From e0fe86b53bdd0b208b10cc8a3e8ddc09910dfd75 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 24 Mar 2026 01:17:38 +0000 Subject: [PATCH 001/359] 8371924: --mac-app-store should be accepted option for app image signing Reviewed-by: almatvee --- .../jdk/jpackage/internal/MacFromOptions.java | 22 ++++----- .../internal/MacRuntimeValidator.java | 34 ++++++++++---- .../resources/MacResources.properties | 1 + .../jpackage/internal/cli/StandardOption.java | 2 +- .../jdk/jpackage/test/JPackageCommand.java | 14 +++++- .../jdk/jpackage/test/LauncherVerifier.java | 14 +++++- .../cli/OptionsValidationFailTest.excludes | 1 + .../jpackage/internal/cli/jpackage-options.md | 2 +- .../jpackage/macosx/SigningAppImageTest.java | 1 - .../macosx/SigningAppImageTwoStepsTest.java | 34 +++++++++++++- test/jdk/tools/jpackage/share/ErrorTest.java | 45 +++++++++++++++++-- 11 files changed, 138 insertions(+), 32 deletions(-) diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromOptions.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromOptions.java index 20dcbcf5742..2c247ed3989 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromOptions.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromOptions.java @@ -27,8 +27,6 @@ package jdk.jpackage.internal; import static jdk.jpackage.internal.FromOptions.buildApplicationBuilder; import static jdk.jpackage.internal.FromOptions.createPackageBuilder; import static jdk.jpackage.internal.MacPackagingPipeline.APPLICATION_LAYOUT; -import static jdk.jpackage.internal.MacRuntimeValidator.validateRuntimeHasJliLib; -import static jdk.jpackage.internal.MacRuntimeValidator.validateRuntimeHasNoBinDir; import static jdk.jpackage.internal.OptionUtils.isBundlingOperation; import static jdk.jpackage.internal.cli.StandardBundlingOperation.CREATE_MAC_PKG; import static jdk.jpackage.internal.cli.StandardOption.APPCLASS; @@ -203,12 +201,14 @@ final class MacFromOptions { final var predefinedRuntimeLayout = PREDEFINED_RUNTIME_IMAGE.findIn(options) .map(MacPackage::guessRuntimeLayout); - predefinedRuntimeLayout.ifPresent(layout -> { - validateRuntimeHasJliLib(layout); - if (MAC_APP_STORE.containsIn(options)) { - validateRuntimeHasNoBinDir(layout); - } - }); + predefinedRuntimeLayout.ifPresent(MacRuntimeValidator::validateRuntimeHasJliLib); + + if (MAC_APP_STORE.containsIn(options)) { + PREDEFINED_APP_IMAGE.findIn(options) + .map(APPLICATION_LAYOUT::resolveAt) + .ifPresent(MacRuntimeValidator::validateRuntimeHasNoBinDir); + predefinedRuntimeLayout.ifPresent(MacRuntimeValidator::validateRuntimeHasNoBinDir); + } final var launcherFromOptions = new LauncherFromOptions().faMapper(MacFromOptions::createMacFa); @@ -269,11 +269,13 @@ final class MacFromOptions { final boolean sign = MAC_SIGN.getFrom(options); final boolean appStore; - if (PREDEFINED_APP_IMAGE.containsIn(options)) { + if (MAC_APP_STORE.containsIn(options)) { + appStore = MAC_APP_STORE.getFrom(options); + } else if (PREDEFINED_APP_IMAGE.containsIn(options)) { final var appImageFileOptions = appBuilder.externalApplication().orElseThrow().extra(); appStore = MAC_APP_STORE.getFrom(appImageFileOptions); } else { - appStore = MAC_APP_STORE.getFrom(options); + appStore = false; } appBuilder.appStore(appStore); diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacRuntimeValidator.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacRuntimeValidator.java index cfab12cbcba..340078849c7 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacRuntimeValidator.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacRuntimeValidator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,10 @@ import java.nio.file.Files; import java.nio.file.NoSuchFileException; import java.nio.file.Path; import java.util.function.Predicate; +import jdk.jpackage.internal.model.AppImageLayout; +import jdk.jpackage.internal.model.ApplicationLayout; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.JPackageException; import jdk.jpackage.internal.model.RuntimeLayout; final class MacRuntimeValidator { @@ -45,17 +49,29 @@ final class MacRuntimeValidator { throw new UncheckedIOException(ex); } - throw I18N.buildConfigException("error.invalid-runtime-image-missing-file", + throw new JPackageException(I18N.format("error.invalid-runtime-image-missing-file", runtimeLayout.rootDirectory(), - runtimeLayout.unresolve().runtimeDirectory().resolve("lib/**").resolve(jliName)).create(); + runtimeLayout.unresolve().runtimeDirectory().resolve("lib/**").resolve(jliName))); } - static void validateRuntimeHasNoBinDir(RuntimeLayout runtimeLayout) { - if (Files.isDirectory(runtimeLayout.runtimeDirectory().resolve("bin"))) { - throw I18N.buildConfigException() - .message("error.invalid-runtime-image-bin-dir", runtimeLayout.rootDirectory()) - .advice("error.invalid-runtime-image-bin-dir.advice", "--mac-app-store") - .create(); + static void validateRuntimeHasNoBinDir(AppImageLayout appImageLayout) { + if (Files.isDirectory(appImageLayout.runtimeDirectory().resolve("bin"))) { + switch (appImageLayout) { + case RuntimeLayout runtimeLayout -> { + throw new ConfigException( + I18N.format("error.invalid-runtime-image-bin-dir", runtimeLayout.rootDirectory()), + I18N.format("error.invalid-runtime-image-bin-dir.advice", "--mac-app-store")); + } + case ApplicationLayout appLayout -> { + throw new JPackageException(I18N.format("error.invalid-app-image-runtime-image-bin-dir", + appLayout.rootDirectory().relativize(appLayout.runtimeDirectory()), + appLayout.rootDirectory())); + } + default -> { + throw new IllegalArgumentException(); + } + } + } } } 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 90c4162b80e..95fff00152b 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 @@ -29,6 +29,7 @@ error.cert.not.found=No certificate found matching [{0}] using keychain [{1}] error.multiple.certs.found=Multiple certificates matching name [{0}] found in keychain [{1}] error.app-image.mac-sign.required=--mac-sign option is required with predefined application image and with type [app-image] error.invalid-runtime-image-missing-file=Runtime image "{0}" is missing "{1}" file +error.invalid-app-image-runtime-image-bin-dir=Runtime directory {0} in the predefined application image [{1}] should not contain "bin" folder error.invalid-runtime-image-bin-dir=Runtime image "{0}" should not contain "bin" folder error.invalid-runtime-image-bin-dir.advice=Use --strip-native-commands jlink option when generating runtime image used with {0} option error.invalid-app-image-plist-file=Invalid "{0}" file in the predefined application image diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardOption.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardOption.java index c2338b87fad..438a5ac3e6f 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardOption.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardOption.java @@ -342,7 +342,7 @@ public final class StandardOption { public static final OptionValue MAC_SIGN = booleanOption("mac-sign").scope(MAC_SIGNING).addAliases("s").create(); - public static final OptionValue MAC_APP_STORE = booleanOption("mac-app-store").create(); + public static final OptionValue MAC_APP_STORE = booleanOption("mac-app-store").scope(MAC_SIGNING).create(); public static final OptionValue MAC_APP_CATEGORY = stringOption("mac-app-category").create(); 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 6b1f67d50f4..4fad120d0f6 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java @@ -392,7 +392,6 @@ public class JPackageCommand extends CommandArguments { } public JPackageCommand setFakeRuntime() { - verifyMutable(); addPrerequisiteAction(cmd -> { cmd.setArgumentValue("--runtime-image", createInputRuntimeImage(RuntimeImageType.RUNTIME_TYPE_FAKE)); }); @@ -400,12 +399,22 @@ public class JPackageCommand extends CommandArguments { return this; } + public JPackageCommand usePredefinedAppImage(JPackageCommand appImageCmd) { + appImageCmd.verifyIsOfType(PackageType.IMAGE); + verifyIsOfType(PackageType.IMAGE); + appImageCmd.getVerifyActionsWithRole(ActionRole.LAUNCHER_VERIFIER).forEach(verifier -> { + addVerifyAction(verifier, ActionRole.LAUNCHER_VERIFIER); + }); + return usePredefinedAppImage(appImageCmd.outputBundle()); + } + public JPackageCommand usePredefinedAppImage(Path predefinedAppImagePath) { return setArgumentValue("--app-image", Objects.requireNonNull(predefinedAppImagePath)) .removeArgumentWithValue("--input"); } JPackageCommand addPrerequisiteAction(ThrowingConsumer action) { + verifyMutable(); prerequisiteActions.add(action); return this; } @@ -421,6 +430,7 @@ public class JPackageCommand extends CommandArguments { } JPackageCommand addVerifyAction(ThrowingConsumer action, ActionRole actionRole) { + verifyMutable(); verifyActions.add(action, actionRole); return this; } @@ -2033,7 +2043,7 @@ public class JPackageCommand extends CommandArguments { // `--runtime-image` parameter set. public static final Path DEFAULT_RUNTIME_IMAGE = Optional.ofNullable(TKit.getConfigProperty("runtime-image")).map(Path::of).orElse(null); - public final static String DEFAULT_VERSION = "1.0"; + public static final String DEFAULT_VERSION = "1.0"; // [HH:mm:ss.SSS] private static final Pattern TIMESTAMP_REGEXP = Pattern.compile( diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherVerifier.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherVerifier.java index f9fcfb905af..7657517bad5 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherVerifier.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherVerifier.java @@ -372,14 +372,21 @@ public final class LauncherVerifier { TKit.assertTrue(entitlements.isPresent(), String.format("Check [%s] launcher is signed with entitlements", name)); + String expectedEntitlementsOrigin; + var customFile = Optional.ofNullable(cmd.getArgumentValue("--mac-entitlements")).map(Path::of); - if (customFile.isEmpty()) { + if (customFile.isPresent()) { + expectedEntitlementsOrigin = String.format("custom entitlements from [%s] file", customFile.get()); + } else { // Try from the resource dir. var resourceDirFile = Optional.ofNullable(cmd.getArgumentValue("--resource-dir")).map(Path::of).map(resourceDir -> { return resourceDir.resolve(cmd.name() + ".entitlements"); }).filter(Files::exists); if (resourceDirFile.isPresent()) { customFile = resourceDirFile; + expectedEntitlementsOrigin = "custom entitlements from the resource directory"; + } else { + expectedEntitlementsOrigin = null; } } @@ -388,11 +395,14 @@ public final class LauncherVerifier { expected = new PListReader(Files.readAllBytes(customFile.orElseThrow())).toMap(true); } else if (cmd.hasArgument("--mac-app-store")) { expected = DefaultEntitlements.APP_STORE; + expectedEntitlementsOrigin = "App Store entitlements"; } else { + expectedEntitlementsOrigin = "default entitlements"; expected = DefaultEntitlements.STANDARD; } - TKit.assertEquals(expected, entitlements.orElseThrow().toMap(true), String.format("Check [%s] launcher is signed with expected entitlements", name)); + TKit.assertEquals(expected, entitlements.orElseThrow().toMap(true), + String.format("Check [%s] launcher is signed with %s", name, expectedEntitlementsOrigin)); } private void executeLauncher(JPackageCommand cmd) throws IOException { diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/OptionsValidationFailTest.excludes b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/OptionsValidationFailTest.excludes index 32968db0606..19478aaa4a7 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/OptionsValidationFailTest.excludes +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/OptionsValidationFailTest.excludes @@ -40,6 +40,7 @@ ErrorTest.test(WIN_MSI; app-desc=Hello; args-add=[--app-version, 1234]; errors=[ ErrorTest.test(WIN_MSI; app-desc=Hello; args-add=[--app-version, 256.1]; errors=[message.error-header+[error.msi-product-version-major-out-of-range], message.advice-header+[error.version-string-wrong-format.advice]]) ErrorTest.test(WIN_MSI; app-desc=Hello; args-add=[--launcher-as-service]; errors=[message.error-header+[error.missing-service-installer], message.advice-header+[error.missing-service-installer.advice]]) ErrorTest.test(args-add=[@foo]; errors=[message.error-header+[ERR_CannotParseOptions, foo]]) +ErrorTest.testMacSignAppStoreInvalidRuntime ErrorTest.testMacSignWithoutIdentity(IMAGE; app-desc=Hello; args-add=[--mac-sign, --mac-signing-keychain, @@EMPTY_KEYCHAIN@@]; errors=[message.error-header+[error.cert.not.found, CODE_SIGN, EMPTY_KEYCHAIN]]) ErrorTest.testMacSignWithoutIdentity(IMAGE; args-add=[--app-image, @@APP_IMAGE_WITH_SHORT_NAME@@, --mac-sign, --mac-signing-keychain, @@EMPTY_KEYCHAIN@@]; errors=[message.error-header+[error.cert.not.found, CODE_SIGN, EMPTY_KEYCHAIN]]) ErrorTest.testMacSignWithoutIdentity(MAC_DMG; app-desc=Hello; args-add=[--mac-sign, --mac-signing-keychain, @@EMPTY_KEYCHAIN@@]; errors=[message.error-header+[error.cert.not.found, CODE_SIGN, EMPTY_KEYCHAIN]]) diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/jpackage-options.md b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/jpackage-options.md index 64d3c6c075b..59ae0d176c1 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/jpackage-options.md +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/jpackage-options.md @@ -29,7 +29,7 @@ | --linux-shortcut | linux-deb, linux-rpm | x | x | x | USE_LAST | | --mac-app-category | mac-bundle | x | x | | USE_LAST | | --mac-app-image-sign-identity | mac | x | x | | USE_LAST | -| --mac-app-store | mac-bundle | x | x | | USE_LAST | +| --mac-app-store | mac | x | x | | USE_LAST | | --mac-dmg-content | mac-dmg | x | x | | CONCATENATE | | --mac-entitlements | mac | x | x | | USE_LAST | | --mac-installer-sign-identity | mac-pkg | x | x | | USE_LAST | diff --git a/test/jdk/tools/jpackage/macosx/SigningAppImageTest.java b/test/jdk/tools/jpackage/macosx/SigningAppImageTest.java index 3a257a425b6..fc146270ab8 100644 --- a/test/jdk/tools/jpackage/macosx/SigningAppImageTest.java +++ b/test/jdk/tools/jpackage/macosx/SigningAppImageTest.java @@ -64,7 +64,6 @@ public class SigningAppImageTest { var testAL = new AdditionalLauncher("testAL"); testAL.applyTo(cmd); - cmd.executeAndAssertHelloAppImageCreated(); MacSign.withKeychain(keychain -> { sign.addTo(cmd); diff --git a/test/jdk/tools/jpackage/macosx/SigningAppImageTwoStepsTest.java b/test/jdk/tools/jpackage/macosx/SigningAppImageTwoStepsTest.java index a6d94b59bd9..20af9572044 100644 --- a/test/jdk/tools/jpackage/macosx/SigningAppImageTwoStepsTest.java +++ b/test/jdk/tools/jpackage/macosx/SigningAppImageTwoStepsTest.java @@ -26,6 +26,7 @@ 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.Collectors; import java.util.stream.Stream; import jdk.jpackage.test.AdditionalLauncher; @@ -68,6 +69,22 @@ public class SigningAppImageTwoStepsTest { spec.test(); } + @Test + public static void testAppStore() { + + var sign = new SignKeyOptionWithKeychain( + SignKeyOption.Type.SIGN_KEY_USER_SHORT_NAME, + SigningBase.StandardCertificateRequest.CODESIGN, + SigningBase.StandardKeychain.MAIN.keychain()); + + var spec = new TestSpec(Optional.empty(), sign); + + spec.signAppImage(spec.createAppImage(), Optional.of(cmd -> { + cmd.addArgument("--mac-app-store"); + })); + } + + public record TestSpec(Optional signAppImage, SignKeyOptionWithKeychain sign) { public TestSpec { @@ -133,7 +150,7 @@ public class SigningAppImageTwoStepsTest { private SignKeyOptionWithKeychain sign; } - void test() { + JPackageCommand createAppImage() { var appImageCmd = JPackageCommand.helloAppImage() .setFakeRuntime() .setArgumentValue("--dest", TKit.createTempDirectory("appimage")); @@ -150,16 +167,29 @@ public class SigningAppImageTwoStepsTest { }, signOption.keychain()); }, appImageCmd::execute); + return appImageCmd; + } + + void signAppImage(JPackageCommand appImageCmd, Optional> mutator) { + Objects.requireNonNull(appImageCmd); + Objects.requireNonNull(mutator); + MacSign.withKeychain(keychain -> { var cmd = new JPackageCommand() .setPackageType(PackageType.IMAGE) - .addArguments("--app-image", appImageCmd.outputBundle()) + .usePredefinedAppImage(appImageCmd) .mutate(sign::addTo); + mutator.ifPresent(cmd::mutate); + cmd.executeAndAssertHelloAppImageCreated(); MacSignVerify.verifyAppImageSigned(cmd, sign.certRequest()); }, sign.keychain()); } + + void test() { + signAppImage(createAppImage(), Optional.empty()); + } } public static Collection test() { diff --git a/test/jdk/tools/jpackage/share/ErrorTest.java b/test/jdk/tools/jpackage/share/ErrorTest.java index 2797115b202..fbaec8283e8 100644 --- a/test/jdk/tools/jpackage/share/ErrorTest.java +++ b/test/jdk/tools/jpackage/share/ErrorTest.java @@ -26,7 +26,6 @@ import static java.util.stream.Collectors.toMap; import static jdk.internal.util.OperatingSystem.LINUX; import static jdk.internal.util.OperatingSystem.MACOS; import static jdk.internal.util.OperatingSystem.WINDOWS; -import static jdk.jpackage.internal.util.PListWriter.writeDict; import static jdk.jpackage.internal.util.PListWriter.writePList; import static jdk.jpackage.internal.util.XmlUtils.createXml; import static jdk.jpackage.internal.util.XmlUtils.toXmlConsumer; @@ -35,6 +34,7 @@ import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; import static jdk.jpackage.test.JPackageCommand.makeAdvice; import static jdk.jpackage.test.JPackageCommand.makeError; +import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; @@ -56,6 +56,7 @@ import jdk.jpackage.internal.util.TokenReplace; import jdk.jpackage.test.Annotations.Parameter; import jdk.jpackage.test.Annotations.ParameterSupplier; import jdk.jpackage.test.Annotations.Test; +import jdk.jpackage.test.ApplicationLayout; import jdk.jpackage.test.CannedArgument; import jdk.jpackage.test.CannedFormattedString; import jdk.jpackage.test.JPackageCommand; @@ -699,11 +700,48 @@ public final class ErrorTest { )); } + @Test(ifOS = MACOS) + public static void testMacSignAppStoreInvalidRuntime() throws IOException { + + // Create app image with the runtime directory content that will fail the subsequent signing jpackage command. + var appImageCmd = JPackageCommand.helloAppImage().setFakeRuntime(); + appImageCmd.executeAndAssertImageCreated(); + Files.createDirectory(appImageCmd.appLayout().runtimeHomeDirectory().resolve("bin")); + + final var keychain = SignEnvMock.SingleCertificateKeychain.FOO.keychain(); + + var spec = testSpec() + .noAppDesc() + .addArgs("--mac-app-store", "--mac-sign", "--app-image", appImageCmd.outputBundle().toString()) + .error("error.invalid-app-image-runtime-image-bin-dir", + ApplicationLayout.macAppImage().runtimeHomeDirectory(), appImageCmd.outputBundle()) + .create(); + + TKit.withNewState(() -> { + var script = Script.build() + // Disable the mutation making mocks "run once". + .commandMockBuilderMutator(null) + // Replace "/usr/bin/security" with the mock bound to the keychain mock. + .map(MacSignMockUtils.securityMock(SignEnvMock.VALUE)) + // Don't mock other external commands. + .use(VerbatimCommandMock.INSTANCE) + .createLoop(); + + // Create jpackage tool provider using the /usr/bin/security mock. + var jpackage = JPackageMockUtils.createJPackageToolProvider(OperatingSystem.MACOS, script); + + // Override the default jpackage tool provider with the one using the /usr/bin/security mock. + JPackageCommand.useToolProviderByDefault(jpackage); + + spec.test(); + }); + } + @Test(ifOS = MACOS) @ParameterSupplier @ParameterSupplier("testMacPkgSignWithoutIdentity") public static void testMacSignWithoutIdentity(TestSpec spec) { - // The test called JPackage Command.useToolProviderBy Default(), + // The test calls JPackageCommand.useToolProviderByDefault(), // which alters global variables in the test library, // so run the test case with a new global state to isolate the alteration of the globals. TKit.withNewState(() -> { @@ -998,8 +1036,7 @@ public final class ErrorTest { // Test a few app-image options that should not be used when signing external app image testCases.addAll(Stream.of( new ArgumentGroup("--app-version", "2.0"), - new ArgumentGroup("--name", "foo"), - new ArgumentGroup("--mac-app-store") + new ArgumentGroup("--name", "foo") ).flatMap(argGroup -> { var withoutSign = testSpec() .noAppDesc() From e6c870ec43fc0b34e7afe7970054c658b7486e3e Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Tue, 24 Mar 2026 01:46:08 +0000 Subject: [PATCH 002/359] 8378731: Move AOT-inited classes to initialized state in early VM bootstrap Reviewed-by: kvn, liach --- src/hotspot/share/cds/aotClassInitializer.cpp | 5 +- .../share/cds/aotLinkedClassBulkLoader.cpp | 104 +++++++++++++++--- .../share/cds/aotLinkedClassBulkLoader.hpp | 7 +- src/hotspot/share/oops/instanceKlass.cpp | 35 +++++- src/hotspot/share/oops/instanceKlass.hpp | 4 +- .../cds/appcds/aotCache/EarlyClassInit.java | 61 ++++++++++ 6 files changed, 190 insertions(+), 26 deletions(-) create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/aotCache/EarlyClassInit.java diff --git a/src/hotspot/share/cds/aotClassInitializer.cpp b/src/hotspot/share/cds/aotClassInitializer.cpp index 06fc3af6f30..41fdeb537cc 100644 --- a/src/hotspot/share/cds/aotClassInitializer.cpp +++ b/src/hotspot/share/cds/aotClassInitializer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -234,7 +234,8 @@ bool AOTClassInitializer::can_archive_initialized_mirror(InstanceKlass* ik) { } void AOTClassInitializer::call_runtime_setup(JavaThread* current, InstanceKlass* ik) { - assert(ik->has_aot_initialized_mirror(), "sanity"); + precond(ik->has_aot_initialized_mirror()); + precond(!AOTLinkedClassBulkLoader::is_initializing_classes_early()); if (ik->is_runtime_setup_required()) { if (log_is_enabled(Info, aot, init)) { ResourceMark rm; diff --git a/src/hotspot/share/cds/aotLinkedClassBulkLoader.cpp b/src/hotspot/share/cds/aotLinkedClassBulkLoader.cpp index 3653f9d518c..6a60177fc40 100644 --- a/src/hotspot/share/cds/aotLinkedClassBulkLoader.cpp +++ b/src/hotspot/share/cds/aotLinkedClassBulkLoader.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -116,11 +116,24 @@ void AOTLinkedClassBulkLoader::preload_classes_in_table(Array* c } } +#ifdef ASSERT +// true iff we are inside AOTLinkedClassBulkLoader::link_classes(), when +// we are moving classes into the fully_initialized state before the +// JVM is able to execute any bytecodes. +static bool _is_initializing_classes_early = false; +bool AOTLinkedClassBulkLoader::is_initializing_classes_early() { + return _is_initializing_classes_early; +} +#endif + // Some cached heap objects may hold references to methods in aot-linked // classes (via MemberName). We need to make sure all classes are // linked before executing any bytecode. void AOTLinkedClassBulkLoader::link_classes(JavaThread* current) { + DEBUG_ONLY(_is_initializing_classes_early = true); link_classes_impl(current); + DEBUG_ONLY(_is_initializing_classes_early = false); + if (current->has_pending_exception()) { exit_on_exception(current); } @@ -135,6 +148,13 @@ void AOTLinkedClassBulkLoader::link_classes_impl(TRAPS) { link_classes_in_table(table->boot2(), CHECK); link_classes_in_table(table->platform(), CHECK); link_classes_in_table(table->app(), CHECK); + + init_classes_for_loader(Handle(), AOTLinkedClassTable::get()->boot1(), /*early_only=*/true, CHECK); + init_classes_for_loader(Handle(), AOTLinkedClassTable::get()->boot2(), /*early_only=*/true, CHECK); + init_classes_for_loader(Handle(), AOTLinkedClassTable::get()->platform(), /*early_only=*/true, CHECK); + init_classes_for_loader(Handle(), AOTLinkedClassTable::get()->app(), /*early_only=*/true, CHECK); + + log_info(aot, init)("------ finished early class init"); } void AOTLinkedClassBulkLoader::link_classes_in_table(Array* classes, TRAPS) { @@ -216,7 +236,7 @@ void AOTLinkedClassBulkLoader::validate_module(Klass* k, const char* category_na #endif void AOTLinkedClassBulkLoader::init_javabase_classes(JavaThread* current) { - init_classes_for_loader(Handle(), AOTLinkedClassTable::get()->boot1(), current); + init_classes_for_loader(Handle(), AOTLinkedClassTable::get()->boot1(), /*early_only=*/false, current); if (current->has_pending_exception()) { exit_on_exception(current); } @@ -246,9 +266,9 @@ void AOTLinkedClassBulkLoader::init_non_javabase_classes_impl(TRAPS) { assert(h_system_loader() != nullptr, "must be"); AOTLinkedClassTable* table = AOTLinkedClassTable::get(); - init_classes_for_loader(Handle(), table->boot2(), CHECK); - init_classes_for_loader(h_platform_loader, table->platform(), CHECK); - init_classes_for_loader(h_system_loader, table->app(), CHECK); + init_classes_for_loader(Handle(), table->boot2(), /*early_only=*/false, CHECK); + init_classes_for_loader(h_platform_loader, table->platform(), /*early_only=*/false, CHECK); + init_classes_for_loader(h_system_loader, table->app(), /*early_only=*/false, CHECK); if (Universe::is_fully_initialized() && VerifyDuringStartup) { // Make sure we're still in a clean state. @@ -324,22 +344,80 @@ void AOTLinkedClassBulkLoader::initiate_loading(JavaThread* current, const char* } } -// Some AOT-linked classes for must be initialized early. This includes -// - classes that were AOT-initialized by AOTClassInitializer -// - the classes of all objects that are reachable from the archived mirrors of -// the AOT-linked classes for . -void AOTLinkedClassBulkLoader::init_classes_for_loader(Handle class_loader, Array* classes, TRAPS) { +// Can we move ik into fully_initialized state before the JVM is able to execute +// bytecodes? +static bool is_early_init_possible(InstanceKlass* ik) { + if (ik->is_runtime_setup_required()) { + // Bytecodes need to be executed in order to initialize this class. + if (log_is_enabled(Debug, aot, init)) { + ResourceMark rm; + log_debug(aot, init)("No early init %s: needs runtimeSetup()", + ik->external_name()); + } + return false; + } + + if (ik->super() != nullptr && !ik->super()->is_initialized()) { + // is_runtime_setup_required() == true for a super type + if (log_is_enabled(Debug, aot, init)) { + ResourceMark rm; + log_debug(aot, init)("No early init %s: super type %s not initialized", + ik->external_name(), ik->super()->external_name()); + } + return false; + } + + Array* interfaces = ik->local_interfaces(); + int num_interfaces = interfaces->length(); + for (int i = 0; i < num_interfaces; i++) { + InstanceKlass* intf = interfaces->at(i); + if (!intf->is_initialized() && intf->interface_needs_clinit_execution_as_super(/*also_check_supers*/false)) { + // is_runtime_setup_required() == true for this interface + if (log_is_enabled(Debug, aot, init)) { + ResourceMark rm; + log_debug(aot, init)("No early init %s: interface type %s not initialized", + ik->external_name(), intf->external_name()); + } + return false; + } + } + + return true; +} + +// Normally, classes are initialized on demand. However, some AOT-linked classes +// for the class_loader must be proactively intialized, including: +// - Classes that have an AOT-initialized mirror (they were AOT-initialized by +// AOTClassInitializer during the assembly phase). +// - The classes of all objects that are reachable from the archived mirrors of +// the AOT-linked classes for the class_loader. These are recorded in the special +// subgraph. +// +// (early_only == true) means that this function is called before the JVM +// is capable of executing Java bytecodes. +void AOTLinkedClassBulkLoader::init_classes_for_loader(Handle class_loader, Array* classes, + bool early_only, TRAPS) { if (classes != nullptr) { for (int i = 0; i < classes->length(); i++) { InstanceKlass* ik = classes->at(i); assert(ik->class_loader_data() != nullptr, "must be"); - if (ik->has_aot_initialized_mirror()) { - ik->initialize_with_aot_initialized_mirror(CHECK); + + bool do_init = ik->has_aot_initialized_mirror(); + if (do_init && early_only && !is_early_init_possible(ik)) { + // ik will be proactively initialized later when init_classes_for_loader() + // is called again with (early_only == false). + do_init = false; + } + + if (do_init) { + ik->initialize_with_aot_initialized_mirror(early_only, CHECK); } } } - HeapShared::init_classes_for_special_subgraph(class_loader, CHECK); + if (!early_only) { + HeapShared::init_classes_for_special_subgraph(class_loader, CHECK); + } } void AOTLinkedClassBulkLoader::replay_training_at_init(Array* classes, TRAPS) { diff --git a/src/hotspot/share/cds/aotLinkedClassBulkLoader.hpp b/src/hotspot/share/cds/aotLinkedClassBulkLoader.hpp index 31fdac386fe..24ff61cea1e 100644 --- a/src/hotspot/share/cds/aotLinkedClassBulkLoader.hpp +++ b/src/hotspot/share/cds/aotLinkedClassBulkLoader.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ class AOTLinkedClassBulkLoader : AllStatic { static void link_classes_impl(TRAPS); static void link_classes_in_table(Array* classes, TRAPS); static void init_non_javabase_classes_impl(TRAPS); - static void init_classes_for_loader(Handle class_loader, Array* classes, TRAPS); + static void init_classes_for_loader(Handle class_loader, Array* classes, bool early_only, TRAPS); static void replay_training_at_init(Array* classes, TRAPS) NOT_CDS_RETURN; #ifdef ASSERT @@ -73,8 +73,9 @@ public: static void init_javabase_classes(JavaThread* current) NOT_CDS_RETURN; static void init_non_javabase_classes(JavaThread* current) NOT_CDS_RETURN; static void exit_on_exception(JavaThread* current); - static void replay_training_at_init_for_preloaded_classes(TRAPS) NOT_CDS_RETURN; + + static bool is_initializing_classes_early() NOT_DEBUG({return false;}); }; #endif // SHARE_CDS_AOTLINKEDCLASSBULKLOADER_HPP diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp index 1963327fc78..919afbf3abd 100644 --- a/src/hotspot/share/oops/instanceKlass.cpp +++ b/src/hotspot/share/oops/instanceKlass.cpp @@ -23,6 +23,7 @@ */ #include "cds/aotClassInitializer.hpp" +#include "cds/aotLinkedClassBulkLoader.hpp" #include "cds/aotMetaspace.hpp" #include "cds/archiveUtils.hpp" #include "cds/cdsConfig.hpp" @@ -150,6 +151,7 @@ #endif // ndef DTRACE_ENABLED bool InstanceKlass::_finalization_enabled = true; +static int call_class_initializer_counter = 0; // for debugging static inline bool is_class_loader(const Symbol* class_name, const ClassFileParser& parser) { @@ -884,7 +886,9 @@ void InstanceKlass::assert_no_clinit_will_run_for_aot_initialized_class() const #endif #if INCLUDE_CDS -void InstanceKlass::initialize_with_aot_initialized_mirror(TRAPS) { +// early_init -- we are moving this class into the fully_initialized state before the +// JVM is able to execute any bytecodes. See AOTLinkedClassBulkLoader::is_initializing_classes_early(). +void InstanceKlass::initialize_with_aot_initialized_mirror(bool early_init, TRAPS) { assert(has_aot_initialized_mirror(), "must be"); assert(CDSConfig::is_loading_heap(), "must be"); assert(CDSConfig::is_using_aot_linked_classes(), "must be"); @@ -894,15 +898,36 @@ void InstanceKlass::initialize_with_aot_initialized_mirror(TRAPS) { return; } + if (log_is_enabled(Info, aot, init)) { + ResourceMark rm; + log_info(aot, init)("%s (aot-inited%s)", external_name(), early_init ? ", early" : ""); + } + if (is_runtime_setup_required()) { + assert(!early_init, "must not call"); // Need to take the slow path, which will call the runtimeSetup() function instead // of initialize(CHECK); return; } - if (log_is_enabled(Info, aot, init)) { - ResourceMark rm; - log_info(aot, init)("%s (aot-inited)", external_name()); + + LogTarget(Info, class, init) lt; + if (lt.is_enabled()) { + ResourceMark rm(THREAD); + LogStream ls(lt); + ls.print("%d Initializing ", call_class_initializer_counter++); + name()->print_value_on(&ls); + ls.print_cr("(aot-inited) (" PTR_FORMAT ") by thread \"%s\"", + p2i(this), THREAD->name()); + } + + if (early_init) { + precond(AOTLinkedClassBulkLoader::is_initializing_classes_early()); + precond(is_linked()); + precond(init_thread() == nullptr); + set_init_state(fully_initialized); + fence_and_clear_init_lock(); + return; } link_class(CHECK); @@ -1699,8 +1724,6 @@ ArrayKlass* InstanceKlass::array_klass_or_null() { return array_klass_or_null(1); } -static int call_class_initializer_counter = 0; // for debugging - Method* InstanceKlass::class_initializer() const { Method* clinit = find_method( vmSymbols::class_initializer_name(), vmSymbols::void_method_signature()); diff --git a/src/hotspot/share/oops/instanceKlass.hpp b/src/hotspot/share/oops/instanceKlass.hpp index e370a3b7a7c..dd563ad3492 100644 --- a/src/hotspot/share/oops/instanceKlass.hpp +++ b/src/hotspot/share/oops/instanceKlass.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -556,7 +556,7 @@ public: // initialization (virtuals from Klass) bool should_be_initialized() const override; // means that initialize should be called - void initialize_with_aot_initialized_mirror(TRAPS); + void initialize_with_aot_initialized_mirror(bool early_init, TRAPS); void assert_no_clinit_will_run_for_aot_initialized_class() const NOT_DEBUG_RETURN; void initialize(TRAPS) override; void initialize_preemptable(TRAPS) override; diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/EarlyClassInit.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/EarlyClassInit.java new file mode 100644 index 00000000000..f78c3f83861 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/EarlyClassInit.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 Early init of classes in the AOT cache + * @bug 8378731 + * @requires vm.cds.supports.aot.class.linking + * @library /test/lib + * @build EarlyClassInit + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app.jar EarlyClassInitApp + * @run driver EarlyClassInit + */ + +import jdk.test.lib.cds.SimpleCDSAppTester; +import jdk.test.lib.process.OutputAnalyzer; + +public class EarlyClassInit { + public static void main(String... args) throws Exception { + SimpleCDSAppTester.of("EarlyClassInit") + .addVmArgs("-Xlog:aot+init=debug") + .classpath("app.jar") + .appCommandLine("EarlyClassInitApp") + .setProductionChecker((OutputAnalyzer out) -> { + out.shouldContain("java.lang.Object (aot-inited, early)") + .shouldContain("No early init java.lang.ClassLoader: needs runtimeSetup()") + .shouldContain("No early init java.security.SecureClassLoader: super type java.lang.ClassLoader not initialized") + .shouldContain("Calling java.lang.ClassLoader::runtimeSetup()") + .shouldContain("java.security.SecureClassLoader (aot-inited)"); + out.shouldContain("HelloWorld"); + }) + .runAOTWorkflow(); + } +} + +class EarlyClassInitApp { + public static void main(String[] args) { + System.out.println("HelloWorld"); + } +} From 105d526fa7dbf371115d9e2e4b906a8c15afd0bf Mon Sep 17 00:00:00 2001 From: Roger Calnan Date: Tue, 24 Mar 2026 02:09:18 +0000 Subject: [PATCH 003/359] 8377921: Add anchors to the options in the Core Libs tool man pages Reviewed-by: jpai, iris --- src/jdk.jartool/share/man/jar.md | 42 ++++++++++++++++---------------- src/jdk.jlink/share/man/jlink.md | 30 +++++++++++------------ 2 files changed, 36 insertions(+), 36 deletions(-) diff --git a/src/jdk.jartool/share/man/jar.md b/src/jdk.jartool/share/man/jar.md index d944afcfb7f..658fa0cb4fa 100644 --- a/src/jdk.jartool/share/man/jar.md +++ b/src/jdk.jartool/share/man/jar.md @@ -1,5 +1,5 @@ --- -# Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. # 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,29 +84,29 @@ appropriate operation arguments described in this section. You can mix an operation argument with other one-letter options. Generally the operation argument is the first argument specified on the command line. -`-c` or `--create` +[`-c`]{#option--create} or `--create` : Creates the archive. -`-i` *FILE* or `--generate-index=`*FILE* +[`-i`]{#option--generate-index} *FILE* or `--generate-index=`*FILE* : Generates index information for the specified JAR file. This option is deprecated and may be removed in a future release. -`-t` or `--list` +[`-t`]{#option--list} or `--list` : Lists the table of contents for the archive. -`-u` or `--update` +[`-u`]{#option--update} or `--update` : Updates an existing JAR file. -`-x` or `--extract` +[`-x`]{#option--extract} or `--extract` : Extracts the named (or all) files from the archive. If a file with the same name appears more than once in the archive, each copy will be extracted, with later copies overwriting (replacing) earlier copies unless -k is specified. -`-d` or `--describe-module` +[`-d`]{#option--describe-module} or `--describe-module` : Prints the module descriptor or automatic module name. -`--validate` +[`--validate`]{#option--validate} : Validate the contents of the JAR file. See `Integrity of a JAR File` section below for more details. @@ -115,7 +115,7 @@ argument is the first argument specified on the command line. You can use the following options to customize the actions of any operation mode included in the `jar` command. -`-C` *DIR* +[`-C`]{#option-C} *DIR* : When used with the create operation mode, changes the specified directory and includes the *files* specified at the end of the command line. @@ -126,10 +126,10 @@ mode included in the `jar` command. where the JAR file will be extracted. Unlike with the create operation mode, this option can be specified only once with the extract operation mode. -`-f` *FILE* or `--file=`*FILE* +[`-f`]{#option--file} *FILE* or `--file=`*FILE* : Specifies the archive file name. -`--release` *VERSION* +[`--release`]{#option--release} *VERSION* : Creates a multirelease JAR file. Places all files specified after the option into a versioned directory of the JAR file named `META-INF/versions/`*VERSION*`/`, where *VERSION* must be must be a @@ -149,26 +149,26 @@ mode included in the `jar` command. You can use the following options to customize the actions of the create and the update main operation modes: -`-e` *CLASSNAME* or `--main-class=`*CLASSNAME* +[`-e`]{#option--main-class} *CLASSNAME* or `--main-class=`*CLASSNAME* : Specifies the application entry point for standalone applications bundled into a modular or executable modular JAR file. -`-m` *FILE* or `--manifest=`*FILE* +[`-m`]{#option--manifest} *FILE* or `--manifest=`*FILE* : Includes the manifest information from the given manifest file. -`-M` or `--no-manifest` +[`-M`]{#option--no-manifest} or `--no-manifest` : Doesn't create a manifest file for the entries. -`--module-version=`*VERSION* +[`--module-version=`]{#option--module-version}*VERSION* : Specifies the module version, when creating or updating a modular JAR file, or updating a non-modular JAR file. -`--hash-modules=`*PATTERN* +[`--hash-modules=`]{#option--hash-modules}*PATTERN* : Computes and records the hashes of modules matched by the given pattern and that depend upon directly or indirectly on a modular JAR file being created or a non-modular JAR file being updated. -`-p` or `--module-path` +[`-p`]{#option--module-path} or `--module-path` : Specifies the location of module dependence for generating the hash. `@`*file* @@ -181,20 +181,20 @@ You can use the following options to customize the actions of the create (`-c` or `--create`) the update (`-u` or `--update` ) and the generate-index (`-i` or `--generate-index=`*FILE*) main operation modes: -`-0` or `--no-compress` +[`-0`]{#option--no-compress} or `--no-compress` : Stores without using ZIP compression. -`--date=`*TIMESTAMP* +[`--date=`]{#option--date}*TIMESTAMP* : The timestamp in ISO-8601 extended offset date-time with optional time-zone format, to use for the timestamp of the entries, e.g. "2022-02-12T12:30:00-05:00". ## Operation Modifiers Valid Only in Extract Mode -`--dir` *DIR* +[`--dir`]{#option--dir} *DIR* : Directory into which the JAR file will be extracted. -`-k` or `--keep-old-files` +[`-k`]{#option--keep-old-files} or `--keep-old-files` : Do not overwrite existing files. If a Jar file entry with the same name exists in the target directory, the existing file will not be overwritten. diff --git a/src/jdk.jlink/share/man/jlink.md b/src/jdk.jlink/share/man/jlink.md index 5c77202434c..b95424fdde9 100644 --- a/src/jdk.jlink/share/man/jlink.md +++ b/src/jdk.jlink/share/man/jlink.md @@ -57,14 +57,14 @@ Developers are responsible for updating their custom runtime images. ## jlink Options -`--add-modules` *mod*\[`,`*mod*...\] +[`--add-modules`]{#option--add-modules} *mod*\[`,`*mod*...\] : Adds the named modules, *mod*, to the default set of root modules. The default set of root modules is empty. -`--bind-services` +[`--bind-services`]{#option--bind-services} : Link service provider modules and their dependencies. -`-c zip-{0-9}` or `--compress=zip-{0-9}` +[`-c zip-{0-9}`]{#option--compress} or `--compress=zip-{0-9}` : Enable compression of resources. The accepted values are: zip-{0-9}, where zip-0 provides no compression, and zip-9 provides the best compression. Default is zip-6. @@ -75,37 +75,37 @@ Developers are responsible for updating their custom runtime images. - `1`: Constant string sharing - `2`: ZIP. Use zip-6 instead. -`--disable-plugin` *pluginname* +[`--disable-plugin`]{#option--disable-plugin} *pluginname* : Disables the specified plug-in. See [jlink Plug-ins] for the list of supported plug-ins. -`--endian` {`little`\|`big`} +[`--endian`]{#option--endian} {`little`\|`big`} : Specifies the byte order of the generated image. The default value is the format of your system's architecture. `-h` or `--help` : Prints the help message. -`--ignore-signing-information` +[`--ignore-signing-information`]{#option--ignore-signing-information} : Suppresses a fatal error when signed modular JARs are linked in the runtime image. The signature-related files of the signed modular JARs aren't copied to the runtime image. -`--launcher` *command*`=`*module* or `--launcher` *command*`=`*module*`/`*main* +[`--launcher`]{#option--launcher} *command*`=`*module* or `--launcher` *command*`=`*module*`/`*main* : Specifies the launcher command name for the module or the command name for the module and main class (the module and the main class names are separated by a slash (`/`)). -`--limit-modules` *mod*\[`,`*mod*...\] +[`--limit-modules`]{#option--limit-modules} *mod*\[`,`*mod*...\] : Limits the universe of observable modules to those in the transitive closure of the named modules, `mod`, plus the main module, if any, plus any further modules specified in the `--add-modules` option. -`--list-plugins` +[`--list-plugins`]{#option--list-plugins} : Lists available plug-ins, which you can access through command-line options; see [jlink Plug-ins]. -`-p` or `--module-path` *modulepath* +[`-p`]{#option-module-path} or `--module-path` *modulepath* : Specifies the module path. If this option is not specified, then the default module path is @@ -114,19 +114,19 @@ Developers are responsible for updating their custom runtime images. `java.base` module cannot be resolved from it, then the `jlink` command appends `$JAVA_HOME/jmods` to the module path. -`--no-header-files` +[`--no-header-files`]{#option--no-header-files} : Excludes header files. -`--no-man-pages` +[`--no-man-pages`]{#option--no-man-pages} : Excludes man pages. -`--output` *path* +[`--output`]{#option--output} *path* : Specifies the location of the generated runtime image. -`--save-opts` *filename* +[`--save-opts`]{#option--save-opts} *filename* : Saves `jlink` options in the specified file. -`--suggest-providers` \[*name*`,` ...\] +[`--suggest-providers`]{#option--suggest-providers} \[*name*`,` ...\] : Suggest providers that implement the given service types from the module path. From cc29010ae29c65964b44e9f472ad0c1d9f848f0a Mon Sep 17 00:00:00 2001 From: Ashutosh Mehra Date: Tue, 24 Mar 2026 03:18:25 +0000 Subject: [PATCH 004/359] 8380664: Remove stub entries used in x86-32 Reviewed-by: kvn --- src/hotspot/share/runtime/stubDeclarations.hpp | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/hotspot/share/runtime/stubDeclarations.hpp b/src/hotspot/share/runtime/stubDeclarations.hpp index c478eda3e7c..7dc0f2d2bed 100644 --- a/src/hotspot/share/runtime/stubDeclarations.hpp +++ b/src/hotspot/share/runtime/stubDeclarations.hpp @@ -667,16 +667,6 @@ do_entry(initial, dcbrt, dcbrt, dcbrt) \ do_stub(initial, fmod) \ do_entry(initial, fmod, fmod, fmod) \ - /* following generic entries should really be x86_32 only */ \ - do_stub(initial, dlibm_sin_cos_huge) \ - do_entry(initial, dlibm_sin_cos_huge, dlibm_sin_cos_huge, \ - dlibm_sin_cos_huge) \ - do_stub(initial, dlibm_reduce_pi04l) \ - do_entry(initial, dlibm_reduce_pi04l, dlibm_reduce_pi04l, \ - dlibm_reduce_pi04l) \ - do_stub(initial, dlibm_tan_cot_huge) \ - do_entry(initial, dlibm_tan_cot_huge, dlibm_tan_cot_huge, \ - dlibm_tan_cot_huge) \ /* merge in stubs and entries declared in arch header */ \ STUBGEN_INITIAL_BLOBS_ARCH_DO(do_stub, do_arch_blob, \ do_arch_entry, do_arch_entry_init) \ From fd2ef1b870ca840e31436a60e726b197254f623f Mon Sep 17 00:00:00 2001 From: Daniel Fuchs Date: Tue, 24 Mar 2026 10:44:03 +0000 Subject: [PATCH 005/359] 8380665: (dc) java/nio/channels/DatagramChannel/SendReceiveMaxSize.java could also test the loopback interface Reviewed-by: alanb, jpai --- .../DatagramChannel/SendReceiveMaxSize.java | 46 ++++++++++++++++--- 1 file changed, 39 insertions(+), 7 deletions(-) diff --git a/test/jdk/java/nio/channels/DatagramChannel/SendReceiveMaxSize.java b/test/jdk/java/nio/channels/DatagramChannel/SendReceiveMaxSize.java index 8d74fd8a387..a2f5844ce25 100644 --- a/test/jdk/java/nio/channels/DatagramChannel/SendReceiveMaxSize.java +++ b/test/jdk/java/nio/channels/DatagramChannel/SendReceiveMaxSize.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * 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 + * @test id=default * @bug 8239355 8242885 8240901 * @key randomness * @summary Check that it is possible to send and receive datagrams of @@ -30,14 +30,41 @@ * @library /test/lib * @build jdk.test.lib.net.IPSupport * @run testng/othervm SendReceiveMaxSize + */ +/* + * @test id=preferIPv4Stack + * @key randomness + * @summary Check that it is possible to send and receive datagrams of + * maximum size on macOS, using an IPv4 only socket. + * @library /test/lib + * @build jdk.test.lib.net.IPSupport * @run testng/othervm -Djava.net.preferIPv4Stack=true SendReceiveMaxSize */ +/* + * @test id=preferIPv6Loopback + * @key randomness + * @summary Check that it is possible to send and receive datagrams of + * maximum size on macOS, using a dual socket and the loopback + * interface. + * @library /test/lib + * @build jdk.test.lib.net.IPSupport + * @run testng/othervm -Dtest.preferLoopback=true SendReceiveMaxSize + */ +/* + * @test id=preferIPv4Loopback + * @key randomness + * @summary Check that it is possible to send and receive datagrams of + * maximum size on macOS, using an IPv4 only socket and the + * loopback interface + * @library /test/lib + * @build jdk.test.lib.net.IPSupport + * @run testng/othervm -Dtest.preferLoopback=true -Djava.net.preferIPv4Stack=true SendReceiveMaxSize + */ import jdk.test.lib.RandomFactory; import jdk.test.lib.NetworkConfiguration; import jdk.test.lib.Platform; import jdk.test.lib.net.IPSupport; -import org.testng.Assert; import org.testng.annotations.BeforeTest; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; @@ -68,6 +95,7 @@ import static org.testng.Assert.assertTrue; public class SendReceiveMaxSize { private final static Class IOE = IOException.class; private final static Random random = RandomFactory.getRandom(); + private final static boolean PREFER_LOOPBACK = Boolean.getBoolean("test.preferLoopback"); public interface DatagramChannelSupplier { DatagramChannel open() throws IOException; @@ -83,11 +111,14 @@ public class SendReceiveMaxSize { public Object[][] invariants() throws IOException { var testcases = new ArrayList(); var nc = NetworkConfiguration.probe(); + var ipv4Loopback = (Inet4Address) InetAddress.getByName("127.0.0.1"); + var ipv6Loopback = (Inet6Address) InetAddress.getByName("::1"); if (hasIPv4()) { - InetAddress IPv4Addr = nc.ip4Addresses() + InetAddress IPv4Addr = PREFER_LOOPBACK ? ipv4Loopback + : nc.ip4Addresses() .filter(Predicate.not(InetAddress::isLoopbackAddress)) .findFirst() - .orElse((Inet4Address) InetAddress.getByName("127.0.0.1")); + .orElse(ipv4Loopback); testcases.add(new Object[]{ supplier(() -> DatagramChannel.open()), IPSupport.getMaxUDPSendBufSizeIPv4(), @@ -100,10 +131,11 @@ public class SendReceiveMaxSize { }); } if (!preferIPv4Stack() && hasIPv6()) { - InetAddress IPv6Addr = nc.ip6Addresses() + InetAddress IPv6Addr = PREFER_LOOPBACK ? ipv6Loopback + : nc.ip6Addresses() .filter(Predicate.not(InetAddress::isLoopbackAddress)) .findFirst() - .orElse((Inet6Address) InetAddress.getByName("::1")); + .orElse(ipv6Loopback); testcases.add(new Object[]{ supplier(() -> DatagramChannel.open()), IPSupport.getMaxUDPSendBufSizeIPv6(), From 90eebaa344d3db6dd92ed6f0531a7dd30c311d67 Mon Sep 17 00:00:00 2001 From: Kevin Walls Date: Tue, 24 Mar 2026 10:52:07 +0000 Subject: [PATCH 006/359] 8380516: HotSpot has two different ways of making Windows strtok_s available as strtok_r Reviewed-by: kbarrett, dlong --- src/hotspot/share/utilities/globalDefinitions_visCPP.hpp | 4 +++- src/hotspot/share/utilities/stringUtils.hpp | 8 ++------ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/hotspot/share/utilities/globalDefinitions_visCPP.hpp b/src/hotspot/share/utilities/globalDefinitions_visCPP.hpp index dfd6f2f1880..f106d325c68 100644 --- a/src/hotspot/share/utilities/globalDefinitions_visCPP.hpp +++ b/src/hotspot/share/utilities/globalDefinitions_visCPP.hpp @@ -69,7 +69,9 @@ inline int strncasecmp(const char *s1, const char *s2, size_t n) { // *not* the same as the C99 Annex K strtok_s. VS provides that function // under the name strtok_s_l. Make strtok_r a synonym so we can use that name // in shared code. -const auto strtok_r = strtok_s; +inline char* strtok_r(char* str, const char* delim, char** saveptr) { + return strtok_s(str, delim, saveptr); +} // VS doesn't provide POSIX macros S_ISFIFO or S_IFIFO. It doesn't even // provide _S_ISFIFO, per its usual naming convention for POSIX stuff. But it diff --git a/src/hotspot/share/utilities/stringUtils.hpp b/src/hotspot/share/utilities/stringUtils.hpp index c3d21233808..66c8d30c7c0 100644 --- a/src/hotspot/share/utilities/stringUtils.hpp +++ b/src/hotspot/share/utilities/stringUtils.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * 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,7 @@ #define SHARE_UTILITIES_STRINGUTILS_HPP #include "memory/allStatic.hpp" - -#ifdef _WINDOWS - // strtok_s is the Windows thread-safe equivalent of POSIX strtok_r -# define strtok_r strtok_s -#endif +#include "utilities/globalDefinitions.hpp" class StringUtils : AllStatic { public: From d0d85cd6b5e8272066b424f4d5f4c84c923a4274 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Tue, 24 Mar 2026 15:36:15 +0000 Subject: [PATCH 007/359] 8380526: G1: Remove "last young" use for the Prepare Mixed GC Reviewed-by: ayang, iwalulya --- src/hotspot/share/gc/g1/g1CollectorState.cpp | 2 +- src/hotspot/share/gc/g1/g1CollectorState.hpp | 22 ++++++++++---------- src/hotspot/share/gc/g1/g1Policy.cpp | 8 +++---- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1CollectorState.cpp b/src/hotspot/share/gc/g1/g1CollectorState.cpp index 66292642603..2b550f36904 100644 --- a/src/hotspot/share/gc/g1/g1CollectorState.cpp +++ b/src/hotspot/share/gc/g1/g1CollectorState.cpp @@ -31,7 +31,7 @@ G1CollectorState::Pause G1CollectorState::gc_pause_type(bool concurrent_operatio assert(SafepointSynchronize::is_at_safepoint(), "must be"); switch (_phase) { case Phase::YoungNormal: return Pause::Normal; - case Phase::YoungLastYoung: return Pause::LastYoung; + case Phase::YoungPrepareMixed: return Pause::PrepareMixed; case Phase::YoungConcurrentStart: return concurrent_operation_is_full_mark ? Pause::ConcurrentStartFull : Pause::ConcurrentStartUndo; diff --git a/src/hotspot/share/gc/g1/g1CollectorState.hpp b/src/hotspot/share/gc/g1/g1CollectorState.hpp index fc59df7349d..64c848959ae 100644 --- a/src/hotspot/share/gc/g1/g1CollectorState.hpp +++ b/src/hotspot/share/gc/g1/g1CollectorState.hpp @@ -45,9 +45,9 @@ class G1CollectorState { // during that GC because we only decide whether we do this type of GC at the start // of the pause. YoungConcurrentStart, - // Indicates that we are about to start or in the last young gc in the Young-Only + // Indicates that we are about to start or in the prepare mixed gc in the Young-Only // phase before the Mixed phase. This GC is required to keep pause time requirements. - YoungLastYoung, + YoungPrepareMixed, // Doing extra old generation evacuation. Mixed, // The Full GC phase (that coincides with the Full GC pause). @@ -72,19 +72,19 @@ public: void set_in_full_gc() { _phase = Phase::FullGC; } // Pause setters - void set_in_young_gc_before_mixed() { _phase = Phase::YoungLastYoung; } void set_in_concurrent_start_gc() { _phase = Phase::YoungConcurrentStart; _initiate_conc_mark_if_possible = false; } + void set_in_prepare_mixed_gc() { _phase = Phase::YoungPrepareMixed; } void set_initiate_conc_mark_if_possible(bool v) { _initiate_conc_mark_if_possible = v; } // Phase getters - bool is_in_young_only_phase() const { return _phase == Phase::YoungNormal || _phase == Phase::YoungConcurrentStart || _phase == Phase::YoungLastYoung; } + bool is_in_young_only_phase() const { return _phase == Phase::YoungNormal || _phase == Phase::YoungConcurrentStart || _phase == Phase::YoungPrepareMixed; } bool is_in_mixed_phase() const { return _phase == Phase::Mixed; } // Specific pauses - bool is_in_young_gc_before_mixed() const { return _phase == Phase::YoungLastYoung; } - bool is_in_full_gc() const { return _phase == Phase::FullGC; } bool is_in_concurrent_start_gc() const { return _phase == Phase::YoungConcurrentStart; } + bool is_in_prepare_mixed_gc() const { return _phase == Phase::YoungPrepareMixed; } + bool is_in_full_gc() const { return _phase == Phase::FullGC; } bool initiate_conc_mark_if_possible() const { return _initiate_conc_mark_if_possible; } @@ -95,9 +95,9 @@ public: enum class Pause : uint { Normal, - LastYoung, ConcurrentStartFull, ConcurrentStartUndo, + PrepareMixed, Cleanup, Remark, Mixed, @@ -109,9 +109,9 @@ public: static const char* to_string(Pause type) { static const char* pause_strings[] = { "Normal", - "Prepare Mixed", "Concurrent Start", // Do not distinguish between the different "Concurrent Start", // Concurrent Start pauses. + "Prepare Mixed", "Cleanup", "Remark", "Mixed", @@ -129,7 +129,7 @@ public: assert_is_young_pause(type); return type == Pause::ConcurrentStartUndo || type == Pause::ConcurrentStartFull || - type == Pause::LastYoung || + type == Pause::PrepareMixed || type == Pause::Normal; } @@ -138,9 +138,9 @@ public: return type == Pause::Mixed; } - static bool is_last_young_pause(Pause type) { + static bool is_prepare_mixed_pause(Pause type) { assert_is_young_pause(type); - return type == Pause::LastYoung; + return type == Pause::PrepareMixed; } static bool is_concurrent_start_pause(Pause type) { diff --git a/src/hotspot/share/gc/g1/g1Policy.cpp b/src/hotspot/share/gc/g1/g1Policy.cpp index dce83a3f084..05caff1257a 100644 --- a/src/hotspot/share/gc/g1/g1Policy.cpp +++ b/src/hotspot/share/gc/g1/g1Policy.cpp @@ -729,7 +729,7 @@ double G1Policy::constant_other_time_ms(double pause_time_ms) const { } bool G1Policy::about_to_start_mixed_phase() const { - return collector_state()->is_in_concurrent_cycle() || collector_state()->is_in_young_gc_before_mixed(); + return collector_state()->is_in_concurrent_cycle() || collector_state()->is_in_prepare_mixed_gc(); } bool G1Policy::need_to_start_conc_mark(const char* source, size_t allocation_word_size) { @@ -935,7 +935,7 @@ void G1Policy::record_young_collection_end(bool concurrent_operation_is_full_mar record_pause(this_pause, start_time_sec, end_time_sec); - if (G1CollectorState::is_last_young_pause(this_pause)) { + if (G1CollectorState::is_prepare_mixed_pause(this_pause)) { assert(!G1CollectorState::is_concurrent_start_pause(this_pause), "The young GC before mixed is not allowed to be concurrent start GC"); // This has been the young GC before we start doing mixed GCs. We already @@ -1332,7 +1332,7 @@ void G1Policy::record_concurrent_mark_cleanup_end(bool has_rebuilt_remembered_se log_debug(gc, ergo)("request young-only gcs (candidate old regions not available)"); } if (mixed_gc_pending) { - collector_state()->set_in_young_gc_before_mixed(); + collector_state()->set_in_prepare_mixed_gc(); } double end_sec = os::elapsedTime(); @@ -1397,7 +1397,7 @@ void G1Policy::update_time_to_mixed_tracking(Pause gc_type, case Pause::Cleanup: case Pause::Remark: case Pause::Normal: - case Pause::LastYoung: + case Pause::PrepareMixed: _concurrent_start_to_mixed.add_pause(end - start); break; case Pause::ConcurrentStartFull: From 9658c19afdf401bfda7ac2d7e79e37bfb78c1330 Mon Sep 17 00:00:00 2001 From: Kangcheng Xu Date: Tue, 24 Mar 2026 16:16:51 +0000 Subject: [PATCH 008/359] 8378713: C2: performance regression due to missing constant folding for Math.pow() Reviewed-by: roland, mchevalier --- src/hotspot/share/opto/callnode.cpp | 174 ++++++++++++++ src/hotspot/share/opto/callnode.hpp | 17 ++ src/hotspot/share/opto/classes.hpp | 1 + src/hotspot/share/opto/library_call.cpp | 62 +---- src/hotspot/share/opto/macro.cpp | 18 +- .../intrinsics/math/PowDNodeTests.java | 218 ++++++++++++++++++ .../compiler/lib/ir_framework/IRNode.java | 6 + 7 files changed, 431 insertions(+), 65 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/intrinsics/math/PowDNodeTests.java diff --git a/src/hotspot/share/opto/callnode.cpp b/src/hotspot/share/opto/callnode.cpp index e01feb874ef..c7c0810ae85 100644 --- a/src/hotspot/share/opto/callnode.cpp +++ b/src/hotspot/share/opto/callnode.cpp @@ -43,6 +43,7 @@ #include "opto/rootnode.hpp" #include "opto/runtime.hpp" #include "runtime/sharedRuntime.hpp" +#include "runtime/stubRoutines.hpp" #include "utilities/powerOfTwo.hpp" // Portions of code courtesy of Clifford Click @@ -1371,6 +1372,25 @@ TupleNode* CallLeafPureNode::make_tuple_of_input_state_and_top_return_values(con return tuple; } +CallLeafPureNode* CallLeafPureNode::inline_call_leaf_pure_node(Node* control) const { + Node* top = Compile::current()->top(); + if (control == nullptr) { + control = in(TypeFunc::Control); + } + + CallLeafPureNode* call = new CallLeafPureNode(tf(), entry_point(), _name); + call->init_req(TypeFunc::Control, control); + call->init_req(TypeFunc::I_O, top); + call->init_req(TypeFunc::Memory, top); + call->init_req(TypeFunc::ReturnAdr, top); + call->init_req(TypeFunc::FramePtr, top); + for (unsigned int i = 0; i < tf()->domain()->cnt() - TypeFunc::Parms; i++) { + call->init_req(TypeFunc::Parms + i, in(TypeFunc::Parms + i)); + } + + return call; +} + Node* CallLeafPureNode::Ideal(PhaseGVN* phase, bool can_reshape) { if (is_dead()) { return nullptr; @@ -2437,3 +2457,157 @@ bool CallNode::may_modify_arraycopy_helper(const TypeOopPtr* dest_t, const TypeO return true; } + +PowDNode::PowDNode(Compile* C, Node* base, Node* exp) + : CallLeafPureNode( + OptoRuntime::Math_DD_D_Type(), + StubRoutines::dpow() != nullptr ? StubRoutines::dpow() : CAST_FROM_FN_PTR(address, SharedRuntime::dpow), + "pow") { + add_flag(Flag_is_macro); + C->add_macro_node(this); + + init_req(TypeFunc::Parms + 0, base); + init_req(TypeFunc::Parms + 1, C->top()); // double slot padding + init_req(TypeFunc::Parms + 2, exp); + init_req(TypeFunc::Parms + 3, C->top()); // double slot padding +} + +const Type* PowDNode::Value(PhaseGVN* phase) const { + const Type* t_base = phase->type(base()); + const Type* t_exp = phase->type(exp()); + + if (t_base == Type::TOP || t_exp == Type::TOP) { + return Type::TOP; + } + + const TypeD* base_con = t_base->isa_double_constant(); + const TypeD* exp_con = t_exp->isa_double_constant(); + const TypeD* result_t = nullptr; + + // constant folding: both inputs are constants + if (base_con != nullptr && exp_con != nullptr) { + result_t = TypeD::make(SharedRuntime::dpow(base_con->getd(), exp_con->getd())); + } + + // Special cases when only the exponent is known: + if (exp_con != nullptr) { + double e = exp_con->getd(); + + // If the second argument is positive or negative zero, then the result is 1.0. + // i.e., pow(x, +/-0.0D) => 1.0 + if (e == 0.0) { // true for both -0.0 and +0.0 + result_t = TypeD::ONE; + } + + // If the second argument is NaN, then the result is NaN. + // i.e., pow(x, NaN) => NaN + if (g_isnan(e)) { + result_t = TypeD::make(NAN); + } + } + + if (result_t != nullptr) { + // We can't simply return a TypeD here, it must be a tuple type to be compatible with call nodes. + const Type** fields = TypeTuple::fields(2); + fields[TypeFunc::Parms + 0] = result_t; + fields[TypeFunc::Parms + 1] = Type::HALF; + return TypeTuple::make(TypeFunc::Parms + 2, fields); + } + + return tf()->range(); +} + +Node* PowDNode::Ideal(PhaseGVN* phase, bool can_reshape) { + if (!can_reshape) { + return nullptr; // wait for igvn + } + + PhaseIterGVN* igvn = phase->is_IterGVN(); + Node* base = this->base(); + Node* exp = this->exp(); + + const Type* t_exp = phase->type(exp); + const TypeD* exp_con = t_exp->isa_double_constant(); + + // Special cases when only the exponent is known: + if (exp_con != nullptr) { + double e = exp_con->getd(); + + // If the second argument is 1.0, then the result is the same as the first argument. + // i.e., pow(x, 1.0) => x + if (e == 1.0) { + return make_tuple_of_input_state_and_result(igvn, base); + } + + // If the second argument is 2.0, then strength reduce to multiplications. + // i.e., pow(x, 2.0) => x * x + if (e == 2.0) { + Node* mul = igvn->transform(new MulDNode(base, base)); + return make_tuple_of_input_state_and_result(igvn, mul); + } + + // If the second argument is 0.5, the strength reduce to square roots. + // i.e., pow(x, 0.5) => sqrt(x) iff x > 0 + if (e == 0.5 && Matcher::match_rule_supported(Op_SqrtD)) { + Node* ctrl = in(TypeFunc::Control); + Node* zero = igvn->zerocon(T_DOUBLE); + + // According to the API specs, pow(-0.0, 0.5) = 0.0 and sqrt(-0.0) = -0.0. + // So pow(-0.0, 0.5) shouldn't be replaced with sqrt(-0.0). + // -0.0/+0.0 are both excluded since floating-point comparison doesn't distinguish -0.0 from +0.0. + Node* cmp = igvn->register_new_node_with_optimizer(new CmpDNode(base, zero)); + Node* test = igvn->register_new_node_with_optimizer(new BoolNode(cmp, BoolTest::le)); + + IfNode* iff = new IfNode(ctrl, test, PROB_UNLIKELY_MAG(3), COUNT_UNKNOWN); + igvn->register_new_node_with_optimizer(iff); + Node* if_slow = igvn->register_new_node_with_optimizer(new IfTrueNode(iff)); // x <= 0 + Node* if_fast = igvn->register_new_node_with_optimizer(new IfFalseNode(iff)); // x > 0 + + // slow path: call pow(x, 0.5) + Node* call = igvn->register_new_node_with_optimizer(inline_call_leaf_pure_node(if_slow)); + Node* call_ctrl = igvn->register_new_node_with_optimizer(new ProjNode(call, TypeFunc::Control)); + Node* call_result = igvn->register_new_node_with_optimizer(new ProjNode(call, TypeFunc::Parms + 0)); + + // fast path: sqrt(x) + Node* sqrt = igvn->register_new_node_with_optimizer(new SqrtDNode(igvn->C, if_fast, base)); + + // merge paths + RegionNode* region = new RegionNode(3); + igvn->register_new_node_with_optimizer(region); + region->init_req(1, call_ctrl); // slow path + region->init_req(2, if_fast); // fast path + + PhiNode* phi = new PhiNode(region, Type::DOUBLE); + igvn->register_new_node_with_optimizer(phi); + phi->init_req(1, call_result); // slow: pow() result + phi->init_req(2, sqrt); // fast: sqrt() result + + igvn->C->set_has_split_ifs(true); // Has chance for split-if optimization + + return make_tuple_of_input_state_and_result(igvn, phi, region); + } + } + + return CallLeafPureNode::Ideal(phase, can_reshape); +} + +// We can't simply have Ideal() returning a Con or MulNode since the users are still expecting a Call node, but we could +// produce a tuple that follows the same pattern so users can still get control, io, memory, etc.. +TupleNode* PowDNode::make_tuple_of_input_state_and_result(PhaseIterGVN* phase, Node* result, Node* control) { + if (control == nullptr) { + control = in(TypeFunc::Control); + } + + Compile* C = phase->C; + C->remove_macro_node(this); + TupleNode* tuple = TupleNode::make( + tf()->range(), + control, + in(TypeFunc::I_O), + in(TypeFunc::Memory), + in(TypeFunc::FramePtr), + in(TypeFunc::ReturnAdr), + result, + C->top()); + return tuple; +} diff --git a/src/hotspot/share/opto/callnode.hpp b/src/hotspot/share/opto/callnode.hpp index 95d1fc27d45..a5131676347 100644 --- a/src/hotspot/share/opto/callnode.hpp +++ b/src/hotspot/share/opto/callnode.hpp @@ -948,6 +948,8 @@ public: } int Opcode() const override; Node* Ideal(PhaseGVN* phase, bool can_reshape) override; + + CallLeafPureNode* inline_call_leaf_pure_node(Node* control = nullptr) const; }; //------------------------------CallLeafNoFPNode------------------------------- @@ -1299,4 +1301,19 @@ public: JVMState* dbg_jvms() const { return nullptr; } #endif }; + +//------------------------------PowDNode-------------------------------------- +class PowDNode : public CallLeafPureNode { + TupleNode* make_tuple_of_input_state_and_result(PhaseIterGVN* phase, Node* result, Node* control = nullptr); + +public: + PowDNode(Compile* C, Node* base, Node* exp); + int Opcode() const override; + const Type* Value(PhaseGVN* phase) const override; + Node* Ideal(PhaseGVN* phase, bool can_reshape) override; + + Node* base() const { return in(TypeFunc::Parms + 0); } + Node* exp() const { return in(TypeFunc::Parms + 2); } +}; + #endif // SHARE_OPTO_CALLNODE_HPP diff --git a/src/hotspot/share/opto/classes.hpp b/src/hotspot/share/opto/classes.hpp index 719b90ad6dd..d9290492337 100644 --- a/src/hotspot/share/opto/classes.hpp +++ b/src/hotspot/share/opto/classes.hpp @@ -286,6 +286,7 @@ macro(OpaqueZeroTripGuard) macro(OpaqueConstantBool) macro(OpaqueInitializedAssertionPredicate) macro(OpaqueTemplateAssertionPredicate) +macro(PowD) macro(ProfileBoolean) macro(OrI) macro(OrL) diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index eed99ceb8bc..e0f95377cde 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -1819,61 +1819,17 @@ bool LibraryCallKit::runtime_math(const TypeFunc* call_type, address funcAddr, c //------------------------------inline_math_pow----------------------------- bool LibraryCallKit::inline_math_pow() { + Node* base = argument(0); Node* exp = argument(2); - const TypeD* d = _gvn.type(exp)->isa_double_constant(); - if (d != nullptr) { - if (d->getd() == 2.0) { - // Special case: pow(x, 2.0) => x * x - Node* base = argument(0); - set_result(_gvn.transform(new MulDNode(base, base))); - return true; - } else if (d->getd() == 0.5 && Matcher::match_rule_supported(Op_SqrtD)) { - // Special case: pow(x, 0.5) => sqrt(x) - Node* base = argument(0); - Node* zero = _gvn.zerocon(T_DOUBLE); - RegionNode* region = new RegionNode(3); - Node* phi = new PhiNode(region, Type::DOUBLE); - - Node* cmp = _gvn.transform(new CmpDNode(base, zero)); - // According to the API specs, pow(-0.0, 0.5) = 0.0 and sqrt(-0.0) = -0.0. - // So pow(-0.0, 0.5) shouldn't be replaced with sqrt(-0.0). - // -0.0/+0.0 are both excluded since floating-point comparison doesn't distinguish -0.0 from +0.0. - Node* test = _gvn.transform(new BoolNode(cmp, BoolTest::le)); - - Node* if_pow = generate_slow_guard(test, nullptr); - Node* value_sqrt = _gvn.transform(new SqrtDNode(C, control(), base)); - phi->init_req(1, value_sqrt); - region->init_req(1, control()); - - if (if_pow != nullptr) { - set_control(if_pow); - address target = StubRoutines::dpow() != nullptr ? StubRoutines::dpow() : - CAST_FROM_FN_PTR(address, SharedRuntime::dpow); - const TypePtr* no_memory_effects = nullptr; - Node* trig = make_runtime_call(RC_LEAF, OptoRuntime::Math_DD_D_Type(), target, "POW", - no_memory_effects, base, top(), exp, top()); - Node* value_pow = _gvn.transform(new ProjNode(trig, TypeFunc::Parms+0)); -#ifdef ASSERT - Node* value_top = _gvn.transform(new ProjNode(trig, TypeFunc::Parms+1)); - assert(value_top == top(), "second value must be top"); -#endif - phi->init_req(2, value_pow); - region->init_req(2, _gvn.transform(new ProjNode(trig, TypeFunc::Control))); - } - - C->set_has_split_ifs(true); // Has chance for split-if optimization - set_control(_gvn.transform(region)); - record_for_igvn(region); - set_result(_gvn.transform(phi)); - - return true; - } - } - - return StubRoutines::dpow() != nullptr ? - runtime_math(OptoRuntime::Math_DD_D_Type(), StubRoutines::dpow(), "dpow") : - runtime_math(OptoRuntime::Math_DD_D_Type(), CAST_FROM_FN_PTR(address, SharedRuntime::dpow), "POW"); + CallNode* pow = new PowDNode(C, base, exp); + set_predefined_input_for_runtime_call(pow); + pow = _gvn.transform(pow)->as_CallLeafPure(); + set_predefined_output_for_runtime_call(pow); + Node* result = _gvn.transform(new ProjNode(pow, TypeFunc::Parms + 0)); + record_for_igvn(pow); + set_result(result); + return true; } //------------------------------inline_math_native----------------------------- diff --git a/src/hotspot/share/opto/macro.cpp b/src/hotspot/share/opto/macro.cpp index 48277eb46d2..c78f6533840 100644 --- a/src/hotspot/share/opto/macro.cpp +++ b/src/hotspot/share/opto/macro.cpp @@ -2500,6 +2500,7 @@ void PhaseMacroExpand::eliminate_macro_nodes() { assert(n->Opcode() == Op_LoopLimit || n->Opcode() == Op_ModD || n->Opcode() == Op_ModF || + n->Opcode() == Op_PowD || n->is_OpaqueConstantBool() || n->is_OpaqueInitializedAssertionPredicate() || n->Opcode() == Op_MaxL || @@ -2656,18 +2657,11 @@ bool PhaseMacroExpand::expand_macro_nodes() { default: switch (n->Opcode()) { case Op_ModD: - case Op_ModF: { - CallNode* mod_macro = n->as_Call(); - CallNode* call = new CallLeafPureNode(mod_macro->tf(), mod_macro->entry_point(), mod_macro->_name); - call->init_req(TypeFunc::Control, mod_macro->in(TypeFunc::Control)); - call->init_req(TypeFunc::I_O, C->top()); - call->init_req(TypeFunc::Memory, C->top()); - call->init_req(TypeFunc::ReturnAdr, C->top()); - call->init_req(TypeFunc::FramePtr, C->top()); - for (unsigned int i = 0; i < mod_macro->tf()->domain()->cnt() - TypeFunc::Parms; i++) { - call->init_req(TypeFunc::Parms + i, mod_macro->in(TypeFunc::Parms + i)); - } - _igvn.replace_node(mod_macro, call); + case Op_ModF: + case Op_PowD: { + CallLeafPureNode* call_macro = n->as_CallLeafPure(); + CallLeafPureNode* call = call_macro->inline_call_leaf_pure_node(); + _igvn.replace_node(call_macro, call); transform_later(call); break; } diff --git a/test/hotspot/jtreg/compiler/intrinsics/math/PowDNodeTests.java b/test/hotspot/jtreg/compiler/intrinsics/math/PowDNodeTests.java new file mode 100644 index 00000000000..e28cc5ab346 --- /dev/null +++ b/test/hotspot/jtreg/compiler/intrinsics/math/PowDNodeTests.java @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2026, IBM and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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.intrinsics.math; + +import jdk.test.lib.Asserts; + +import compiler.lib.ir_framework.*; +import compiler.lib.generators.*; +import static compiler.lib.generators.Generators.*; + +import java.util.Random; + +/* + * @test + * @bug 8378713 + * @key randomness + * @summary Math.pow(base, exp) should constant propagate + * @library /test/lib / + * @run driver ${test.main.class} + */ +public class PowDNodeTests { + public static final Generator UNIFORMS = G.uniformDoubles(); // [0, 1) + + public static final double B = UNIFORMS.next() * 1000.0d; + public static final double E = UNIFORMS.next() * 1000.0d + 3.0d; // e >= 3 to avoid strength reduction code + + public static void main(String[] args) { + TestFramework.run(); + + testCorrectness(); + } + + // Test 1: pow(2.0, 10.0) -> 1024.0 + @Test + @IR(failOn = {IRNode.POW_D}) + public static double constantLiteralFolding() { + return Math.pow(2.0, 10.0); // should fold to 1024.0 + } + + // Test 2: pow(final B, final E) -> B^E + @Test + @IR(failOn = {IRNode.POW_D}) + public static double constantStaticFolding() { + return Math.pow(B, E); // should fold to B^E + } + + // Test 3: pow(b, 0.0) -> 1.0 + @Test + @IR(failOn = {IRNode.POW_D}) + @Arguments(values = {Argument.RANDOM_EACH}) + public static double expZero(double b) { + return Math.pow(b, 0.0); + } + + // Test 4: pow(b, 1.0) -> b (identity) + @Test + @IR(failOn = {IRNode.POW_D}) + @Arguments(values = {Argument.RANDOM_EACH}) + public static double expOne(double b) { + return Math.pow(b, 1.0); + } + + // Test 5: pow(b, NaN) -> NaN + @Test + @IR(failOn = {IRNode.POW_D}) + @Arguments(values = {Argument.RANDOM_EACH}) + public static double expNaN(double b) { + return Math.pow(b, Double.NaN); + } + + // Test 6: pow(b, 2.0) -> b * b + // More tests in TestPow2Opt.java + @Test + @IR(failOn = {IRNode.POW_D}) + @IR(counts = {IRNode.MUL_D, "1"}) + @Arguments(values = {Argument.RANDOM_EACH}) + public static double expTwo(double b) { + return Math.pow(b, 2.0); + } + + // Test 7: pow(b, 0.5) -> b <= 0.0 ? pow(b, 0.5) : sqrt(b) + // More tests in TestPow0Dot5Opt.java + @Test + @IR(counts = {IRNode.IF, "1"}) + @IR(counts = {IRNode.SQRT_D, "1"}) + @IR(counts = {".*CallLeaf.*pow.*", "1"}, phase = CompilePhase.BEFORE_MATCHING) + @Arguments(values = {Argument.RANDOM_EACH}) + public static double expDot5(double b) { + return Math.pow(b, 0.5); // expand to: if (b > 0) { sqrt(b) } else { call(b) } + } + + // Test 8: non-constant exponent stays as call + @Test + @IR(counts = {IRNode.POW_D, "1"}) + @Arguments(values = {Argument.RANDOM_EACH, Argument.RANDOM_EACH}) + public static double nonConstant(double b, double e) { + return Math.pow(b, e); + } + + // Test 9: late constant discovery on base (after loop opts) + @Test + @IR(counts = {IRNode.POW_D, "1"}, phase = CompilePhase.AFTER_PARSING) + @IR(failOn = {IRNode.POW_D}) + public static double lateBaseConstant() { + double base = 0; + for (int i = 0; i < 4; i++) { + if ((i % 2) == 0) { + base = B; + } + } + // After loop opts, base == B (constant), so pow(B, E) folds + return Math.pow(base, E); + } + + // Test 10: late constant discovery on exp (after loop opts) + @Test + @IR(counts = {IRNode.POW_D, "1"}, phase = CompilePhase.AFTER_PARSING) + @IR(failOn = {IRNode.POW_D}) + public static double lateExpConstant() { + double exp = 0; + for (int i = 0; i < 4; i++) { + if ((i % 2) == 0) { + exp = E; + } + } + // After loop opts, exp == E (constant), so pow(B, E) folds + return Math.pow(B, exp); + } + + // Test 11: late constant discoveries on both base and exp (after loop opts) + @Test + @IR(counts = {IRNode.POW_D, "1"}, phase = CompilePhase.AFTER_PARSING) + @IR(failOn = {IRNode.POW_D}) + public static double lateBothConstant() { + double base = 0, exp = 0; + for (int i = 0; i < 4; i++) { + if ((i % 2) == 0) { + base = B; + exp = E; + } + } + // After loop opts, base = B, exp == E, so pow(B, E) folds + return Math.pow(base, exp); + } + + private static void assertEQWithinOneUlp(double expected, double observed) { + if (Double.isNaN(expected) && Double.isNaN(observed)) return; + + // Math.pow() requires result must be within 1 ulp of the respective magnitude + double ulp = Math.max(Math.ulp(expected), Math.ulp(observed)); + if (Math.abs(expected - observed) > ulp) { + throw new AssertionError(String.format( + "expect = %x, observed = %x, ulp = %x", + Double.doubleToRawLongBits(expected), Double.doubleToRawLongBits(observed), Double.doubleToRawLongBits(ulp) + )); + } + } + + private static void testCorrectness() { + // No need to warm up for intrinsics + Asserts.assertEQ(1024.0d, constantLiteralFolding()); + + double BE = StrictMath.pow(B, E); + assertEQWithinOneUlp(BE, constantStaticFolding()); + assertEQWithinOneUlp(BE, lateBaseConstant()); + assertEQWithinOneUlp(BE, lateExpConstant()); + assertEQWithinOneUlp(BE, lateBothConstant()); + + Generator anyBits = G.anyBitsDouble(); + Generator largeDoubles = G.uniformDoubles(Long.MAX_VALUE, Double.MAX_VALUE); + Generator doubles = G.doubles(); + double[] values = { + Double.MIN_VALUE, Double.MIN_NORMAL, -42.0d, -1.0d, -0.0d, +0.0d, 0.5d, 1.0d, 2.0d, 123d, Double.MAX_VALUE, + Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, Double.NaN, + UNIFORMS.next(), UNIFORMS.next(), + largeDoubles.next(), -largeDoubles.next(), // some sufficiently large magnitudes + anyBits.next(), anyBits.next(), // any bits with potentially more NaN representation + doubles.next(), doubles.next() // a healthy sprinkle of whatever else is possible + }; + + for (double b : values) { + // Strength reduced, so we know the bits matches exactly + Asserts.assertEQ(1.0d, expZero(b)); + Asserts.assertEQ(b, expOne(b)); + Asserts.assertEQ(b * b, expTwo(b)); + + assertEQWithinOneUlp(Double.NaN, expNaN(b)); + + // Runtime calls, so make sure the result is within 1 ulp + assertEQWithinOneUlp(StrictMath.pow(b, 0.5d), expDot5(b)); + + for (double e : values) { + assertEQWithinOneUlp(StrictMath.pow(b, e), nonConstant(b, e)); + } + } + } +} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java index ebc95527344..8885d1283df 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java @@ -3134,6 +3134,12 @@ public class IRNode { macroNodes(MOD_D, regex); } + public static final String POW_D = PREFIX + "POW_D" + POSTFIX; + static { + String regex = START + "PowD" + MID + END; + macroNodes(POW_D, regex); + } + public static final String BLACKHOLE = PREFIX + "BLACKHOLE" + POSTFIX; static { fromBeforeRemoveUselessToFinalCode(BLACKHOLE, "Blackhole"); From 7b7f40b143ff84b7d4580930ec11926b833af031 Mon Sep 17 00:00:00 2001 From: Daniel Fuchs Date: Tue, 24 Mar 2026 17:12:50 +0000 Subject: [PATCH 009/359] 8380561: Refactor java/nio/channels/DatagramChannel TestNG tests to use JUnit Reviewed-by: alanb, bpb --- .../DatagramChannel/AdaptorConnect.java | 31 +++--- .../DatagramChannel/AdaptorGetters.java | 105 +++++++++--------- .../DatagramChannel/AfterDisconnect.java | 40 +++---- .../DatagramChannel/ConnectExceptions.java | 93 +++++++++------- .../DatagramChannel/ConnectPortZero.java | 59 +++++----- .../DatagramChannel/ConnectedSend.java | 34 +++--- .../nio/channels/DatagramChannel/SRTest.java | 32 ++++-- .../DatagramChannel/SendExceptions.java | 99 ++++++++++------- .../DatagramChannel/SendPortZero.java | 59 +++++----- .../DatagramChannel/SendReceiveMaxSize.java | 64 ++++++----- 10 files changed, 343 insertions(+), 273 deletions(-) diff --git a/test/jdk/java/nio/channels/DatagramChannel/AdaptorConnect.java b/test/jdk/java/nio/channels/DatagramChannel/AdaptorConnect.java index a609089e459..bf6b9023eb4 100644 --- a/test/jdk/java/nio/channels/DatagramChannel/AdaptorConnect.java +++ b/test/jdk/java/nio/channels/DatagramChannel/AdaptorConnect.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * 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 8232673 * @summary Test DatagramChannel socket adaptor connect method with illegal args - * @run testng AdaptorConnect + * @run junit AdaptorConnect */ import java.net.DatagramSocket; @@ -34,10 +34,9 @@ import java.net.SocketException; import java.nio.channels.DatagramChannel; import static java.net.InetAddress.getLoopbackAddress; -import org.testng.annotations.Test; -import static org.testng.Assert.*; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; -@Test public class AdaptorConnect { /** @@ -59,6 +58,7 @@ public class AdaptorConnect { /** * Test connect method with an open socket. */ + @Test public void testOpenSocket() throws Exception { try (DatagramChannel dc = DatagramChannel.open()) { DatagramSocket s = dc.socket(); @@ -66,42 +66,43 @@ public class AdaptorConnect { testConnectWithIllegalArguments(s); // should not be bound or connected - assertTrue(s.getLocalSocketAddress() == null); - assertTrue(s.getRemoteSocketAddress() == null); + assertNull(s.getLocalSocketAddress()); + assertNull(s.getRemoteSocketAddress()); // connect(SocketAddress) var remote1 = new InetSocketAddress(getLoopbackAddress(), 7001); s.connect(remote1); - assertEquals(s.getRemoteSocketAddress(), remote1); + assertEquals(remote1, s.getRemoteSocketAddress()); testConnectWithIllegalArguments(s); - assertEquals(s.getRemoteSocketAddress(), remote1); + assertEquals(remote1, s.getRemoteSocketAddress()); // connect(SocketAddress) var remote2 = new InetSocketAddress(getLoopbackAddress(), 7002); s.connect(remote2); - assertEquals(s.getRemoteSocketAddress(), remote2); + assertEquals(remote2, s.getRemoteSocketAddress()); testConnectWithIllegalArguments(s); - assertEquals(s.getRemoteSocketAddress(), remote2); + assertEquals(remote2, s.getRemoteSocketAddress()); // connect(InetAddress, int) var remote3 = new InetSocketAddress(getLoopbackAddress(), 7003); s.connect(remote3.getAddress(), remote3.getPort()); - assertEquals(s.getRemoteSocketAddress(), remote3); + assertEquals(remote3, s.getRemoteSocketAddress()); testConnectWithIllegalArguments(s); - assertEquals(s.getRemoteSocketAddress(), remote3); + assertEquals(remote3, s.getRemoteSocketAddress()); // connect(InetAddress, int) var remote4 = new InetSocketAddress(getLoopbackAddress(), 7004); s.connect(remote4.getAddress(), remote4.getPort()); - assertEquals(s.getRemoteSocketAddress(), remote4); + assertEquals(remote4, s.getRemoteSocketAddress()); testConnectWithIllegalArguments(s); - assertEquals(s.getRemoteSocketAddress(), remote4); + assertEquals(remote4, s.getRemoteSocketAddress()); } } /** * Test connect method with a closed socket. */ + @Test public void testClosedSocket() throws Exception { DatagramChannel dc = DatagramChannel.open(); DatagramSocket s = dc.socket(); diff --git a/test/jdk/java/nio/channels/DatagramChannel/AdaptorGetters.java b/test/jdk/java/nio/channels/DatagramChannel/AdaptorGetters.java index 9e12f46be04..69f5a76c12d 100644 --- a/test/jdk/java/nio/channels/DatagramChannel/AdaptorGetters.java +++ b/test/jdk/java/nio/channels/DatagramChannel/AdaptorGetters.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * 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 8232673 * @summary Test the DatagramChannel socket adaptor getter methods - * @run testng AdaptorGetters + * @run junit AdaptorGetters */ import java.net.DatagramSocket; @@ -32,15 +32,15 @@ import java.net.InetAddress; import java.net.InetSocketAddress; import java.nio.channels.DatagramChannel; -import org.testng.annotations.Test; -import static org.testng.Assert.*; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; -@Test public class AdaptorGetters { /** * Test getters on unbound socket, before and after it is closed. */ + @Test public void testUnboundSocket() throws Exception { DatagramChannel dc = DatagramChannel.open(); DatagramSocket s = dc.socket(); @@ -53,12 +53,12 @@ public class AdaptorGetters { // local address assertTrue(s.getLocalAddress().isAnyLocalAddress()); - assertTrue(s.getLocalPort() == 0); - assertTrue(s.getLocalSocketAddress() == null); + assertEquals(0, s.getLocalPort()); + assertNull(s.getLocalSocketAddress()); // remote address - assertTrue(s.getInetAddress() == null); - assertTrue(s.getPort() == -1); + assertNull(s.getInetAddress()); + assertEquals(-1, s.getPort()); } finally { dc.close(); @@ -70,19 +70,20 @@ public class AdaptorGetters { assertTrue(s.isClosed()); // local address - assertTrue(s.getLocalAddress() == null); - assertTrue(s.getLocalPort() == -1); - assertTrue(s.getLocalSocketAddress() == null); + assertNull(s.getLocalAddress()); + assertEquals(-1, s.getLocalPort()); + assertNull(s.getLocalSocketAddress()); // remote address - assertTrue(s.getInetAddress() == null); - assertTrue(s.getPort() == -1); - assertTrue((s.getRemoteSocketAddress() == null)); + assertNull(s.getInetAddress()); + assertEquals(-1, s.getPort()); + assertNull(s.getRemoteSocketAddress()); } /** * Test getters on bound socket, before and after it is closed. */ + @Test public void testBoundSocket() throws Exception { DatagramChannel dc = DatagramChannel.open(); DatagramSocket s = dc.socket(); @@ -96,14 +97,14 @@ public class AdaptorGetters { assertFalse(s.isClosed()); // local address - assertEquals(s.getLocalAddress(), localAddress.getAddress()); - assertTrue(s.getLocalPort() == localAddress.getPort()); - assertEquals(s.getLocalSocketAddress(), localAddress); + assertEquals(localAddress.getAddress(), s.getLocalAddress()); + assertEquals(localAddress.getPort(), s.getLocalPort()); + assertEquals(localAddress, s.getLocalSocketAddress()); // remote address - assertTrue(s.getInetAddress() == null); - assertTrue(s.getPort() == -1); - assertTrue((s.getRemoteSocketAddress() == null)); + assertNull(s.getInetAddress()); + assertEquals(-1, s.getPort()); + assertNull(s.getRemoteSocketAddress()); } finally { dc.close(); @@ -115,19 +116,20 @@ public class AdaptorGetters { assertTrue(s.isClosed()); // local address - assertTrue(s.getLocalAddress() == null); - assertTrue(s.getLocalPort() == -1); - assertTrue(s.getLocalSocketAddress() == null); + assertNull(s.getLocalAddress()); + assertEquals(-1, s.getLocalPort()); + assertNull(s.getLocalSocketAddress()); // remote address - assertTrue(s.getInetAddress() == null); - assertTrue(s.getPort() == -1); - assertTrue((s.getRemoteSocketAddress() == null)); + assertNull(s.getInetAddress()); + assertEquals(-1, s.getPort()); + assertNull(s.getRemoteSocketAddress()); } /** * Test getters on connected socket, before and after it is closed. */ + @Test public void testConnectedSocket() throws Exception { var loopback = InetAddress.getLoopbackAddress(); var remoteAddress = new InetSocketAddress(loopback, 7777); @@ -143,14 +145,14 @@ public class AdaptorGetters { assertFalse(s.isClosed()); // local address - assertEquals(s.getLocalAddress(), localAddress.getAddress()); - assertTrue(s.getLocalPort() == localAddress.getPort()); - assertEquals(s.getLocalSocketAddress(), localAddress); + assertEquals(localAddress.getAddress(), s.getLocalAddress()); + assertEquals(localAddress.getPort(), s.getLocalPort()); + assertEquals(localAddress, s.getLocalSocketAddress()); // remote address - assertEquals(s.getInetAddress(), remoteAddress.getAddress()); - assertTrue(s.getPort() == remoteAddress.getPort()); - assertEquals(s.getRemoteSocketAddress(), remoteAddress); + assertEquals(remoteAddress.getAddress(), s.getInetAddress()); + assertEquals(remoteAddress.getPort(), s.getPort()); + assertEquals(remoteAddress, s.getRemoteSocketAddress()); } finally { dc.close(); @@ -162,19 +164,20 @@ public class AdaptorGetters { assertTrue(s.isClosed()); // local address - assertTrue(s.getLocalAddress() == null); - assertTrue(s.getLocalPort() == -1); - assertTrue(s.getLocalSocketAddress() == null); + assertNull(s.getLocalAddress()); + assertEquals(-1, s.getLocalPort()); + assertNull(s.getLocalSocketAddress()); // remote address - assertEquals(s.getInetAddress(), remoteAddress.getAddress()); - assertTrue(s.getPort() == remoteAddress.getPort()); - assertEquals(s.getRemoteSocketAddress(), remoteAddress); + assertEquals(remoteAddress.getAddress(), s.getInetAddress()); + assertEquals(remoteAddress.getPort(), s.getPort()); + assertEquals(remoteAddress, s.getRemoteSocketAddress()); } /** * Test getters on disconnected socket, before and after it is closed. */ + @Test public void testDisconnectedSocket() throws Exception { DatagramChannel dc = DatagramChannel.open(); DatagramSocket s = dc.socket(); @@ -191,14 +194,14 @@ public class AdaptorGetters { assertFalse(s.isClosed()); // local address - assertEquals(s.getLocalAddress(), localAddress.getAddress()); - assertTrue(s.getLocalPort() == localAddress.getPort()); - assertEquals(s.getLocalSocketAddress(), localAddress); + assertEquals(localAddress.getAddress(), s.getLocalAddress()); + assertEquals(localAddress.getPort(), s.getLocalPort()); + assertEquals(localAddress, s.getLocalSocketAddress()); // remote address - assertTrue(s.getInetAddress() == null); - assertTrue(s.getPort() == -1); - assertTrue((s.getRemoteSocketAddress() == null)); + assertNull(s.getInetAddress()); + assertEquals(-1, s.getPort()); + assertNull(s.getRemoteSocketAddress()); } finally { @@ -211,13 +214,13 @@ public class AdaptorGetters { assertTrue(s.isClosed()); // local address - assertTrue(s.getLocalAddress() == null); - assertTrue(s.getLocalPort() == -1); - assertTrue(s.getLocalSocketAddress() == null); + assertNull(s.getLocalAddress()); + assertEquals(-1, s.getLocalPort()); + assertNull(s.getLocalSocketAddress()); // remote address - assertTrue(s.getInetAddress() == null); - assertTrue(s.getPort() == -1); - assertTrue((s.getRemoteSocketAddress() == null)); + assertNull(s.getInetAddress()); + assertEquals(-1, s.getPort()); + assertNull(s.getRemoteSocketAddress()); } } diff --git a/test/jdk/java/nio/channels/DatagramChannel/AfterDisconnect.java b/test/jdk/java/nio/channels/DatagramChannel/AfterDisconnect.java index de59984dae1..44a34ea3e55 100644 --- a/test/jdk/java/nio/channels/DatagramChannel/AfterDisconnect.java +++ b/test/jdk/java/nio/channels/DatagramChannel/AfterDisconnect.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * 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,9 @@ * @bug 8231880 8231258 * @library /test/lib * @summary Test DatagramChannel bound to specific address/ephemeral port after disconnect - * @run testng/othervm AfterDisconnect - * @run testng/othervm -Djava.net.preferIPv4Stack=true AfterDisconnect - * @run testng/othervm -Djava.net.preferIPv6Addresses=true AfterDisconnect + * @run junit/othervm AfterDisconnect + * @run junit/othervm -Djava.net.preferIPv4Stack=true AfterDisconnect + * @run junit/othervm -Djava.net.preferIPv6Addresses=true AfterDisconnect */ import java.io.IOException; @@ -49,15 +49,17 @@ import java.util.HashMap; import java.util.Map; import java.util.function.Predicate; -import org.testng.annotations.Test; -import static org.testng.Assert.*; - import jdk.test.lib.net.IPSupport; +import org.junit.jupiter.api.Test; + +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.junit.jupiter.api.Assertions.*; + public class AfterDisconnect { interface RetryableTest { - public void runTest() throws T; + void runTest() throws T; } // retry the given lambda (RetryableTest) if an exception @@ -81,7 +83,7 @@ public class AfterDisconnect { * When calling {@link DatagramChannel#disconnect()} a {@link BindException} * may occur. In which case we want to retry the test. */ - class BindExceptionOnDisconnect extends BindException { + static class BindExceptionOnDisconnect extends BindException { BindExceptionOnDisconnect(BindException x) { super(x.getMessage()); initCause(x); @@ -149,8 +151,8 @@ public class AfterDisconnect { dc.connect(remote); assertTrue(dc.isConnected()); - assertEquals(dc.getLocalAddress(), local); - assertEquals(dc.getRemoteAddress(), remote); + assertEquals(local, dc.getLocalAddress()); + assertEquals(remote, dc.getRemoteAddress()); try { dc.disconnect(); @@ -158,8 +160,8 @@ public class AfterDisconnect { throw new BindExceptionOnDisconnect(x); } assertFalse(dc.isConnected()); - assertEquals(dc.getLocalAddress(), local); - assertTrue(dc.getRemoteAddress() == null); + assertEquals(local, dc.getLocalAddress()); + assertNull(dc.getRemoteAddress()); } } @@ -192,7 +194,7 @@ public class AfterDisconnect { /** * Returns a map of the given channel's socket options and values. */ - private Map, Object> options(DatagramChannel dc) throws IOException { + private Map, Object> options(DatagramChannel dc) { Map, Object> map = new HashMap<>(); for (SocketOption option : dc.supportedOptions()) { try { @@ -229,15 +231,15 @@ public class AfterDisconnect { // check blocking mode with non-blocking receive ByteBuffer bb = ByteBuffer.allocate(100); SocketAddress sender = dc.receive(bb); - assertTrue(sender == null); + assertNull(sender); // send datagram and ensure that channel is selected - dc.send(ByteBuffer.wrap("Hello".getBytes("UTF-8")), dc.getLocalAddress()); + dc.send(ByteBuffer.wrap("Hello".getBytes(UTF_8)), dc.getLocalAddress()); assertFalse(key.isReadable()); while (sel.select() == 0); assertTrue(key.isReadable()); sender = dc.receive(bb); - assertEquals(sender, dc.getLocalAddress()); + assertEquals(dc.getLocalAddress(), sender); // cancel key, flush from Selector, and restore blocking mode key.cancel(); @@ -273,10 +275,10 @@ public class AfterDisconnect { assertTrue(key.isValid()); // send datagram to multicast group, should be received - dc.send(ByteBuffer.wrap("Hello".getBytes("UTF-8")), dc.getLocalAddress()); + dc.send(ByteBuffer.wrap("Hello".getBytes(UTF_8)), dc.getLocalAddress()); ByteBuffer bb = ByteBuffer.allocate(100); SocketAddress sender = dc.receive(bb); - assertEquals(sender, dc.getLocalAddress()); + assertEquals(dc.getLocalAddress(), sender); // drop membership key.drop(); diff --git a/test/jdk/java/nio/channels/DatagramChannel/ConnectExceptions.java b/test/jdk/java/nio/channels/DatagramChannel/ConnectExceptions.java index a913f1f42e9..a89c4798c08 100644 --- a/test/jdk/java/nio/channels/DatagramChannel/ConnectExceptions.java +++ b/test/jdk/java/nio/channels/DatagramChannel/ConnectExceptions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,26 +25,32 @@ * @bug 8198753 * @summary Test DatagramChannel connect exceptions * @library .. - * @run testng ConnectExceptions + * @run junit ConnectExceptions */ -import java.io.*; -import java.net.*; -import java.nio.*; -import java.nio.channels.*; -import org.testng.annotations.AfterTest; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.Test; -import static org.testng.Assert.*; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.nio.channels.AlreadyConnectedException; +import java.nio.channels.DatagramChannel; +import java.nio.channels.UnresolvedAddressException; +import java.nio.channels.UnsupportedAddressTypeException; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; public class ConnectExceptions { - static DatagramChannel sndChannel; - static DatagramChannel rcvChannel; - static InetSocketAddress sender; - static InetSocketAddress receiver; + private DatagramChannel sndChannel; + private DatagramChannel rcvChannel; + private InetSocketAddress sender; + private InetSocketAddress receiver; - @BeforeTest - public static void setup() throws Exception { + @BeforeEach + public void setup() throws Exception { sndChannel = DatagramChannel.open(); sndChannel.bind(null); InetAddress address = InetAddress.getLocalHost(); @@ -60,29 +66,40 @@ public class ConnectExceptions { rcvChannel.socket().getLocalPort()); } - @Test(expectedExceptions = UnsupportedAddressTypeException.class) - public static void unsupportedAddressTypeException() throws Exception { - rcvChannel.connect(sender); - sndChannel.connect(new SocketAddress() {}); - } - - @Test(expectedExceptions = UnresolvedAddressException.class) - public static void unresolvedAddressException() throws Exception { - String host = TestUtil.UNRESOLVABLE_HOST; - InetSocketAddress unresolvable = new InetSocketAddress (host, 37); - sndChannel.connect(unresolvable); - } - - @Test(expectedExceptions = AlreadyConnectedException.class) - public static void alreadyConnectedException() throws Exception { - sndChannel.connect(receiver); - InetSocketAddress random = new InetSocketAddress(0); - sndChannel.connect(random); - } - - @AfterTest - public static void cleanup() throws Exception { + @AfterEach + public void cleanup() throws Exception { rcvChannel.close(); sndChannel.close(); } + + @Test + public void unsupportedAddressTypeException() throws IOException { + rcvChannel.connect(sender); + assertThrows(UnsupportedAddressTypeException.class, () -> { + sndChannel.connect(new SocketAddress() {}); + }); + } + + @Test + public void unresolvedAddressException() throws IOException { + String host = TestUtil.UNRESOLVABLE_HOST; + InetSocketAddress unresolvable = new InetSocketAddress (host, 37); + assertThrows(UnresolvedAddressException.class, () -> { + sndChannel.connect(unresolvable); + }); + sndChannel.connect(receiver); + assertThrows(UnresolvedAddressException.class, () -> { + sndChannel.connect(unresolvable); + }); + } + + @Test + public void alreadyConnectedException() throws IOException { + sndChannel.connect(receiver); + assertThrows(AlreadyConnectedException.class, () -> { + InetSocketAddress random = new InetSocketAddress(0); + sndChannel.connect(random); + }); + } + } diff --git a/test/jdk/java/nio/channels/DatagramChannel/ConnectPortZero.java b/test/jdk/java/nio/channels/DatagramChannel/ConnectPortZero.java index 4aa28e5226e..3ddad9ef526 100644 --- a/test/jdk/java/nio/channels/DatagramChannel/ConnectPortZero.java +++ b/test/jdk/java/nio/channels/DatagramChannel/ConnectPortZero.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * 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,10 +21,6 @@ * questions. */ -import org.testng.annotations.AfterTest; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import java.io.IOException; import java.net.InetAddress; @@ -38,7 +34,15 @@ import static jdk.test.lib.net.IPSupport.hasIPv6; import static jdk.test.lib.net.IPSupport.hasIPv4; import static java.net.StandardProtocolFamily.INET; import static java.net.StandardProtocolFamily.INET6; -import static org.testng.Assert.assertThrows; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; /* * @test @@ -46,51 +50,54 @@ import static org.testng.Assert.assertThrows; * @library /test/lib * @build jdk.test.lib.net.IPSupport * @summary Check that DatagramChannel throws expected Exception when connecting to port 0 - * @run testng ConnectPortZero - * @run testng/othervm -Djava.net.preferIPv4Stack=true ConnectPortZero + * @run junit ConnectPortZero + * @run junit/othervm -Djava.net.preferIPv4Stack=true ConnectPortZero */ public class ConnectPortZero { - private InetSocketAddress loopbackZeroAddr, wildcardZeroAddr; - private DatagramChannel datagramChannel, datagramChannelIPv4, datagramChannelIPv6; - private List channels; + private static InetSocketAddress loopbackZeroAddr, wildcardZeroAddr; + private static DatagramChannel datagramChannel, datagramChannelIPv4, datagramChannelIPv6; + private static List channels; private static final Class SE = SocketException.class; - @BeforeTest - public void setUp() throws IOException { + @BeforeAll + public static void setUp() throws IOException { wildcardZeroAddr = new InetSocketAddress(0); loopbackZeroAddr = new InetSocketAddress(InetAddress.getLoopbackAddress(), 0); channels = new ArrayList<>(); datagramChannel = DatagramChannel.open(); - channels.add(new Object[]{datagramChannel}); + channels.add(datagramChannel); if (hasIPv4()) { datagramChannelIPv4 = DatagramChannel.open(INET); - channels.add(new Object[]{datagramChannelIPv4}); + channels.add(datagramChannelIPv4); } if (hasIPv6()) { datagramChannelIPv6 = DatagramChannel.open(INET6); - channels.add(new Object[]{datagramChannelIPv6}); + channels.add(datagramChannelIPv6); } } - @DataProvider(name = "data") - public Object[][] variants() { - return channels.toArray(Object[][]::new); + @AfterAll + public static void tearDown() throws IOException { + for(DatagramChannel ch : channels) { + ch.close(); + } } - @Test(dataProvider = "data") + public static List channels() { + return channels; + } + + @ParameterizedTest + @MethodSource("channels") public void testChannelConnect(DatagramChannel dc) { + assertTrue(dc.isOpen()); + assertFalse(dc.isConnected()); assertThrows(SE, () -> dc.connect(loopbackZeroAddr)); assertThrows(SE, () -> dc.connect(wildcardZeroAddr)); } - @AfterTest - public void tearDown() throws IOException { - for(Object[] ch : channels) { - ((DatagramChannel)ch[0]).close(); - } - } } diff --git a/test/jdk/java/nio/channels/DatagramChannel/ConnectedSend.java b/test/jdk/java/nio/channels/DatagramChannel/ConnectedSend.java index d761f8db3f0..78e5a37294f 100644 --- a/test/jdk/java/nio/channels/DatagramChannel/ConnectedSend.java +++ b/test/jdk/java/nio/channels/DatagramChannel/ConnectedSend.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * 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,23 +25,27 @@ * @bug 4849277 7183800 * @summary Test DatagramChannel send while connected * @library .. - * @run testng ConnectedSend + * @run junit ConnectedSend * @author Mike McCloskey */ -import java.io.*; -import java.net.*; -import java.nio.*; -import java.nio.channels.*; -import java.nio.charset.*; -import org.testng.annotations.Test; -import static org.testng.Assert.*; + +import java.net.DatagramPacket; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.channels.DatagramChannel; +import java.nio.charset.StandardCharsets; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; public class ConnectedSend { // Check if DatagramChannel.send while connected can include // address without throwing @Test - public static void sendToConnectedAddress() throws Exception { + public void sendToConnectedAddress() throws Exception { DatagramChannel sndChannel = DatagramChannel.open(); sndChannel.bind(null); InetAddress address = InetAddress.getLocalHost(); @@ -68,7 +72,7 @@ public class ConnectedSend { bb.clear(); rcvChannel.receive(bb); bb.flip(); - CharBuffer cb = Charset.forName("US-ASCII").newDecoder().decode(bb); + CharBuffer cb = StandardCharsets.US_ASCII.newDecoder().decode(bb); assertTrue(cb.toString().startsWith("h"), "Unexpected message content"); rcvChannel.close(); @@ -79,7 +83,7 @@ public class ConnectedSend { // that has not been initialized with an address; the legacy // datagram socket will send in this case @Test - public static void sendAddressedPacket() throws Exception { + public void sendAddressedPacket() throws Exception { DatagramChannel sndChannel = DatagramChannel.open(); sndChannel.bind(null); InetAddress address = InetAddress.getLocalHost(); @@ -99,19 +103,19 @@ public class ConnectedSend { rcvChannel.connect(sender); sndChannel.connect(receiver); - byte b[] = "hello".getBytes("UTF-8"); + byte[] b = "hello".getBytes(StandardCharsets.UTF_8); DatagramPacket pkt = new DatagramPacket(b, b.length); sndChannel.socket().send(pkt); ByteBuffer bb = ByteBuffer.allocate(256); rcvChannel.receive(bb); bb.flip(); - CharBuffer cb = Charset.forName("US-ASCII").newDecoder().decode(bb); + CharBuffer cb = StandardCharsets.US_ASCII.newDecoder().decode(bb); assertTrue(cb.toString().startsWith("h"), "Unexpected message content"); // Check that the pkt got set with the target address; // This is legacy behavior - assertEquals(pkt.getSocketAddress(), receiver, + assertEquals(receiver, pkt.getSocketAddress(), "Unexpected address set on packet"); rcvChannel.close(); diff --git a/test/jdk/java/nio/channels/DatagramChannel/SRTest.java b/test/jdk/java/nio/channels/DatagramChannel/SRTest.java index 9a7309cc46e..5ad66e6cdff 100644 --- a/test/jdk/java/nio/channels/DatagramChannel/SRTest.java +++ b/test/jdk/java/nio/channels/DatagramChannel/SRTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,13 +23,19 @@ /* @test * @summary Test DatagramChannel's send and receive methods - * @run testng/othervm/timeout=20 SRTest + * @run junit/othervm SRTest */ -import java.io.*; -import java.net.*; -import java.nio.*; -import java.nio.channels.*; +import java.io.IOException; +import java.io.PrintStream; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.SocketException; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.channels.DatagramChannel; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; import java.util.concurrent.ExecutorService; @@ -37,22 +43,24 @@ import java.util.concurrent.Executors; import java.util.stream.Stream; import static java.nio.charset.StandardCharsets.US_ASCII; -import org.testng.annotations.*; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; public class SRTest { - ExecutorService executorService; + static ExecutorService executorService; static PrintStream log = System.err; static final String DATA_STRING = "hello"; - @BeforeClass - public void beforeClass() { + @BeforeAll + public static void beforeClass() { executorService = Executors.newCachedThreadPool(); } - @AfterClass - public void afterClass() { + @AfterAll + public static void afterClass() { executorService.shutdown(); } diff --git a/test/jdk/java/nio/channels/DatagramChannel/SendExceptions.java b/test/jdk/java/nio/channels/DatagramChannel/SendExceptions.java index 343ab1b8232..94508f9b6e2 100644 --- a/test/jdk/java/nio/channels/DatagramChannel/SendExceptions.java +++ b/test/jdk/java/nio/channels/DatagramChannel/SendExceptions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,27 +25,34 @@ * @bug 4675045 8198753 * @summary Test DatagramChannel send exceptions * @library .. - * @run testng SendExceptions + * @run junit SendExceptions */ -import java.io.*; -import java.net.*; -import java.nio.*; -import java.nio.channels.*; -import org.testng.annotations.AfterTest; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.Test; -import static org.testng.Assert.*; +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.nio.ByteBuffer; +import java.nio.channels.AlreadyConnectedException; +import java.nio.channels.DatagramChannel; +import java.nio.channels.UnresolvedAddressException; +import java.nio.channels.UnsupportedAddressTypeException; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; public class SendExceptions { - static DatagramChannel sndChannel; - static DatagramChannel rcvChannel; - static InetSocketAddress sender; - static InetSocketAddress receiver; - static ByteBuffer buf = ByteBuffer.allocate(17); + private DatagramChannel sndChannel; + private DatagramChannel rcvChannel; + private InetSocketAddress sender; + private InetSocketAddress receiver; + static final ByteBuffer buf = ByteBuffer.allocate(17); - @BeforeTest - public static void setup() throws Exception { + @BeforeEach + public void setup() throws Exception { + buf.rewind(); sndChannel = DatagramChannel.open(); sndChannel.bind(null); InetAddress address = InetAddress.getLocalHost(); @@ -61,29 +68,43 @@ public class SendExceptions { rcvChannel.socket().getLocalPort()); } - @Test(expectedExceptions = UnsupportedAddressTypeException.class) - public static void unsupportedAddressTypeException() throws Exception { - rcvChannel.connect(sender); - sndChannel.send(buf, new SocketAddress() {}); - } - - @Test(expectedExceptions = UnresolvedAddressException.class) - public static void unresolvedAddressException() throws Exception { - String host = TestUtil.UNRESOLVABLE_HOST; - InetSocketAddress unresolvable = new InetSocketAddress (host, 37); - sndChannel.send(buf, unresolvable); - } - - @Test(expectedExceptions = AlreadyConnectedException.class) - public static void alreadyConnectedException() throws Exception { - sndChannel.connect(receiver); - InetSocketAddress random = new InetSocketAddress(0); - sndChannel.send(buf, random); - } - - @AfterTest - public static void cleanup() throws Exception { + @AfterEach + public void cleanup() throws Exception { rcvChannel.close(); sndChannel.close(); } + + @Test + public void unsupportedAddressTypeException() throws IOException { + assertThrows(UnsupportedAddressTypeException.class, () -> { + sndChannel.send(buf, new SocketAddress() {}); + }); + rcvChannel.connect(sender); + assertThrows(UnsupportedAddressTypeException.class, () -> { + sndChannel.send(buf, new SocketAddress() {}); + }); + sndChannel.connect(receiver); + assertThrows(UnsupportedAddressTypeException.class, () -> { + sndChannel.send(buf, new SocketAddress() {}); + }); + } + + @Test + public void unresolvedAddressException() { + String host = TestUtil.UNRESOLVABLE_HOST; + InetSocketAddress unresolvable = new InetSocketAddress (host, 37); + assertThrows(UnresolvedAddressException.class, () -> { + sndChannel.send(buf, unresolvable); + }); + } + + @Test + public void alreadyConnectedException() throws IOException { + sndChannel.connect(receiver); + InetSocketAddress random = new InetSocketAddress(0); + assertThrows(AlreadyConnectedException.class, () -> { + sndChannel.send(buf, random); + }); + } + } diff --git a/test/jdk/java/nio/channels/DatagramChannel/SendPortZero.java b/test/jdk/java/nio/channels/DatagramChannel/SendPortZero.java index 6a8b9f24d41..9733dad83f8 100644 --- a/test/jdk/java/nio/channels/DatagramChannel/SendPortZero.java +++ b/test/jdk/java/nio/channels/DatagramChannel/SendPortZero.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * 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,11 +21,6 @@ * questions. */ -import org.testng.annotations.AfterTest; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - import java.io.IOException; import java.net.InetAddress; import java.net.InetSocketAddress; @@ -39,7 +34,13 @@ import static java.net.StandardProtocolFamily.INET; import static java.net.StandardProtocolFamily.INET6; import static jdk.test.lib.net.IPSupport.hasIPv4; import static jdk.test.lib.net.IPSupport.hasIPv6; -import static org.testng.Assert.assertThrows; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; /* * @test @@ -47,20 +48,20 @@ import static org.testng.Assert.assertThrows; * @library /test/lib * @build jdk.test.lib.net.IPSupport * @summary Check that DatagramChannel throws expected Exception when sending to port 0 - * @run testng/othervm SendPortZero - * @run testng/othervm -Djava.net.preferIPv4Stack=true SendPortZero + * @run junit/othervm SendPortZero + * @run junit/othervm -Djava.net.preferIPv4Stack=true SendPortZero */ public class SendPortZero { - private ByteBuffer buf; - private List channels; - private InetSocketAddress loopbackZeroAddr, wildcardZeroAddr; - private DatagramChannel datagramChannel, datagramChannelIPv4, datagramChannelIPv6; + private static ByteBuffer buf; + private static List channels; + private static InetSocketAddress loopbackZeroAddr, wildcardZeroAddr; + private static DatagramChannel datagramChannel, datagramChannelIPv4, datagramChannelIPv6; private static final Class SE = SocketException.class; - @BeforeTest - public void setUp() throws IOException { + @BeforeAll + public static void setUp() throws IOException { buf = ByteBuffer.wrap("test".getBytes()); wildcardZeroAddr = new InetSocketAddress(0); @@ -69,32 +70,34 @@ public class SendPortZero { channels = new ArrayList<>(); datagramChannel = DatagramChannel.open(); - channels.add(new Object[]{datagramChannel}); + channels.add(datagramChannel); if (hasIPv4()) { datagramChannelIPv4 = DatagramChannel.open(INET); - channels.add(new Object[]{datagramChannelIPv4}); + channels.add(datagramChannelIPv4); } if (hasIPv6()) { datagramChannelIPv6 = DatagramChannel.open(INET6); - channels.add(new Object[]{datagramChannelIPv6}); + channels.add(datagramChannelIPv6); } } - @DataProvider(name = "data") - public Object[][] variants() { - return channels.toArray(Object[][]::new); + @AfterAll + public static void tearDown() throws IOException { + for(DatagramChannel ch : channels) { + ch.close(); + } } - @Test(dataProvider = "data") + public static List channels() { + return channels; + } + + @ParameterizedTest + @MethodSource("channels") public void testChannelSend(DatagramChannel dc) { + assertTrue(dc.isOpen()); assertThrows(SE, () -> dc.send(buf, loopbackZeroAddr)); assertThrows(SE, () -> dc.send(buf, wildcardZeroAddr)); } - @AfterTest - public void tearDown() throws IOException { - for(Object[] ch : channels) { - ((DatagramChannel)ch[0]).close(); - } - } } diff --git a/test/jdk/java/nio/channels/DatagramChannel/SendReceiveMaxSize.java b/test/jdk/java/nio/channels/DatagramChannel/SendReceiveMaxSize.java index a2f5844ce25..cb6e66dd5de 100644 --- a/test/jdk/java/nio/channels/DatagramChannel/SendReceiveMaxSize.java +++ b/test/jdk/java/nio/channels/DatagramChannel/SendReceiveMaxSize.java @@ -29,7 +29,7 @@ * maximum size on macOS. * @library /test/lib * @build jdk.test.lib.net.IPSupport - * @run testng/othervm SendReceiveMaxSize + * @run junit/othervm SendReceiveMaxSize */ /* * @test id=preferIPv4Stack @@ -38,7 +38,7 @@ * maximum size on macOS, using an IPv4 only socket. * @library /test/lib * @build jdk.test.lib.net.IPSupport - * @run testng/othervm -Djava.net.preferIPv4Stack=true SendReceiveMaxSize + * @run junit/othervm -Djava.net.preferIPv4Stack=true SendReceiveMaxSize */ /* * @test id=preferIPv6Loopback @@ -48,7 +48,7 @@ * interface. * @library /test/lib * @build jdk.test.lib.net.IPSupport - * @run testng/othervm -Dtest.preferLoopback=true SendReceiveMaxSize + * @run junit/othervm -Dtest.preferLoopback=true SendReceiveMaxSize */ /* * @test id=preferIPv4Loopback @@ -58,16 +58,13 @@ * loopback interface * @library /test/lib * @build jdk.test.lib.net.IPSupport - * @run testng/othervm -Dtest.preferLoopback=true -Djava.net.preferIPv4Stack=true SendReceiveMaxSize + * @run junit/othervm -Dtest.preferLoopback=true -Djava.net.preferIPv4Stack=true SendReceiveMaxSize */ import jdk.test.lib.RandomFactory; import jdk.test.lib.NetworkConfiguration; import jdk.test.lib.Platform; import jdk.test.lib.net.IPSupport; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import java.io.IOException; import java.net.Inet4Address; @@ -78,6 +75,7 @@ import java.net.SocketAddress; import java.nio.ByteBuffer; import java.nio.channels.DatagramChannel; import java.util.ArrayList; +import java.util.List; import java.util.Random; import java.util.function.Predicate; @@ -88,9 +86,14 @@ import static java.net.StandardSocketOptions.SO_RCVBUF; import static jdk.test.lib.net.IPSupport.hasIPv4; import static jdk.test.lib.net.IPSupport.hasIPv6; import static jdk.test.lib.net.IPSupport.preferIPv4Stack; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertThrows; -import static org.testng.Assert.assertTrue; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; public class SendReceiveMaxSize { private final static Class IOE = IOException.class; @@ -102,14 +105,13 @@ public class SendReceiveMaxSize { } static DatagramChannelSupplier supplier(DatagramChannelSupplier supplier) { return supplier; } - @BeforeTest - public void setUp() { + @BeforeAll + public static void setUp() { IPSupport.throwSkippedExceptionIfNonOperational(); } - @DataProvider - public Object[][] invariants() throws IOException { - var testcases = new ArrayList(); + public static List testCases() throws IOException { + var testcases = new ArrayList(); var nc = NetworkConfiguration.probe(); var ipv4Loopback = (Inet4Address) InetAddress.getByName("127.0.0.1"); var ipv6Loopback = (Inet6Address) InetAddress.getByName("::1"); @@ -119,16 +121,16 @@ public class SendReceiveMaxSize { .filter(Predicate.not(InetAddress::isLoopbackAddress)) .findFirst() .orElse(ipv4Loopback); - testcases.add(new Object[]{ + testcases.add(Arguments.of( supplier(() -> DatagramChannel.open()), IPSupport.getMaxUDPSendBufSizeIPv4(), IPv4Addr - }); - testcases.add(new Object[]{ + )); + testcases.add(Arguments.of( supplier(() -> DatagramChannel.open(INET)), IPSupport.getMaxUDPSendBufSizeIPv4(), IPv4Addr - }); + )); } if (!preferIPv4Stack() && hasIPv6()) { InetAddress IPv6Addr = PREFER_LOOPBACK ? ipv6Loopback @@ -136,21 +138,22 @@ public class SendReceiveMaxSize { .filter(Predicate.not(InetAddress::isLoopbackAddress)) .findFirst() .orElse(ipv6Loopback); - testcases.add(new Object[]{ + testcases.add(Arguments.of( supplier(() -> DatagramChannel.open()), IPSupport.getMaxUDPSendBufSizeIPv6(), IPv6Addr - }); - testcases.add(new Object[]{ + )); + testcases.add(Arguments.of( supplier(() -> DatagramChannel.open(INET6)), IPSupport.getMaxUDPSendBufSizeIPv6(), IPv6Addr - }); + )); } - return testcases.toArray(Object[][]::new); + return testcases; } - @Test(dataProvider = "invariants") + @ParameterizedTest + @MethodSource("testCases") public void testGetOption(DatagramChannelSupplier supplier, int capacity, InetAddress host) throws IOException { if (Platform.isOSX()) { @@ -160,7 +163,8 @@ public class SendReceiveMaxSize { } } - @Test(dataProvider = "invariants") + @ParameterizedTest + @MethodSource("testCases") public void testSendReceiveMaxSize(DatagramChannelSupplier supplier, int capacity, InetAddress host) throws IOException { try (var receiver = DatagramChannel.open()) { @@ -205,8 +209,8 @@ public class SendReceiveMaxSize { // check that data has been fragmented and re-assembled correctly at receiver System.out.println("sendBuf: " + sendBuf); System.out.println("receiveBuf: " + receiveBuf); - assertEquals(sendBuf, receiveBuf); - assertEquals(sendBuf.compareTo(receiveBuf), 0); + assertEquals(receiveBuf, sendBuf); + assertEquals(0, sendBuf.compareTo(receiveBuf)); testData = new byte[capacity - 1]; random.nextBytes(testData); @@ -232,8 +236,8 @@ public class SendReceiveMaxSize { // check that data has been fragmented and re-assembled correctly at receiver System.out.println("sendBuf: " + sendBuf); System.out.println("receiveBuf: " + receiveBuf); - assertEquals(sendBuf, receiveBuf); - assertEquals(sendBuf.compareTo(receiveBuf), 0); + assertEquals(receiveBuf, sendBuf); + assertEquals(0, sendBuf.compareTo(receiveBuf)); var failSendBuf = ByteBuffer.allocate(capacity + 1); assertThrows(IOE, () -> sender.send(failSendBuf, addr)); From 4a9903bae4691947391942064624c44f5d26cab5 Mon Sep 17 00:00:00 2001 From: William Kemper Date: Tue, 24 Mar 2026 18:06:28 +0000 Subject: [PATCH 010/359] 8380431: Shenandoah: Concurrent modification of stack-chunk objects during evacuation Reviewed-by: rkennke --- .../share/gc/shenandoah/shenandoahFullGC.cpp | 5 ++++- .../shenandoah/shenandoahGenerationalHeap.cpp | 17 +++++++++-------- .../share/gc/shenandoah/shenandoahHeap.cpp | 13 +++++++++++-- .../gc/shenandoah/shenandoahMark.inline.hpp | 7 +++---- 4 files changed, 27 insertions(+), 15 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp index 750f7e9122d..21b1fd9e0a8 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp @@ -878,8 +878,11 @@ public: Copy::aligned_conjoint_words(compact_from, compact_to, size); oop new_obj = cast_to_oop(compact_to); - ContinuationGCSupport::relativize_stack_chunk(new_obj); + // Restore the mark word before relativizing the stack chunk. The copy's + // mark word contains the full GC forwarding encoding, which would cause + // is_stackChunk() to read garbage (especially with compact headers). new_obj->init_mark(); + ContinuationGCSupport::relativize_stack_chunk(new_obj); } } }; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp index 27e374a0f85..d5cfa4b7fb9 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp @@ -346,18 +346,19 @@ oop ShenandoahGenerationalHeap::try_evacuate_object(oop p, Thread* thread, uint increase_object_age(copy_val, from_region_age + 1); } + // Relativize stack chunks before publishing the copy. After the forwarding CAS, + // mutators can see the copy and thaw it via the fast path if flags == 0. We must + // relativize derived pointers and set gc_mode before that happens. Skip if the + // copy's mark word is already a forwarding pointer (another thread won the race + // and overwrote the original's header before we copied it). + if (!ShenandoahForwarding::is_forwarded(copy_val)) { + ContinuationGCSupport::relativize_stack_chunk(copy_val); + } + // Try to install the new forwarding pointer. oop result = ShenandoahForwarding::try_update_forwardee(p, copy_val); if (result == copy_val) { // Successfully evacuated. Our copy is now the public one! - - // This is necessary for virtual thread support. This uses the mark word without - // considering that it may now be a forwarding pointer (and could therefore crash). - // Secondarily, we do not want to spend cycles relativizing stack chunks for oops - // that lost the evacuation race (and will therefore not become visible). It is - // safe to do this on the public copy (this is also done during concurrent mark). - ContinuationGCSupport::relativize_stack_chunk(copy_val); - if (ShenandoahEvacTracking) { // Record that the evacuation succeeded evac_tracker()->end_evacuation(thread, size * HeapWordSize, FROM_GENERATION, TO_GENERATION); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index 817f5e8dc47..5bf76505506 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -1353,12 +1353,21 @@ oop ShenandoahHeap::try_evacuate_object(oop p, Thread* thread, ShenandoahHeapReg // Copy the object: Copy::aligned_disjoint_words(cast_from_oop(p), copy, size); - // Try to install the new forwarding pointer. oop copy_val = cast_to_oop(copy); + + // Relativize stack chunks before publishing the copy. After the forwarding CAS, + // mutators can see the copy and thaw it via the fast path if flags == 0. We must + // relativize derived pointers and set gc_mode before that happens. Skip if the + // copy's mark word is already a forwarding pointer (another thread won the race + // and overwrote the original's header before we copied it). + if (!ShenandoahForwarding::is_forwarded(copy_val)) { + ContinuationGCSupport::relativize_stack_chunk(copy_val); + } + + // Try to install the new forwarding pointer. oop result = ShenandoahForwarding::try_update_forwardee(p, copy_val); if (result == copy_val) { // Successfully evacuated. Our copy is now the public one! - ContinuationGCSupport::relativize_stack_chunk(copy_val); shenandoah_assert_correct(nullptr, copy_val); if (ShenandoahEvacTracking) { evac_tracker()->end_evacuation(thread, size * HeapWordSize, from_region->affiliation(), target_gen); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp index ba24e890769..d4699a61166 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp @@ -77,10 +77,9 @@ void ShenandoahMark::do_task(ShenandoahObjToScanQueue* q, T* cl, ShenandoahLiveD if (task->is_not_chunked()) { if (obj->is_instance()) { // Case 1: Normal oop, process as usual. - if (ContinuationGCSupport::relativize_stack_chunk(obj)) { - // Loom doesn't support mixing of weak marking and strong marking of - // stack chunks. - cl->set_weak(false); + if (obj->is_stackChunk()) { + // Loom doesn't support mixing of weak marking and strong marking of stack chunks. + cl->set_weak(false); } obj->oop_iterate(cl); From 6b156ab45b763c7e79e4df15a8cab61949623eea Mon Sep 17 00:00:00 2001 From: Matias Saavedra Silva Date: Tue, 24 Mar 2026 18:23:53 +0000 Subject: [PATCH 011/359] 8357037: Verifier rejects method ending in switch instruction Reviewed-by: dlong, dholmes, coleenp --- src/hotspot/share/interpreter/bytecodes.cpp | 2 +- .../verifier/MethodEndsWithLookupSwitch.jasm | 54 ++++++++++++++++++ .../verifier/MethodEndsWithSwitch.java | 42 ++++++++++++++ .../verifier/MethodEndsWithTableSwitch.jasm | 57 +++++++++++++++++++ 4 files changed, 154 insertions(+), 1 deletion(-) create mode 100644 test/hotspot/jtreg/runtime/verifier/MethodEndsWithLookupSwitch.jasm create mode 100644 test/hotspot/jtreg/runtime/verifier/MethodEndsWithSwitch.java create mode 100644 test/hotspot/jtreg/runtime/verifier/MethodEndsWithTableSwitch.jasm diff --git a/src/hotspot/share/interpreter/bytecodes.cpp b/src/hotspot/share/interpreter/bytecodes.cpp index 1526b3c330e..a7914b6b93a 100644 --- a/src/hotspot/share/interpreter/bytecodes.cpp +++ b/src/hotspot/share/interpreter/bytecodes.cpp @@ -402,7 +402,7 @@ int Bytecodes::special_length_at(Bytecodes::Code code, address bcp, address end) case _fast_binaryswitch: // fall through case _fast_linearswitch: { address aligned_bcp = align_up(bcp + 1, jintSize); - if (end != nullptr && aligned_bcp + 2*jintSize >= end) { + if (end != nullptr && aligned_bcp + 2*jintSize > end) { return -1; // don't read past end of code buffer } // Promote calculation to 64 bits to do range checks, used by the verifier. diff --git a/test/hotspot/jtreg/runtime/verifier/MethodEndsWithLookupSwitch.jasm b/test/hotspot/jtreg/runtime/verifier/MethodEndsWithLookupSwitch.jasm new file mode 100644 index 00000000000..c6043674da9 --- /dev/null +++ b/test/hotspot/jtreg/runtime/verifier/MethodEndsWithLookupSwitch.jasm @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +super public class MethodEndsWithLookupSwitch version 51:0 { + +/* + * See if verifier allows a method to end with a switch instruction. + */ +private Method "foo":"()V" + stack 1 locals 1 +{ + goto L1; +L3: + stack_frame_type same; + return; +L1: + stack_frame_type same; + iconst_0; + lookupswitch { + default: L3 + }; +} + +public Method "":"()V" + stack 2 locals 1 +{ + aload_0; + dup; + invokespecial Method java/lang/Object."":"()V"; + invokespecial Method "foo":"()V"; + return; +} + +} // end Class MethodEndsWithLookupSwitch diff --git a/test/hotspot/jtreg/runtime/verifier/MethodEndsWithSwitch.java b/test/hotspot/jtreg/runtime/verifier/MethodEndsWithSwitch.java new file mode 100644 index 00000000000..9fca02eb5f0 --- /dev/null +++ b/test/hotspot/jtreg/runtime/verifier/MethodEndsWithSwitch.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 Verify that method can end with a switch instruction. + * @compile MethodEndsWithLookupSwitch.jasm MethodEndsWithTableSwitch.jasm + * @run main/othervm MethodEndsWithSwitch + */ + +public class MethodEndsWithSwitch { + + static void test(String testName) throws Exception { + System.out.println("Testing: " + testName); + Class c = Class.forName(testName); + } + + public static void main(String[] args) throws Exception { + test("MethodEndsWithLookupSwitch"); + test("MethodEndsWithTableSwitch"); + } +} diff --git a/test/hotspot/jtreg/runtime/verifier/MethodEndsWithTableSwitch.jasm b/test/hotspot/jtreg/runtime/verifier/MethodEndsWithTableSwitch.jasm new file mode 100644 index 00000000000..97505f48643 --- /dev/null +++ b/test/hotspot/jtreg/runtime/verifier/MethodEndsWithTableSwitch.jasm @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +super public class MethodEndsWithTableSwitch version 51:0 { + +/* + * See if verifier allows a method to end with a switch instruction. + */ +private Method "foo":"()V" + stack 1 locals 1 +{ + goto L1; +L3: + stack_frame_type same; + return; +L1: + stack_frame_type same; + iconst_0; + tableswitch { + 0: L3; + 1: L3; + 2: L3; + default: L3 + }; +} + +public Method "":"()V" + stack 2 locals 1 +{ + aload_0; + dup; + invokespecial Method java/lang/Object."":"()V"; + invokespecial Method "foo":"()V"; + return; +} + +} // end Class MethodEndsWithTableSwitch From 2afd7b8b1459951fd476f0e9b0b8e1845c97890d Mon Sep 17 00:00:00 2001 From: Brent Christian Date: Tue, 24 Mar 2026 18:53:53 +0000 Subject: [PATCH 012/359] 8379672: jdk/internal/misc/VM/RuntimeArguments.java test still fails in Virtual threads mode after JDK-8373718 Reviewed-by: jpai --- test/jdk/jdk/internal/misc/VM/RuntimeArguments.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/jdk/jdk/internal/misc/VM/RuntimeArguments.java b/test/jdk/jdk/internal/misc/VM/RuntimeArguments.java index b86593d84ba..47df5da36f9 100644 --- a/test/jdk/jdk/internal/misc/VM/RuntimeArguments.java +++ b/test/jdk/jdk/internal/misc/VM/RuntimeArguments.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,7 @@ /** * @test * @requires vm.flagless - * @requires test.thread.factory == null + * @requires test.thread.factory == "" * @library /test/lib * @modules java.base/jdk.internal.misc * jdk.zipfs From 18fdbd2404b3b6b23ba8457e4c42674ffc3fffa4 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Tue, 24 Mar 2026 20:32:31 +0000 Subject: [PATCH 013/359] 8314258: Add integer_cast for checking conversions don't change the value Reviewed-by: azafari, stefank, lkorinth --- src/hotspot/share/utilities/integerCast.hpp | 157 ++++++++++ .../gtest/utilities/test_integerCast.cpp | 287 ++++++++++++++++++ 2 files changed, 444 insertions(+) create mode 100644 src/hotspot/share/utilities/integerCast.hpp create mode 100644 test/hotspot/gtest/utilities/test_integerCast.cpp diff --git a/src/hotspot/share/utilities/integerCast.hpp b/src/hotspot/share/utilities/integerCast.hpp new file mode 100644 index 00000000000..0715cab18d5 --- /dev/null +++ b/src/hotspot/share/utilities/integerCast.hpp @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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_UTILITIES_INTEGERCAST_HPP +#define SHARE_UTILITIES_INTEGERCAST_HPP + +#include "cppstdlib/limits.hpp" +#include "cppstdlib/type_traits.hpp" +#include "metaprogramming/enableIf.hpp" +#include "utilities/debug.hpp" +#include "utilities/macros.hpp" + +#include + +// Tests whether all values for the From type are within the range of values +// for the To Type. From and To must be integral types. This is used by +// integer_cast to test for tautological conversions. +template), + ENABLE_IF(std::is_integral_v)> +constexpr bool is_always_integer_convertible() { + if constexpr (std::is_signed_v == std::is_signed_v) { + // signed => signed or unsigned => unsigned. + return sizeof(To) >= sizeof(From); + } else if constexpr (std::is_signed_v) { + // signed => unsigned is never tautological, because of negative values. + return false; + } else { + // unsigned => signed. + return sizeof(To) > sizeof(From); + } +} + +// Tests whether the value of from is within the range of values for the To +// type. To and From must be integral types. This is used by integer_cast +// to test whether the conversion should be performed. +template), + ENABLE_IF(std::is_integral_v)> +constexpr bool is_integer_convertible(From from) { + if constexpr (is_always_integer_convertible()) { + // This clause simplifies direct calls and the implementation below. It + // isn't needed by integer_cast, where a tautological call is discarded. + return true; + } else if constexpr (std::is_unsigned_v) { + // unsigned => signed or unsigned => unsigned. + // Convert To::max to corresponding unsigned for compare. + using U = std::make_unsigned_t; + return from <= static_cast(std::numeric_limits::max()); + } else if constexpr (std::is_signed_v) { + // signed => signed. + return ((std::numeric_limits::min() <= from) && + (from <= std::numeric_limits::max())); + } else { + // signed => unsigned. Convert from to corresponding unsigned for compare. + using U = std::make_unsigned_t; + return (0 <= from) && (static_cast(from) <= std::numeric_limits::max()); + } +} + +// Convert the from value to the To type, after a debug-only check that the +// value of from is within the range of values for the To type. To and From +// must be integral types. +// +// permit_tautology determines the behavior when a conversion will always +// succeed because the range of values for the From type is enclosed by the +// range of values for the To type (is_always_integer_convertible() +// is true). If true, the conversion will be performed as requested. If +// false, a compile-time error is produced. The default is false for 64bit +// platforms, true for 32bit platforms. See integer_cast_permit_tautology as +// the preferred way to override the default and always provide a true value. +// +// Unnecessary integer_casts make code harder to understand. Hence the +// compile-time failure for tautological conversions, to alert that a code +// change is making a integer_cast unnecessary. This can be suppressed on a +// per-call basis, because there are cases where a conversion might only +// sometimes be tautological. For example, the types involved may vary by +// platform. Another case is if the operation is in a template with dependent +// types, with the operation only being tautological for some instantiations. +// Suppressing the tautology check is an alternative to possibly complex +// metaprogramming to only perform the integer_cast when necessary. +// +// Despite that, for 32bit platforms the default is to not reject unnecessary +// integer_casts. This is because 64bit platforms are the primary target, and +// are likely to require conversions in some places. However, some of those +// conversions will be tautological on 32bit platforms, such as size_t => uint. +template), + ENABLE_IF(std::is_integral_v)> +constexpr To integer_cast(From from) { + if constexpr (is_always_integer_convertible()) { + static_assert(permit_tautology, "tautological integer_cast"); + } else { +#ifdef ASSERT + if (!is_integer_convertible(from)) { + if constexpr (std::is_signed_v) { + fatal("integer_cast failed: %jd", static_cast(from)); + } else { + fatal("integer_cast failed: %ju", static_cast(from)); + } + } +#endif // ASSERT + } + return static_cast(from); +} + +// Equivalent to "integer_cast(from)", disabling the compile-time +// check for tautological casts. Using this function is prefered to direct +// use of the permit_tautology template parameter for integer_cast, unless the +// choice is computed. +template), + ENABLE_IF(std::is_integral_v)> +constexpr To integer_cast_permit_tautology(From from) { + return integer_cast(from); +} + +// Convert an enumerator to an integral value via static_cast, after a +// debug-only check that the value is within the range for the destination +// type. This is mostly for compatibility with old code. Class scoped enums +// were used to work around ancient compilers that didn't implement class +// scoped static integral constants properly, and HotSpot code still has many +// examples of this. For others it might be sufficient to provide an explicit +// underlying type and either permit implicit conversions or use +// PrimitiveConversion::cast. +template), + ENABLE_IF(std::is_enum_v)> +constexpr To integer_cast(From from) { + using U = std::underlying_type_t; + return integer_cast(static_cast(from)); +} + +#endif // SHARE_UTILITIES_INTEGERCAST_HPP diff --git a/test/hotspot/gtest/utilities/test_integerCast.cpp b/test/hotspot/gtest/utilities/test_integerCast.cpp new file mode 100644 index 00000000000..87d35384c2c --- /dev/null +++ b/test/hotspot/gtest/utilities/test_integerCast.cpp @@ -0,0 +1,287 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 "cppstdlib/limits.hpp" +#include "cppstdlib/type_traits.hpp" +#include "utilities/integerCast.hpp" +#include "utilities/globalDefinitions.hpp" + +#include "unittest.hpp" + +// Enable gcc warnings to verify we don't get any of these. +// Eventually we plan to have these globally enabled, but not there yet. +#ifdef __GNUC__ +#pragma GCC diagnostic warning "-Wconversion" +#pragma GCC diagnostic warning "-Wsign-conversion" +#endif + +// Tautology tests for signed -> signed types. +static_assert(is_always_integer_convertible()); +static_assert(!is_always_integer_convertible()); +static_assert(is_always_integer_convertible()); +static_assert(is_always_integer_convertible()); + +// Tautology tests for unsigned -> unsigned types. +static_assert(is_always_integer_convertible()); +static_assert(!is_always_integer_convertible()); +static_assert(is_always_integer_convertible()); +static_assert(is_always_integer_convertible()); + +// Tautology tests for signed -> unsigned types. +static_assert(!is_always_integer_convertible()); +static_assert(!is_always_integer_convertible()); +static_assert(!is_always_integer_convertible()); +static_assert(!is_always_integer_convertible()); + +// Tautology tests for unsigned -> signed types. +static_assert(!is_always_integer_convertible()); +static_assert(!is_always_integer_convertible()); +static_assert(is_always_integer_convertible()); +static_assert(!is_always_integer_convertible()); + +template +struct TestIntegerCastValues { + static TestIntegerCastValues values; + + T minus_one = static_cast(-1); + T zero = static_cast(0); + T one = static_cast(1); + T min = std::numeric_limits::min(); + T max = std::numeric_limits::max(); +}; + +template +TestIntegerCastValues TestIntegerCastValues::values{}; + +template +struct TestIntegerCastPairedValues { + static TestIntegerCastPairedValues values; + + From min = static_cast(std::numeric_limits::min()); + From max = static_cast(std::numeric_limits::max()); +}; + +template +TestIntegerCastPairedValues +TestIntegerCastPairedValues::values{}; + +////////////////////////////////////////////////////////////////////////////// +// Integer casts between integral types of different sizes. +// Test narrowing to verify checking. +// Test widening to verify no compiler warnings for tautological comparisons. + +template +struct TestIntegerCastIntegerValues { + static TestIntegerCastIntegerValues values; + + TestIntegerCastValues to; + TestIntegerCastValues from; + TestIntegerCastPairedValues to_as_from; +}; + +template +TestIntegerCastIntegerValues +TestIntegerCastIntegerValues::values{}; + +template +static void good_integer_conversion(From from) { + ASSERT_TRUE(is_integer_convertible(from)); + EXPECT_EQ(static_cast(from), integer_cast(from)); +} + +template +static void bad_integer_conversion(From from) { + EXPECT_FALSE(is_integer_convertible(from)); +} + +// signed -> signed is tautological unless From is wider than To. + +TEST(TestIntegerCast, wide_signed_to_narrow_signed_integers) { + using To = int32_t; + using From = int64_t; + using Values = TestIntegerCastIntegerValues; + const Values& values = Values::values; + + good_integer_conversion(values.from.minus_one); + good_integer_conversion(values.from.zero); + good_integer_conversion(values.from.one); + bad_integer_conversion(values.from.min); + bad_integer_conversion(values.from.max); + good_integer_conversion(values.to_as_from.min); + good_integer_conversion(values.to_as_from.max); + bad_integer_conversion(values.to_as_from.min - 1); + bad_integer_conversion(values.to_as_from.max + 1); +} + +// unsigned -> unsigned is tautological unless From is wider than To. + +TEST(TestIntegerCast, wide_unsigned_to_narrow_unsigned_integers) { + using To = uint32_t; + using From = uint64_t; + using Values = TestIntegerCastIntegerValues; + const Values& values = Values::values; + + bad_integer_conversion(values.from.minus_one); + good_integer_conversion(values.from.zero); + good_integer_conversion(values.from.one); + good_integer_conversion(values.from.min); + bad_integer_conversion(values.from.max); + good_integer_conversion(values.to_as_from.min); + good_integer_conversion(values.to_as_from.min); + bad_integer_conversion(values.to_as_from.min - 1); + bad_integer_conversion(values.to_as_from.max + 1); +} + +TEST(TestIntegerCast, unsigned_to_signed_same_size_integers) { + using To = int32_t; + using From = uint32_t; + using Values = TestIntegerCastIntegerValues; + const Values& values = Values::values; + + good_integer_conversion(values.from.zero); + good_integer_conversion(values.from.one); + good_integer_conversion(values.from.min); + bad_integer_conversion(values.from.max); + bad_integer_conversion(values.to_as_from.min); + good_integer_conversion(values.to_as_from.max); + bad_integer_conversion(values.to_as_from.max + 1); +} + +// Narrow unsigned to wide signed is tautological. + +TEST(TestIntegerCast, wide_unsigned_to_narrow_signed_integers) { + using To = int32_t; + using From = uint64_t; + using Values = TestIntegerCastIntegerValues; + const Values& values = Values::values; + + bad_integer_conversion(values.from.minus_one); + good_integer_conversion(values.from.zero); + good_integer_conversion(values.from.one); + good_integer_conversion(values.from.min); + bad_integer_conversion(values.from.max); + bad_integer_conversion(values.to_as_from.min); + good_integer_conversion(values.to_as_from.max); + bad_integer_conversion(values.to_as_from.min - 1); + bad_integer_conversion(values.to_as_from.max + 1); +} + +TEST(TestIntegerCast, signed_to_unsigned_same_size_integers) { + using To = uint32_t; + using From = int32_t; + using Values = TestIntegerCastIntegerValues; + const Values& values = Values::values; + + bad_integer_conversion(values.from.minus_one); + good_integer_conversion(values.from.zero); + good_integer_conversion(values.from.one); + bad_integer_conversion(values.from.min); + good_integer_conversion(values.from.max); + good_integer_conversion(values.to_as_from.min); + bad_integer_conversion(values.to_as_from.max); +} + +TEST(TestIntegerCast, narrow_signed_to_wide_unsigned_integers) { + using To = uint64_t; + using From = int32_t; + using Values = TestIntegerCastIntegerValues; + const Values& values = Values::values; + + bad_integer_conversion(values.from.minus_one); + good_integer_conversion(values.from.zero); + good_integer_conversion(values.from.one); + bad_integer_conversion(values.from.min); + good_integer_conversion(values.from.max); + good_integer_conversion(values.to_as_from.min); + bad_integer_conversion(values.to_as_from.max); +} + +TEST(TestIntegerCast, wide_signed_to_narrow_unsigned_integers) { + using To = uint32_t; + using From = int64_t; + using Values = TestIntegerCastIntegerValues; + const Values& values = Values::values; + + bad_integer_conversion(values.from.minus_one); + good_integer_conversion(values.from.zero); + good_integer_conversion(values.from.one); + bad_integer_conversion(values.from.min); + bad_integer_conversion(values.from.max); + good_integer_conversion(values.to_as_from.min); + good_integer_conversion(values.to_as_from.max); +} + +TEST(TestIntegerCast, permit_tautology) { + using From = uint32_t; + using To = int64_t; + using Values = TestIntegerCastIntegerValues; + const Values& values = Values::values; + + static_assert(is_always_integer_convertible()); + EXPECT_EQ(static_cast(values.from.min), + (integer_cast(values.from.min))); + EXPECT_EQ(static_cast(values.from.min), + (integer_cast_permit_tautology(values.from.min))); + EXPECT_EQ(static_cast(values.from.max), + (integer_cast(values.from.max))); + EXPECT_EQ(static_cast(values.from.max), + integer_cast_permit_tautology(values.from.max)); +} + +TEST(TestIntegerCast, check_constexpr) { + using From = int64_t; + using To = int32_t; + constexpr From value = std::numeric_limits::max(); + constexpr To converted = integer_cast(value); + EXPECT_EQ(static_cast(value), converted); +} + +#ifdef ASSERT + +TEST_VM_ASSERT(TestIntegerCast, cast_failure_signed_range) { + using From = int64_t; + using To = int32_t; + using Values = TestIntegerCastIntegerValues; + const Values& values = Values::values; + + From value = values.from.max; + To expected = static_cast(value); // Narrowing conversion. + EXPECT_FALSE(is_integer_convertible(value)); + // Should assert. If it doesn't, then shuld be equal, so fail. + EXPECT_NE(static_cast(value), integer_cast(value)); +} + +TEST_VM_ASSERT(TestIntegerCast, cast_failure_unsigned_range) { + using From = uint64_t; + using To = uint32_t; + using Values = TestIntegerCastIntegerValues; + const Values& values = Values::values; + + From value = values.from.max; + To expected = static_cast(value); // Narrowing conversion. + EXPECT_FALSE(is_integer_convertible(value)); + // Should assert. If it doesn't, then should be equal, so fail. + EXPECT_NE(static_cast(value), integer_cast(value)); +} + +#endif // ASSERT From 4b38e7bcd3989a5e33d2b38e3c7904a5d3be7e45 Mon Sep 17 00:00:00 2001 From: Naoto Sato Date: Tue, 24 Mar 2026 21:35:17 +0000 Subject: [PATCH 014/359] 8346133: Refactor java.time.ZoneOffset caching Reviewed-by: jlu, liach, rriggs --- .../share/classes/java/time/ZoneOffset.java | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/java.base/share/classes/java/time/ZoneOffset.java b/src/java.base/share/classes/java/time/ZoneOffset.java index 2a45e7cbf82..3bcb75db3e4 100644 --- a/src/java.base/share/classes/java/time/ZoneOffset.java +++ b/src/java.base/share/classes/java/time/ZoneOffset.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2025, Alibaba Group Holding Limited. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -87,9 +87,9 @@ import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicReferenceArray; +import java.util.function.Supplier; import jdk.internal.util.DecimalDigits; -import jdk.internal.vm.annotation.Stable; /** * A time-zone offset from Greenwich/UTC, such as {@code +02:00}. @@ -178,8 +178,13 @@ public final class ZoneOffset /** * The zone rules for an offset will always return this offset. Cache it for efficiency. */ - @Stable - private transient ZoneRules rules; + private final transient LazyConstant rules = + LazyConstant.of(new Supplier() { + @Override + public ZoneRules get() { + return ZoneRules.of(ZoneOffset.this); + } + }); //----------------------------------------------------------------------- /** @@ -521,11 +526,7 @@ public final class ZoneOffset */ @Override public ZoneRules getRules() { - ZoneRules rules = this.rules; - if (rules == null) { - rules = this.rules = ZoneRules.of(this); - } - return rules; + return rules.get(); } @Override From 4e7901576851ebe22b40349bf0e155b39ca6c34a Mon Sep 17 00:00:00 2001 From: William Kemper Date: Tue, 24 Mar 2026 23:52:27 +0000 Subject: [PATCH 015/359] 8380846: GenShen: Remove the experimental option to disable adaptive tenuring Reviewed-by: kdnilsen --- .../gc/shenandoah/shenandoahAgeCensus.cpp | 28 ++++--------------- .../gc/shenandoah/shenandoahAgeCensus.hpp | 1 - .../gc/shenandoah/shenandoahGeneration.cpp | 2 +- .../gc/shenandoah/shenandoahMark.inline.hpp | 12 ++++---- .../gc/shenandoah/shenandoah_globals.hpp | 6 +--- 5 files changed, 12 insertions(+), 37 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.cpp b/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.cpp index 86ff6f22c72..71fd6e37614 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.cpp @@ -57,21 +57,13 @@ ShenandoahAgeCensus::ShenandoahAgeCensus(uint max_workers) // Sentinel value _tenuring_threshold[i] = MAX_COHORTS; } - if (ShenandoahGenerationalAdaptiveTenuring) { - _local_age_tables = NEW_C_HEAP_ARRAY(AgeTable*, _max_workers, mtGC); - CENSUS_NOISE(_local_noise = NEW_C_HEAP_ARRAY(ShenandoahNoiseStats, max_workers, mtGC);) - for (uint i = 0; i < _max_workers; i++) { - _local_age_tables[i] = new AgeTable(false); - CENSUS_NOISE(_local_noise[i].clear();) - } - } else { - _local_age_tables = nullptr; + _local_age_tables = NEW_C_HEAP_ARRAY(AgeTable*, _max_workers, mtGC); + CENSUS_NOISE(_local_noise = NEW_C_HEAP_ARRAY(ShenandoahNoiseStats, max_workers, mtGC);) + for (uint i = 0; i < _max_workers; i++) { + _local_age_tables[i] = new AgeTable(false); + CENSUS_NOISE(_local_noise[i].clear();) } _epoch = MAX_SNAPSHOTS - 1; // see prepare_for_census_update() - - if (!ShenandoahGenerationalAdaptiveTenuring) { - _tenuring_threshold[_epoch] = InitialTenuringThreshold; - } } ShenandoahAgeCensus::~ShenandoahAgeCensus() { @@ -154,7 +146,6 @@ void ShenandoahAgeCensus::prepare_for_census_update() { // and compute the new tenuring threshold. void ShenandoahAgeCensus::update_census(size_t age0_pop) { prepare_for_census_update(); - assert(ShenandoahGenerationalAdaptiveTenuring, "Only update census when adaptive tenuring is enabled"); assert(_global_age_tables[_epoch]->is_clear(), "Dirty decks"); CENSUS_NOISE(assert(_global_noise[_epoch].is_clear(), "Dirty decks");) @@ -195,10 +186,6 @@ void ShenandoahAgeCensus::reset_global() { // Reset the local age tables, clearing any partial census. void ShenandoahAgeCensus::reset_local() { - if (!ShenandoahGenerationalAdaptiveTenuring) { - assert(_local_age_tables == nullptr, "Error"); - return; - } for (uint i = 0; i < _max_workers; i++) { _local_age_tables[i]->clear(); CENSUS_NOISE(_local_noise[i].clear();) @@ -221,10 +208,6 @@ bool ShenandoahAgeCensus::is_clear_global() { // Is local census information clear? bool ShenandoahAgeCensus::is_clear_local() { - if (!ShenandoahGenerationalAdaptiveTenuring) { - assert(_local_age_tables == nullptr, "Error"); - return true; - } for (uint i = 0; i < _max_workers; i++) { bool clear = _local_age_tables[i]->is_clear(); CENSUS_NOISE(clear |= _local_noise[i].is_clear();) @@ -258,7 +241,6 @@ void ShenandoahAgeCensus::update_total() { #endif // !PRODUCT void ShenandoahAgeCensus::update_tenuring_threshold() { - assert(ShenandoahGenerationalAdaptiveTenuring, "Only update when adaptive tenuring is enabled"); uint tt = compute_tenuring_threshold(); assert(tt <= MAX_COHORTS, "Out of bounds"); _tenuring_threshold[_epoch] = tt; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.hpp b/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.hpp index 39ea4ee9002..5ccd0b21398 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.hpp @@ -173,7 +173,6 @@ class ShenandoahAgeCensus: public CHeapObj { ~ShenandoahAgeCensus(); // Return the local age table (population vector) for worker_id. - // Only used in the case of ShenandoahGenerationalAdaptiveTenuring AgeTable* get_local_age_table(uint worker_id) const { return _local_age_tables[worker_id]; } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp index 750389ae6c3..f3c05049079 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp @@ -272,7 +272,7 @@ void ShenandoahGeneration::prepare_regions_and_collection_set(bool concurrent) { } // Tally the census counts and compute the adaptive tenuring threshold - if (is_generational && ShenandoahGenerationalAdaptiveTenuring) { + if (is_generational) { // Objects above TAMS weren't included in the age census. Since they were all // allocated in this cycle they belong in the age 0 cohort. We walk over all // young regions and sum the volume of objects between TAMS and top. diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp index d4699a61166..0d42b95164b 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp @@ -117,13 +117,11 @@ inline void ShenandoahMark::count_liveness(ShenandoahLiveData* live_data, oop ob // Age census for objects in the young generation if (GENERATION == YOUNG || (GENERATION == GLOBAL && region->is_young())) { assert(heap->mode()->is_generational(), "Only if generational"); - if (ShenandoahGenerationalAdaptiveTenuring) { - assert(region->is_young(), "Only for young objects"); - uint age = ShenandoahHeap::get_object_age(obj); - ShenandoahAgeCensus* const census = ShenandoahGenerationalHeap::heap()->age_census(); - CENSUS_NOISE(census->add(age, region->age(), region->youth(), size, worker_id);) - NO_CENSUS_NOISE(census->add(age, region->age(), size, worker_id);) - } + assert(region->is_young(), "Only for young objects"); + const uint age = ShenandoahHeap::get_object_age(obj); + ShenandoahAgeCensus* const census = ShenandoahGenerationalHeap::heap()->age_census(); + CENSUS_NOISE(census->add(age, region->age(), region->youth(), size, worker_id);) + NO_CENSUS_NOISE(census->add(age, region->age(), size, worker_id);) } if (!region->is_humongous_start()) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp b/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp index d3e9a1f9fae..bbfa19934d9 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp @@ -152,9 +152,6 @@ "evvort even if the usage of old generation is below " \ "ShenandoahIgnoreOldGrowthBelowPercentage.") \ \ - product(bool, ShenandoahGenerationalAdaptiveTenuring, true, EXPERIMENTAL, \ - "(Generational mode only) Dynamically adapt tenuring age.") \ - \ product(bool, ShenandoahGenerationalCensusIgnoreOlderCohorts, true, \ EXPERIMENTAL,\ "(Generational mode only) Ignore mortality rates older than the " \ @@ -179,8 +176,7 @@ "(Generational mode only) Cohort mortality rates below this " \ "value will be treated as indicative of longevity, leading to " \ "tenuring. A lower value delays tenuring, a higher value hastens "\ - "it. Used only when ShenandoahGenerationalhenAdaptiveTenuring is "\ - "enabled.") \ + "it.") \ range(0.001,0.999) \ \ product(size_t, ShenandoahGenerationalTenuringCohortPopulationThreshold, \ From e8ce930e28c26b12fb0eafab201ccedaa2650e5d Mon Sep 17 00:00:00 2001 From: William Kemper Date: Wed, 25 Mar 2026 00:23:41 +0000 Subject: [PATCH 016/359] 8379020: GenShen: Promote all objects when whitebox full GC is requested Reviewed-by: ysr, kdnilsen --- .../gc/shenandoah/shenandoahAgeCensus.hpp | 28 +++++++++++++++++++ .../shenandoahGenerationalControlThread.cpp | 7 +++++ 2 files changed, 35 insertions(+) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.hpp b/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.hpp index 5ccd0b21398..9c5baaedcd6 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.hpp @@ -97,6 +97,8 @@ struct ShenandoahNoiseStats { // once the per-worker data is consolidated into the appropriate population vector // per minor collection. The _local_age_table is thus C x N, for N GC workers. class ShenandoahAgeCensus: public CHeapObj { + friend class ShenandoahTenuringOverride; + AgeTable** _global_age_tables; // Global age tables used for adapting tenuring threshold, one per snapshot AgeTable** _local_age_tables; // Local scratch age tables to track object ages, one per worker @@ -148,6 +150,10 @@ class ShenandoahAgeCensus: public CHeapObj { return _tenuring_threshold[prev]; } + // Override the tenuring threshold for the current epoch. This is used to + // cause everything to be promoted for a whitebox full gc request. + void set_tenuring_threshold(uint threshold) { _tenuring_threshold[_epoch] = threshold; } + #ifndef PRODUCT // Return the sum of size of objects of all ages recorded in the // census at snapshot indexed by snap. @@ -232,4 +238,26 @@ class ShenandoahAgeCensus: public CHeapObj { void print(); }; +// RAII object that temporarily overrides the tenuring threshold for the +// duration of a scope, restoring the original value on destruction. +// Used to force promotion of all young objects during whitebox full GCs. +class ShenandoahTenuringOverride : public StackObj { + ShenandoahAgeCensus* _census; + uint _saved_threshold; + bool _active; +public: + ShenandoahTenuringOverride(bool active, ShenandoahAgeCensus* census) : + _census(census), _saved_threshold(0), _active(active) { + if (_active) { + _saved_threshold = _census->tenuring_threshold(); + _census->set_tenuring_threshold(0); + } + } + ~ShenandoahTenuringOverride() { + if (_active) { + _census->set_tenuring_threshold(_saved_threshold); + } + } +}; + #endif // SHARE_GC_SHENANDOAH_SHENANDOAHAGECENSUS_HPP diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp index 1edff443ded..67cc4d2f703 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp @@ -24,6 +24,7 @@ * */ +#include "gc/shenandoah/shenandoahAgeCensus.hpp" #include "gc/shenandoah/shenandoahAsserts.hpp" #include "gc/shenandoah/shenandoahCollectorPolicy.hpp" #include "gc/shenandoah/shenandoahConcurrentGC.hpp" @@ -271,6 +272,12 @@ void ShenandoahGenerationalControlThread::run_gc_cycle(const ShenandoahGCRequest // Cannot uncommit bitmap slices during concurrent reset ShenandoahNoUncommitMark forbid_region_uncommit(_heap); + // When a whitebox full GC is requested, set the tenuring threshold to zero + // so that all young objects are promoted to old. This ensures that tests + // using WB.fullGC() to promote objects to old gen will not loop forever. + ShenandoahTenuringOverride tenuring_override(request.cause == GCCause::_wb_full_gc, + _heap->age_census()); + _heap->print_before_gc(); switch (gc_mode()) { case concurrent_normal: { From 56885958c2207eabd24c079a8f4a69e2aad066a5 Mon Sep 17 00:00:00 2001 From: Kelvin Nilsen Date: Wed, 25 Mar 2026 00:40:37 +0000 Subject: [PATCH 017/359] 8380408: GenShen: Fix regression with vmTestbase/gc/memory/Churn/Churn2/TestDescription.java Reviewed-by: wkemper --- .../heuristics/shenandoahGenerationalHeuristics.cpp | 4 ++++ .../heuristics/shenandoahGenerationalHeuristics.hpp | 2 +- .../gc/shenandoah/heuristics/shenandoahOldHeuristics.cpp | 6 ++++-- src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp | 6 ++++-- src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp | 6 ------ src/hotspot/share/gc/shenandoah/shenandoahGeneration.hpp | 3 +-- .../share/gc/shenandoah/shenandoahYoungGeneration.cpp | 8 ++++++++ .../share/gc/shenandoah/shenandoahYoungGeneration.hpp | 2 ++ 8 files changed, 24 insertions(+), 13 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp index 08d628e67ff..d5622ed5d79 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp @@ -498,7 +498,11 @@ void ShenandoahGenerationalHeuristics::adjust_evacuation_budgets(ShenandoahHeap* size_t young_evacuated = collection_set->get_live_bytes_in_untenurable_regions(); size_t young_evacuated_reserve_used = (size_t) (ShenandoahEvacWaste * double(young_evacuated)); + // In top_off_collection_set(), we shrunk planned future reserve by _add_regions_to_old * region_size_bytes, but we + // didn't shrink available. The current reserve is not affected by the planned future reserve. Current available is + // larger than planned available by the planned adjustment amount. size_t total_young_available = young_generation->available_with_reserve() - _add_regions_to_old * region_size_bytes; + assert(young_evacuated_reserve_used <= total_young_available, "Cannot evacuate (%zu) more than is available in young (%zu)", young_evacuated_reserve_used, total_young_available); young_generation->set_evacuation_reserve(young_evacuated_reserve_used); diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.hpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.hpp index c418e8c24ec..d6551cffb73 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.hpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.hpp @@ -76,7 +76,7 @@ private: // Filter and sort remaining regions before adding to collection set. void filter_regions(ShenandoahCollectionSet* collection_set); - // Adjust evacuation budgets after choosing collection set. The argument regions_to_xfer + // Adjust evacuation budgets after choosing collection set. On entry, the instance variable _regions_to_xfer // represents regions to be transferred to old based on decisions made in top_off_collection_set() void adjust_evacuation_budgets(ShenandoahHeap* const heap, ShenandoahCollectionSet* const collection_set); diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahOldHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahOldHeuristics.cpp index 4f71562f4f6..33c91e27be5 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahOldHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahOldHeuristics.cpp @@ -369,7 +369,6 @@ bool ShenandoahOldHeuristics::top_off_collection_set(ShenandoahCollectionSet* co assert(consumed_from_young_cset <= max_young_cset, "sanity"); assert(max_young_cset <= young_unaffiliated_regions * region_size_bytes, "sanity"); - size_t regions_for_old_expansion; if (consumed_from_young_cset < max_young_cset) { size_t excess_young_reserves = max_young_cset - consumed_from_young_cset; @@ -392,7 +391,10 @@ bool ShenandoahOldHeuristics::top_off_collection_set(ShenandoahCollectionSet* co _unspent_unfragmented_old_budget += supplement_without_waste; _old_generation->augment_evacuation_reserve(budget_supplement); young_generation->set_evacuation_reserve(max_young_cset - budget_supplement); - + assert(young_generation->get_evacuation_reserve() >= + collection_set->get_live_bytes_in_untenurable_regions() * ShenandoahEvacWaste, + "adjusted evac reserve (%zu) must be large enough for planned evacuation (%zu)", + young_generation->get_evacuation_reserve(), collection_set->get_live_bytes_in_untenurable_regions()); return add_old_regions_to_cset(collection_set); } else { add_regions_to_old = 0; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp index 2df06432bd2..eeff0fde87c 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp @@ -857,14 +857,16 @@ public: ShenandoahRebuildLocker locker(rebuild_lock()); return _partitions.available_in_locked_for_rebuild(ShenandoahFreeSetPartitionId::Mutator); } - inline size_t available_holding_lock() const - { return _partitions.available_in(ShenandoahFreeSetPartitionId::Mutator); } // Use this version of available() if the heap lock is held. inline size_t available_locked() const { return _partitions.available_in(ShenandoahFreeSetPartitionId::Mutator); } + inline size_t collector_available_locked() const { + return _partitions.available_in(ShenandoahFreeSetPartitionId::Collector); + } + inline size_t total_humongous_waste() const { return _total_humongous_waste; } inline size_t humongous_waste_in_mutator() const { return _partitions.humongous_waste(ShenandoahFreeSetPartitionId::Mutator); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp index f3c05049079..3d592e9f9be 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp @@ -423,12 +423,6 @@ size_t ShenandoahGeneration::available() const { return result; } -// For ShenandoahYoungGeneration, Include the young available that may have been reserved for the Collector. -size_t ShenandoahGeneration::available_with_reserve() const { - size_t result = available(max_capacity()); - return result; -} - size_t ShenandoahGeneration::soft_mutator_available() const { size_t result = available(ShenandoahHeap::heap()->soft_max_capacity() * (100.0 - ShenandoahEvacReserve) / 100); return result; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.hpp b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.hpp index 1a549be8988..6f32d101152 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.hpp @@ -63,7 +63,7 @@ private: // Return available assuming that we can allocate no more than capacity bytes within this generation. size_t available(size_t capacity) const; - public: +public: ShenandoahGeneration(ShenandoahGenerationType type, uint max_workers); ~ShenandoahGeneration(); @@ -96,7 +96,6 @@ private: virtual size_t max_capacity() const override = 0; size_t available() const override; - size_t available_with_reserve() const; // Returns the memory available based on the _soft_ max heap capacity (soft_max_heap - used). // The soft max heap size may be adjusted lower than the max heap size to cause the trigger diff --git a/src/hotspot/share/gc/shenandoah/shenandoahYoungGeneration.cpp b/src/hotspot/share/gc/shenandoah/shenandoahYoungGeneration.cpp index f00ce16136f..7a76bc50078 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahYoungGeneration.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahYoungGeneration.cpp @@ -131,6 +131,14 @@ size_t ShenandoahYoungGeneration::free_unaffiliated_regions() const { return _free_set->young_unaffiliated_regions(); } +size_t ShenandoahYoungGeneration::available_with_reserve() const { + shenandoah_assert_heaplocked(); + ShenandoahFreeSet* free_set = ShenandoahHeap::heap()->free_set(); + size_t mutator_available = free_set->available_locked(); + size_t collector_available = free_set->collector_available_locked(); + return mutator_available + collector_available; +} + size_t ShenandoahYoungGeneration::available() const { // The collector reserve may eat into what the mutator is allowed to use. Make sure we are looking // at what is available to the mutator when reporting how much memory is available. diff --git a/src/hotspot/share/gc/shenandoah/shenandoahYoungGeneration.hpp b/src/hotspot/share/gc/shenandoah/shenandoahYoungGeneration.hpp index 930c5ff1747..c3b6944ec80 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahYoungGeneration.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahYoungGeneration.hpp @@ -82,6 +82,8 @@ public: size_t get_affiliated_region_count() const override; size_t max_capacity() const override; + // Return sum of bytes available to mutator and to Collector, assuming heap lock is held. + size_t available_with_reserve() const; size_t available() const override; size_t soft_mutator_available() const override; From 4408e1c9279184fa0558e41d77f5683f61e5b314 Mon Sep 17 00:00:00 2001 From: Dingli Zhang Date: Wed, 25 Mar 2026 02:16:59 +0000 Subject: [PATCH 018/359] 8380580: Enable TestCombineAddPWithConstantOffsets.java IR tests for RISC-V Reviewed-by: fyang --- .../c2/irTests/igvn/TestCombineAddPWithConstantOffsets.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/hotspot/jtreg/compiler/c2/irTests/igvn/TestCombineAddPWithConstantOffsets.java b/test/hotspot/jtreg/compiler/c2/irTests/igvn/TestCombineAddPWithConstantOffsets.java index 69963316fa9..cb7a63f5fe6 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/igvn/TestCombineAddPWithConstantOffsets.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/igvn/TestCombineAddPWithConstantOffsets.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,7 +27,7 @@ import compiler.lib.ir_framework.*; /* * @test * @bug 8343067 - * @requires os.simpleArch == "x64" | os.simpleArch == "aarch64" + * @requires os.simpleArch == "x64" | os.simpleArch == "aarch64" | os.simpleArch == "riscv64" * @requires vm.compiler2.enabled * @summary Test that chains of AddP nodes with constant offsets are idealized * when their offset input changes. @@ -43,6 +43,7 @@ public class TestCombineAddPWithConstantOffsets { @Test @IR(applyIfPlatform = {"x64", "true"}, failOn = {IRNode.ADD_P_OF, ".*"}) @IR(applyIfPlatform = {"aarch64", "true"}, failOn = {IRNode.ADD_P_OF, "reg_imm"}) + @IR(applyIfPlatform = {"riscv64", "true"}, failOn = {IRNode.ADD_P_OF, "reg_imm"}) static void testCombineAddPWithConstantOffsets(int[] arr) { for (long i = 6; i < 14; i++) { arr[(int)i] = 1; From 274f8e601c60fe48c6dc0fe113c44dc253cd757b Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 25 Mar 2026 02:44:14 +0000 Subject: [PATCH 019/359] 8371182: [macos] Improve error messages for "invalid mac bundle identifier" Reviewed-by: almatvee --- .../internal/MacApplicationBuilder.java | 45 ++-- .../resources/MacResources.properties | 5 +- .../jpackage/internal/cli/StandardOption.java | 7 + .../internal/cli/StandardValidator.java | 6 +- .../resources/MainResources.properties | 2 + .../jpackage/test/CannedFormattedString.java | 20 +- .../jdk/jpackage/test/JPackageCommand.java | 47 ++++ .../test/JPackageOutputValidator.java | 5 + .../internal/MacApplicationBuilderTest.java | 96 ++++++++ .../tools/jpackage/junit/macosx/junit.java | 8 + .../cli/OptionsValidationFailTest.excludes | 1 - .../internal/cli/StandardOptionTest.java | 36 +++ .../jpackage/macosx/MacPropertiesTest.java | 223 ++++++++++++++++-- .../tools/jpackage/share/AppVersionTest.java | 41 ++-- test/jdk/tools/jpackage/share/ErrorTest.java | 4 +- 15 files changed, 465 insertions(+), 81 deletions(-) create mode 100644 test/jdk/tools/jpackage/junit/macosx/jdk.jpackage/jdk/jpackage/internal/MacApplicationBuilderTest.java diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationBuilder.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationBuilder.java index cdccd488ed6..d6b816ca75e 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationBuilder.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationBuilder.java @@ -24,6 +24,8 @@ */ package jdk.jpackage.internal; +import static jdk.jpackage.internal.cli.StandardValidator.IS_VALID_MAC_BUNDLE_IDENTIFIER; + import java.io.IOException; import java.io.UncheckedIOException; import java.nio.file.Files; @@ -37,6 +39,7 @@ import jdk.jpackage.internal.model.AppImageLayout; import jdk.jpackage.internal.model.AppImageSigningConfig; import jdk.jpackage.internal.model.Application; import jdk.jpackage.internal.model.ApplicationLaunchers; +import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.ExternalApplication; import jdk.jpackage.internal.model.JPackageException; import jdk.jpackage.internal.model.Launcher; @@ -138,20 +141,6 @@ final class MacApplicationBuilder { return MacApplication.create(ApplicationBuilder.overrideAppImageLayout(app, appImageLayout), mixin); } - static boolean isValidBundleIdentifier(String id) { - for (int i = 0; i < id.length(); i++) { - char a = id.charAt(i); - // We check for ASCII codes first which we accept. If check fails, - // check if it is acceptable extended ASCII or unicode character. - if ((a >= 'A' && a <= 'Z') || (a >= 'a' && a <= 'z') - || (a >= '0' && a <= '9') || (a == '-' || a == '.')) { - continue; - } - return false; - } - return true; - } - private static void validateAppVersion(Application app) { try { CFBundleVersion.of(app.version()); @@ -246,8 +235,8 @@ final class MacApplicationBuilder { } private String validatedBundleIdentifier(Application app) { - final var value = Optional.ofNullable(bundleIdentifier).orElseGet(() -> { - return app.mainLauncher() + return Optional.ofNullable(bundleIdentifier).orElseGet(() -> { + var derivedValue = app.mainLauncher() .flatMap(Launcher::startupInfo) .map(li -> { final var packageName = li.packageName(); @@ -258,15 +247,23 @@ final class MacApplicationBuilder { } }) .orElseGet(app::name); + + if (!IS_VALID_MAC_BUNDLE_IDENTIFIER.test(derivedValue)) { + // Derived bundle identifier is invalid. Try to adjust it by dropping all invalid characters. + derivedValue = derivedValue.codePoints() + .mapToObj(Character::toString) + .filter(IS_VALID_MAC_BUNDLE_IDENTIFIER) + .collect(Collectors.joining("")); + if (!IS_VALID_MAC_BUNDLE_IDENTIFIER.test(derivedValue)) { + throw new ConfigException( + I18N.format("error.invalid-derived-bundle-identifier"), + I18N.format("error.invalid-derived-bundle-identifier.advice")); + } + } + + Log.verbose(I18N.format("message.derived-bundle-identifier", derivedValue)); + return derivedValue; }); - - if (!isValidBundleIdentifier(value)) { - throw I18N.buildConfigException("message.invalid-identifier", value) - .advice("message.invalid-identifier.advice") - .create(); - } - - return value; } private String validatedCategory() { 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 95fff00152b..2ed1f740805 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 @@ -33,6 +33,8 @@ error.invalid-app-image-runtime-image-bin-dir=Runtime directory {0} in the prede error.invalid-runtime-image-bin-dir=Runtime image "{0}" should not contain "bin" folder error.invalid-runtime-image-bin-dir.advice=Use --strip-native-commands jlink option when generating runtime image used with {0} option error.invalid-app-image-plist-file=Invalid "{0}" file in the predefined application image +error.invalid-derived-bundle-identifier=Can't derive a valid bundle identifier from the input data +error.invalid-derived-bundle-identifier.advice=Specify bundle identifier with --mac-package-identifier option resource.app-info-plist=Application Info.plist resource.app-runtime-info-plist=Embedded Java Runtime Info.plist @@ -57,8 +59,7 @@ message.icon-not-icns= The specified icon "{0}" is not an ICNS file and will not message.version-string-too-many-components='app-version' may have between 1 and 3 numbers: 1, 1.2, 1.2.3. message.version-string-first-number-not-zero=The first number in an app-version cannot be zero or negative. message.keychain.error=Unable to get keychain list. -message.invalid-identifier=Invalid mac bundle identifier [{0}]. -message.invalid-identifier.advice=specify identifier with "--mac-package-identifier". +message.derived-bundle-identifier=Derived bundle identifier: {0} message.preparing-dmg-setup=Preparing dmg setup: {0}. message.preparing-scripts=Preparing package scripts. message.preparing-distribution-dist=Preparing distribution.dist: {0}. diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardOption.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardOption.java index 438a5ac3e6f..f193cff0dc0 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardOption.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardOption.java @@ -58,9 +58,11 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Stream; import jdk.internal.util.OperatingSystem; +import jdk.jpackage.internal.cli.OptionValueExceptionFactory.StandardArgumentsMapper; import jdk.jpackage.internal.model.AppImageBundleType; import jdk.jpackage.internal.model.BundleType; import jdk.jpackage.internal.model.BundlingOperationDescriptor; +import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.JPackageException; import jdk.jpackage.internal.model.LauncherShortcut; import jdk.jpackage.internal.model.LauncherShortcutStartupDirectory; @@ -352,6 +354,11 @@ public final class StandardOption { public static final OptionValue MAC_BUNDLE_IDENTIFIER = stringOption("mac-package-identifier") .valuePattern("package identifier") + .validator(StandardValidator.IS_VALID_MAC_BUNDLE_IDENTIFIER) + .validatorExceptionFactory(OptionValueExceptionFactory.build((message, cause) -> { + return new ConfigException(message, I18N.format("error.parameter-not-mac-bundle-identifier.advice"), cause); + }).formatArgumentsTransformer(StandardArgumentsMapper.VALUE_AND_NAME).create()) + .validatorExceptionFormatString("error.parameter-not-mac-bundle-identifier") .create(); public static final OptionValue MAC_BUNDLE_SIGNING_PREFIX = stringOption("mac-package-signing-prefix").scope(MAC_SIGNING).create(); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardValidator.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardValidator.java index cfa97439592..ee9f39ee9cd 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardValidator.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardValidator.java @@ -36,11 +36,12 @@ import java.nio.file.Path; import java.util.Objects; import java.util.function.Consumer; import java.util.function.Predicate; +import java.util.regex.Pattern; import jdk.jpackage.internal.cli.Validator.ValidatingConsumerException; import jdk.jpackage.internal.util.FileUtils; import jdk.jpackage.internal.util.MacBundle; -final public class StandardValidator { +public final class StandardValidator { private StandardValidator() { } @@ -143,6 +144,9 @@ final public class StandardValidator { return MacBundle.fromPath(path).isPresent(); }; + // https://developer.apple.com/documentation/BundleResources/Information-Property-List/CFBundleIdentifier + public static final Predicate IS_VALID_MAC_BUNDLE_IDENTIFIER = Pattern.compile("[\\p{Alnum}-\\.]+").asMatchPredicate(); + public static final class DirectoryListingIOException extends RuntimeException { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties index 02784a52acc..9dfd13d60bb 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties @@ -88,6 +88,8 @@ error.parameter-not-empty-directory=The value "{0}" provided for parameter {1} i error.parameter-not-url=The value "{0}" provided for parameter {1} is not a valid URL error.parameter-not-launcher-shortcut-dir=The value "{0}" provided for parameter {1} is not a valid shortcut startup directory error.parameter-not-mac-bundle=The value "{0}" provided for parameter {1} is not a valid macOS bundle +error.parameter-not-mac-bundle-identifier=The value "{0}" provided for parameter {1} is not a valid macOS bundle identifier. +error.parameter-not-mac-bundle-identifier.advice=Bundle identifier must be a non-empty string containing only alphanumeric characters (A-Z, a-z, and 0-9), hyphens (-), and periods (.) error.path-parameter-ioexception=I/O error accessing path value "{0}" of parameter {1} error.parameter-add-launcher-malformed=The value "{0}" provided for parameter {1} does not match the pattern = error.parameter-add-launcher-not-file=The value of path to a property file "{0}" provided for additional launcher "{1}" is not a valid file path diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/CannedFormattedString.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/CannedFormattedString.java index d5248ee2b17..cc31c416d44 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/CannedFormattedString.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/CannedFormattedString.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,7 @@ import java.util.List; import java.util.Objects; import java.util.function.BiFunction; import java.util.function.UnaryOperator; +import java.util.regex.Pattern; import java.util.stream.Stream; public record CannedFormattedString(BiFunction formatter, String key, List args) implements CannedArgument { @@ -67,6 +68,23 @@ public record CannedFormattedString(BiFunction formatt } } + public interface Spec { + + String format(); + List modelArgs(); + + default CannedFormattedString asCannedFormattedString(Object ... args) { + if (args.length != modelArgs().size()) { + throw new IllegalArgumentException(); + } + return JPackageStringBundle.MAIN.cannedFormattedString(format(), args); + } + + default Pattern asPattern() { + return JPackageStringBundle.MAIN.cannedFormattedStringAsPattern(format(), modelArgs().toArray()); + } + } + private record AddPrefixFormatter(BiFunction formatter) implements BiFunction { AddPrefixFormatter { 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 4fad120d0f6..b173d345596 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java @@ -1078,6 +1078,53 @@ public class JPackageCommand extends CommandArguments { return this; } + public JPackageCommand validateOutput( + Class messageGroup, + Consumer validatorMutator, + List expectedMessages) { + + Objects.requireNonNull(validatorMutator); + + if (!messageGroup.isEnum()) { + throw new IllegalArgumentException(); + } + + var messageSpecs = messageGroup.getEnumConstants(); + + var expectMessageFormats = expectedMessages.stream().map(CannedFormattedString::key).toList(); + + var groupMessageFormats = Stream.of(messageSpecs) + .map(CannedFormattedString.Spec::format) + .collect(Collectors.toMap(x -> x, x -> x)) + .keySet(); + + if (!groupMessageFormats.containsAll(expectMessageFormats)) { + // Expected format strings should be a subset of the group format strings. + throw new IllegalArgumentException(); + } + + if (!expectedMessages.isEmpty()) { + new JPackageOutputValidator().expectMatchingStrings(expectedMessages).mutate(validatorMutator).applyTo(this); + } + + Stream.of(messageSpecs).filter(spec -> { + return !expectMessageFormats.contains(spec.format()); + }).map(CannedFormattedString.Spec::asPattern).map(pattern -> { + return TKit.assertTextStream(pattern).negate(); + }).forEach(validator -> { + new JPackageOutputValidator().add(validator).stdoutAndStderr().applyTo(this); + }); + + return this; + } + + public JPackageCommand validateOutput( + Class messageGroup, + Consumer validatorMutator, + CannedFormattedString... expected) { + return validateOutput(messageGroup, validatorMutator, List.of(expected)); + } + public boolean isWithToolProvider() { return toolProviderSource.toolProvider().isPresent(); } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageOutputValidator.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageOutputValidator.java index ed14f40f65c..8817ca0b730 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageOutputValidator.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageOutputValidator.java @@ -140,6 +140,11 @@ public final class JPackageOutputValidator { return this; } + public JPackageOutputValidator mutate(Consumer mutator) { + mutator.accept(this); + return this; + } + public void applyTo(JPackageCommand cmd) { toResultConsumer(cmd).ifPresent(cmd::validateResult); } diff --git a/test/jdk/tools/jpackage/junit/macosx/jdk.jpackage/jdk/jpackage/internal/MacApplicationBuilderTest.java b/test/jdk/tools/jpackage/junit/macosx/jdk.jpackage/jdk/jpackage/internal/MacApplicationBuilderTest.java new file mode 100644 index 00000000000..559e8d53827 --- /dev/null +++ b/test/jdk/tools/jpackage/junit/macosx/jdk.jpackage/jdk/jpackage/internal/MacApplicationBuilderTest.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal; + +import static jdk.jpackage.internal.MacPackagingPipeline.APPLICATION_LAYOUT; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrowsExactly; + +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import jdk.jpackage.internal.model.ApplicationLaunchers; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.Launcher; +import jdk.jpackage.internal.model.LauncherStartupInfo; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +class MacApplicationBuilderTest { + + @ParameterizedTest + @CsvSource({ + "NAME,!fo#o,foo", + "NAME,bar,bar", + "MAIN_LAUNCHER_CLASSNAME,foo.b$ar.Hello,foo.bar", + "MAIN_LAUNCHER_CLASSNAME,Hello$2,Hello2", + "NAME,!#,", + }) + void testDerivedBundleIdentifier(ApplicationBuilderProperty type, String value, String expectedBundleIdentifier) { + + var builder = buildApplication(); + var macBuilder = new MacApplicationBuilder(builder); + + type.applyTo(value, builder, macBuilder); + + if (expectedBundleIdentifier != null) { + assertEquals(expectedBundleIdentifier, macBuilder.create().bundleIdentifier()); + } else { + var ex = assertThrowsExactly(ConfigException.class, macBuilder::create); + assertEquals(I18N.format("error.invalid-derived-bundle-identifier"), ex.getMessage()); + assertEquals(I18N.format("error.invalid-derived-bundle-identifier.advice"), ex.getAdvice()); + } + } + + private static ApplicationBuilder buildApplication() { + return new ApplicationBuilder().appImageLayout(APPLICATION_LAYOUT); + } + + enum ApplicationBuilderProperty { + NAME { + void applyTo(String value, ApplicationBuilder builder, MacApplicationBuilder macBuilder) { + builder.name(Objects.requireNonNull(value)); + } + }, + MAIN_LAUNCHER_CLASSNAME { + void applyTo(String value, ApplicationBuilder builder, MacApplicationBuilder macBuilder) { + var startupInfo = new LauncherStartupInfo.Stub(Objects.requireNonNull(value), List.of(), List.of(), List.of()); + var launcher = new Launcher.Stub( + startupInfo.simpleClassName(), + Optional.of(startupInfo), + List.of(), + false, + "", + Optional.empty(), + null, + Map.of()); + builder.launchers(new ApplicationLaunchers(launcher)); + } + } + ; + + abstract void applyTo(String value, ApplicationBuilder builder, MacApplicationBuilder macBuilder); + } +} diff --git a/test/jdk/tools/jpackage/junit/macosx/junit.java b/test/jdk/tools/jpackage/junit/macosx/junit.java index 4ab05daf1ae..55d309a5d7c 100644 --- a/test/jdk/tools/jpackage/junit/macosx/junit.java +++ b/test/jdk/tools/jpackage/junit/macosx/junit.java @@ -63,3 +63,11 @@ * jdk/jpackage/internal/ActiveKeychainListTest.java * @run junit jdk.jpackage/jdk.jpackage.internal.ActiveKeychainListTest */ + +/* @test + * @summary Test MacApplicationBuilderTest + * @requires (os.family == "mac") + * @compile/module=jdk.jpackage -Xlint:all -Werror + * jdk/jpackage/internal/MacApplicationBuilderTest.java + * @run junit jdk.jpackage/jdk.jpackage.internal.MacApplicationBuilderTest + */ diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/OptionsValidationFailTest.excludes b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/OptionsValidationFailTest.excludes index 19478aaa4a7..a7a65402b9c 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/OptionsValidationFailTest.excludes +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/OptionsValidationFailTest.excludes @@ -18,7 +18,6 @@ ErrorTest.test(IMAGE; args-add=[--module, com.foo.bar, --runtime-image, @@JAVA_H ErrorTest.test(IMAGE; args-add=[--module, java.base, --runtime-image, @@JAVA_HOME@@]; errors=[message.error-header+[ERR_NoMainClass]]) ErrorTest.test(LINUX_DEB; app-desc=Hello; args-add=[--linux-package-name, #]; errors=[message.error-header+[error.deb-invalid-value-for-package-name, #], message.advice-header+[error.deb-invalid-value-for-package-name.advice]]) ErrorTest.test(LINUX_RPM; app-desc=Hello; args-add=[--linux-package-name, #]; errors=[message.error-header+[error.rpm-invalid-value-for-package-name, #], message.advice-header+[error.rpm-invalid-value-for-package-name.advice]]) -ErrorTest.test(MAC_PKG; app-desc=Hello; args-add=[--mac-package-identifier, #1]; errors=[message.error-header+[message.invalid-identifier, #1], message.advice-header+[message.invalid-identifier.advice]]) ErrorTest.test(NATIVE; app-desc=Hello; args-add=[--mac-app-store, --runtime-image, @@JAVA_HOME@@]; errors=[message.error-header+[error.invalid-runtime-image-bin-dir, @@JAVA_HOME@@], message.advice-header+[error.invalid-runtime-image-bin-dir.advice, --mac-app-store]]) ErrorTest.test(NATIVE; app-desc=Hello; args-add=[--runtime-image, @@EMPTY_DIR@@]; errors=[message.error-header+[error.invalid-runtime-image-missing-file, @@EMPTY_DIR@@, lib/**/libjli.dylib]]) ErrorTest.test(NATIVE; app-desc=Hello; args-add=[--runtime-image, @@INVALID_MAC_RUNTIME_BUNDLE@@]; errors=[message.error-header+[error.invalid-runtime-image-missing-file, @@INVALID_MAC_RUNTIME_BUNDLE@@, Contents/Home/lib/**/libjli.dylib]]) diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/StandardOptionTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/StandardOptionTest.java index 58a78edb627..4d47bced8f1 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/StandardOptionTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/StandardOptionTest.java @@ -58,6 +58,7 @@ import jdk.jpackage.internal.cli.StandardOption.LauncherProperty; import jdk.jpackage.internal.model.AppImageBundleType; import jdk.jpackage.internal.model.BundleType; import jdk.jpackage.internal.model.JPackageException; +import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.LauncherShortcut; import jdk.jpackage.internal.model.LauncherShortcutStartupDirectory; import jdk.jpackage.internal.util.RootedPath; @@ -71,6 +72,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.CsvSource; import org.junit.jupiter.params.provider.EnumSource; import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.ValueSource; @@ -258,6 +260,40 @@ public class StandardOptionTest extends JUnitAdapter.TestSrcInitializer { }).toList(), result.errors()); } + @ParameterizedTest + @ValueSource(strings = { + ".", + "a-b.c", + "A", + "com.acme.Foo" + }) + void test_MAC_BUNDLE_IDENTIFIER_valid(String id) { + + var spec = StandardOption.MAC_BUNDLE_IDENTIFIER.getSpec(); + + var result = spec.convert(spec.name(), StringToken.of(id)).orElseThrow(); + + assertEquals(result, id); + } + + @ParameterizedTest + @ValueSource(strings = { + "", + ",", + "Hello!" + }) + void test_MAC_BUNDLE_IDENTIFIER_invalid(String id) { + + var spec = StandardOption.MAC_BUNDLE_IDENTIFIER.getSpec(); + + var result = spec.convert(spec.name(), StringToken.of(id)); + + var ex = assertThrows(ConfigException.class, result::orElseThrow); + + assertEquals(I18N.format("error.parameter-not-mac-bundle-identifier", id, spec.name().formatForCommandLine()), ex.getMessage()); + assertEquals(I18N.format("error.parameter-not-mac-bundle-identifier.advice"), ex.getAdvice()); + } + @ParameterizedTest @EnumSource(OptionMutatorTest.TestType.class) public void test_pathOptionMutator(OptionMutatorTest.TestType type) { diff --git a/test/jdk/tools/jpackage/macosx/MacPropertiesTest.java b/test/jdk/tools/jpackage/macosx/MacPropertiesTest.java index 67a5cf6b609..f8638735a6a 100644 --- a/test/jdk/tools/jpackage/macosx/MacPropertiesTest.java +++ b/test/jdk/tools/jpackage/macosx/MacPropertiesTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * 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,11 +21,20 @@ * questions. */ -import jdk.jpackage.test.TKit; -import jdk.jpackage.test.MacHelper; -import jdk.jpackage.test.JPackageCommand; +import java.util.ArrayList; +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.Collectors; +import jdk.jpackage.test.Annotations.ParameterSupplier; import jdk.jpackage.test.Annotations.Test; -import jdk.jpackage.test.Annotations.Parameter; +import jdk.jpackage.test.CannedFormattedString; +import jdk.jpackage.test.JPackageCommand; +import jdk.jpackage.test.JPackageOutputValidator; +import jdk.jpackage.test.MacHelper; +import jdk.jpackage.test.TKit; /** @@ -43,30 +52,198 @@ import jdk.jpackage.test.Annotations.Parameter; * --jpt-run=MacPropertiesTest */ public class MacPropertiesTest { - @Test - @Parameter("MacPackageNameTest") - public void testPackageName(String packageName) { - testParameterInAppImage("--mac-package-name", "CFBundleName", - packageName); - } @Test - @Parameter("Foo") - public void testPackageIdetifier(String packageId) { - testParameterInAppImage("--mac-package-identifier", "CFBundleIdentifier", - packageId); + @ParameterSupplier + public void test(TestSpec spec) { + spec.run(); } - private static void testParameterInAppImage(String jpackageParameterName, - String plistKeyName, String value) { - JPackageCommand cmd = JPackageCommand.helloAppImage() - .addArguments(jpackageParameterName, value); + public static Collection test() { - cmd.executeAndAssertHelloAppImageCreated(); + var testCases = new ArrayList(); - var plist = MacHelper.readPListFromAppImage(cmd.outputBundle()); + testCases.addAll(List.of( + TestSpec.build("CFBundleName").addArgs("--mac-package-name", "MacPackageNameTest").expect("MacPackageNameTest"), + TestSpec.build("CFBundleIdentifier").addArgs("--mac-package-identifier", "Foo").expect("Foo"), + // Should derive from the input data. + TestSpec.build("CFBundleIdentifier").appDesc("com.acme.Hello").expect("com.acme").expect(BundleIdentifierMessage.VALUE.asCannedFormattedString("com.acme")) + )); - TKit.assertEquals(value, plist.queryValue(plistKeyName), String.format( - "Check value of %s plist key", plistKeyName)); + return testCases.stream().map(TestSpec.Builder::create).map(v -> { + return new Object[] {v}; + }).toList(); + } + + enum BundleIdentifierMessage implements CannedFormattedString.Spec { + VALUE("message.derived-bundle-identifier", "bundle-id"), + ; + + BundleIdentifierMessage(String key, Object ... args) { + this.key = Objects.requireNonNull(key); + this.args = List.of(args); + } + + @Override + public String format() { + return key; + } + + @Override + public List modelArgs() { + return args; + } + + private final String key; + private final List args; + } + + record TestSpec( + Optional appDesc, + List addArgs, + List delArgs, + List expectedTraceMessages, + String expectedInfoPlistKeyValue, + String infoPlistKey, + Optional> traceMessagesClass) { + + TestSpec { + Objects.requireNonNull(addArgs); + Objects.requireNonNull(delArgs); + Objects.requireNonNull(expectedTraceMessages); + Objects.requireNonNull(expectedInfoPlistKeyValue); + Objects.requireNonNull(infoPlistKey); + Objects.requireNonNull(traceMessagesClass); + } + + void run() { + var cmd = appDesc.map(JPackageCommand::helloAppImage).orElseGet(JPackageCommand::helloAppImage) + .setFakeRuntime().addArguments(addArgs); + + delArgs.forEach(cmd::removeArgumentWithValue); + + Consumer validatorMutator = validator -> { + validator.matchTimestamps().stripTimestamps(); + }; + + traceMessagesClass.ifPresentOrElse(v -> { + cmd.validateOutput(v, validatorMutator, expectedTraceMessages); + }, () -> { + new JPackageOutputValidator() + .mutate(validatorMutator) + .expectMatchingStrings(expectedTraceMessages) + .applyTo(cmd); + }); + + cmd.executeAndAssertHelloAppImageCreated(); + + var plist = MacHelper.readPListFromAppImage(cmd.outputBundle()); + + TKit.assertEquals( + expectedInfoPlistKeyValue, + plist.queryValue(infoPlistKey), + String.format("Check value of %s plist key", infoPlistKey)); + } + + @Override + public String toString() { + var tokens = new ArrayList(); + + tokens.add(String.format("%s=>%s", infoPlistKey, expectedInfoPlistKeyValue)); + + appDesc.ifPresent(v -> { + tokens.add("app-desc=" + v); + }); + + if (!addArgs.isEmpty()) { + tokens.add("args-add=" + addArgs); + } + + if (!delArgs.isEmpty()) { + tokens.add("args-del=" + delArgs); + } + + if (!expectedTraceMessages.isEmpty()) { + tokens.add("expect=" + expectedTraceMessages); + } + + return tokens.stream().collect(Collectors.joining("; ")); + } + + static Builder build() { + return new Builder(); + } + + static Builder build(String infoPlistKey) { + return build().infoPlistKey(Objects.requireNonNull(infoPlistKey)); + } + + static final class Builder { + + TestSpec create() { + + Class traceMessagesClass = switch (Objects.requireNonNull(infoPlistKey)) { + case "CFBundleIdentifier" -> BundleIdentifierMessage.class; + case "CFBundleName" -> null; + default -> { + throw new IllegalStateException(); + } + }; + + return new TestSpec( + Optional.ofNullable(appDesc), + addArgs, + delArgs, + expectedTraceMessages, + expectedInfoPlistKeyValue, + infoPlistKey, + Optional.ofNullable(traceMessagesClass)); + } + + Builder appDesc(String v) { + appDesc = v; + return this; + } + + Builder addArgs(List v) { + addArgs.addAll(v); + return this; + } + + Builder addArgs(String... args) { + return addArgs(List.of(args)); + } + + Builder delArgs(List v) { + delArgs.addAll(v); + return this; + } + + Builder delArgs(String... args) { + return delArgs(List.of(args)); + } + + Builder expect(CannedFormattedString traceMessage) { + expectedTraceMessages.add(traceMessage); + return this; + } + + Builder expect(String v) { + expectedInfoPlistKeyValue = v; + return this; + } + + Builder infoPlistKey(String v) { + infoPlistKey = v; + return this; + } + + private String appDesc; + private final List addArgs = new ArrayList<>(); + private final List delArgs = new ArrayList<>(); + private final List expectedTraceMessages = new ArrayList<>(); + private String expectedInfoPlistKeyValue; + private String infoPlistKey; + } } } diff --git a/test/jdk/tools/jpackage/share/AppVersionTest.java b/test/jdk/tools/jpackage/share/AppVersionTest.java index 7ba1870def1..598ee1551b3 100644 --- a/test/jdk/tools/jpackage/share/AppVersionTest.java +++ b/test/jdk/tools/jpackage/share/AppVersionTest.java @@ -46,7 +46,6 @@ import java.util.Optional; import java.util.Set; import java.util.function.Consumer; import java.util.function.Predicate; -import java.util.stream.Stream; import jdk.internal.util.OperatingSystem; import jdk.jpackage.internal.util.MacBundle; import jdk.jpackage.internal.util.RuntimeReleaseFile; @@ -58,8 +57,6 @@ import jdk.jpackage.test.CannedFormattedString; import jdk.jpackage.test.ConfigurationTarget; import jdk.jpackage.test.JPackageCommand; import jdk.jpackage.test.JPackageCommand.StandardAssert; -import jdk.jpackage.test.JPackageOutputValidator; -import jdk.jpackage.test.JPackageStringBundle; import jdk.jpackage.test.JavaAppDesc; import jdk.jpackage.test.MacHelper; import jdk.jpackage.test.PackageTest; @@ -270,7 +267,7 @@ public final class AppVersionTest { }).toList(); } - enum Message { + enum Message implements CannedFormattedString.Spec { VERSION_FROM_MODULE("message.module-version", "version", "module"), VERSION_FROM_RELEASE_FILE("message.release-version", "version"), VERSION_NORMALIZED("message.version-normalized", "version", "version"), @@ -278,24 +275,21 @@ public final class AppVersionTest { Message(String key, Object ... args) { this.key = Objects.requireNonNull(key); - this.args = args; + this.args = List.of(args); } - CannedFormattedString cannedFormattedString(Object ... args) { - return JPackageStringBundle.MAIN.cannedFormattedString(key, args); - } - - TKit.TextStreamVerifier negateFind() { - var pattern = JPackageStringBundle.MAIN.cannedFormattedStringAsPattern(key, args); - return TKit.assertTextStream(pattern).negate(); - } - - String key() { + @Override + public String format() { return key; } + @Override + public List modelArgs() { + return args; + } + private final String key; - private final Object[] args; + private final List args; } sealed interface VersionSource { @@ -389,16 +383,9 @@ public final class AppVersionTest { } void applyTo(JPackageCommand cmd) { - Objects.requireNonNull(cmd); - new JPackageOutputValidator().expectMatchingStrings(messages).matchTimestamps().stripTimestamps().applyTo(cmd); - cmd.version(version); - - var expectMessageKeys = messages.stream().map(CannedFormattedString::key).toList(); - Stream.of(Message.values()).filter(message -> { - return !expectMessageKeys.contains(message.key()); - }).map(Message::negateFind).forEach(validator -> { - new JPackageOutputValidator().add(validator).stdoutAndStderr().applyTo(cmd); - }); + cmd.version(version).validateOutput(Message.class, validator -> { + validator.matchTimestamps().stripTimestamps(); + }, messages); } @Override @@ -436,7 +423,7 @@ public final class AppVersionTest { } Builder message(Message message, Object ... args) { - return messages(message.cannedFormattedString(args)); + return messages(message.asCannedFormattedString(args)); } private String version; diff --git a/test/jdk/tools/jpackage/share/ErrorTest.java b/test/jdk/tools/jpackage/share/ErrorTest.java index fbaec8283e8..ed5865024fa 100644 --- a/test/jdk/tools/jpackage/share/ErrorTest.java +++ b/test/jdk/tools/jpackage/share/ErrorTest.java @@ -1015,8 +1015,8 @@ public final class ErrorTest { testSpec().noAppDesc().addArgs("--app-image", Token.APP_IMAGE.token()) .error("error.app-image.mac-sign.required"), testSpec().type(PackageType.MAC_PKG).addArgs("--mac-package-identifier", "#1") - .error("message.invalid-identifier", "#1") - .advice("message.invalid-identifier.advice"), + .error("error.parameter-not-mac-bundle-identifier", "#1", "--mac-package-identifier") + .advice("error.parameter-not-mac-bundle-identifier.advice"), // Bundle for mac app store should not have runtime commands testSpec().nativeType().addArgs("--mac-app-store", "--jlink-options", "--bind-services") .error("ERR_MissingJLinkOptMacAppStore", "--strip-native-commands"), From ec8bcf72c82b4c7a6a3e6098d4f48a0fe6522e78 Mon Sep 17 00:00:00 2001 From: Vladimir Petko Date: Wed, 25 Mar 2026 04:58:48 +0000 Subject: [PATCH 020/359] 8352567: [s390x] ProblemList JFR tests requiring JFR stubs Reviewed-by: amitkumar, aph --- test/hotspot/jtreg/ProblemList.txt | 2 ++ test/jdk/ProblemList.txt | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index dec9682f0cf..3b871d9f4b6 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -78,6 +78,7 @@ compiler/floatingpoint/TestSubnormalDouble.java 8317810 generic-i586 compiler/codecache/CodeCacheFullCountTest.java 8332954 generic-all compiler/interpreter/Test6833129.java 8335266 generic-i586 +compiler/intrinsics/TestReturnOopSetForJFRWriteCheckpoint.java 8286300 linux-s390x compiler/c2/aarch64/TestStaticCallStub.java 8359963 linux-aarch64,macosx-aarch64 @@ -113,6 +114,7 @@ runtime/StackGuardPages/TestStackGuardPagesNative.java 8303612 linux-all runtime/ErrorHandling/MachCodeFramesInErrorFile.java 8313315 linux-ppc64le runtime/NMT/VirtualAllocCommitMerge.java 8309698 linux-s390x +applications/ctw/modules/jdk_jfr.java 8286300 linux-s390x applications/jcstress/copy.java 8229852 linux-all containers/docker/TestJFREvents.java 8327723 linux-x64 diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 38ffe2ae963..f1bd91d86aa 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -713,6 +713,24 @@ jdk/incubator/vector/LoadJsvmlTest.java 8305390 windows- # jdk_jfr +jdk/jfr/api/consumer/TestRecordingFileWrite.java 8286300 linux-s390x +jdk/jfr/api/consumer/streaming/TestCrossProcessStreaming.java 8286300 linux-s390x +jdk/jfr/api/consumer/streaming/TestFilledChunks.java 8286300 linux-s390x +jdk/jfr/api/consumer/streaming/TestRemovedChunks.java 8286300 linux-s390x +jdk/jfr/api/recording/misc/TestGetStreamWithFailure.java 8286300 linux-s390x +jdk/jfr/api/settings/TestSettingControl.java 8286300 linux-s390x +jdk/jfr/event/runtime/TestBackToBackSensitive.java 8286300 linux-s390x +jdk/jfr/event/runtime/TestSyncOnValueBasedClassEvent.java 8286300 linux-s390x +jdk/jfr/event/tracing/TestMultipleThreads.java 8286300 linux-s390x +jdk/jfr/event/tracing/TestTracedString.java 8286300 linux-s390x +jdk/jfr/javaagent/TestLoadedAgent.java 8286300 linux-s390x +jdk/jfr/javaagent/TestPremainAgent.java 8286300 linux-s390x +jdk/jfr/jmx/streaming/TestClose.java 8286300 linux-s390x +jdk/jfr/jmx/streaming/TestMaxSize.java 8286300 linux-s390x +jdk/jfr/jvm/TestChunkIntegrity.java 8286300 linux-s390x +jdk/jfr/jvm/TestJFRIntrinsic.java 8286300 linux-s390x +jdk/jfr/tool/TestDisassemble.java 8286300 linux-s390x +jdk/jfr/tool/TestScrub.java 8286300 linux-s390x jdk/jfr/event/compiler/TestCodeSweeper.java 8338127 generic-all jdk/jfr/event/oldobject/TestShenandoah.java 8342951 generic-all jdk/jfr/event/runtime/TestResidentSetSizeEvent.java 8309846 aix-ppc64 From 51ea257460cc999468c7799afb76fb8cebaff80c Mon Sep 17 00:00:00 2001 From: Fredrik Bredberg Date: Wed, 25 Mar 2026 06:53:14 +0000 Subject: [PATCH 021/359] 8379782: Implement Object Monitor Table enabled by default Reviewed-by: stefank, coleenp, aartemov --- src/hotspot/share/runtime/globals.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp index 17e10e2f87c..60feddde09b 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -1929,7 +1929,7 @@ const int ObjectAlignmentInBytes = 8; "Mark all threads after a safepoint, and clear on a modify " \ "fence. Add cleanliness checks.") \ \ - product(bool, UseObjectMonitorTable, false, DIAGNOSTIC, \ + product(bool, UseObjectMonitorTable, true, DIAGNOSTIC, \ "Use a table to record inflated monitors rather than the first " \ "word of the object.") \ \ From 0c60c9ca1477a114a9c7095226d3a1e5d31600fb Mon Sep 17 00:00:00 2001 From: Jean-Philippe Bempel Date: Wed, 25 Mar 2026 06:56:41 +0000 Subject: [PATCH 022/359] 8376185: NoSuchFieldError thrown after a record with type annotation retransformed Reviewed-by: sspitsyn, dholmes --- .../share/prims/jvmtiRedefineClasses.cpp | 4 +- .../RetransformRecordTypeAnn/MyRecord.java | 47 ++ .../TestRetransformRecord.java | 94 ++++ .../altered/MyRecord.jcod | 421 ++++++++++++++++++ test/lib/RedefineClassHelper.java | 2 +- 5 files changed, 566 insertions(+), 2 deletions(-) create mode 100644 test/jdk/java/lang/instrument/RetransformRecordTypeAnn/MyRecord.java create mode 100644 test/jdk/java/lang/instrument/RetransformRecordTypeAnn/TestRetransformRecord.java create mode 100644 test/jdk/java/lang/instrument/RetransformRecordTypeAnn/altered/MyRecord.jcod diff --git a/src/hotspot/share/prims/jvmtiRedefineClasses.cpp b/src/hotspot/share/prims/jvmtiRedefineClasses.cpp index 13b239b4df0..c594cfc6816 100644 --- a/src/hotspot/share/prims/jvmtiRedefineClasses.cpp +++ b/src/hotspot/share/prims/jvmtiRedefineClasses.cpp @@ -1481,6 +1481,8 @@ jvmtiError VM_RedefineClasses::load_new_class_versions() { } else { return JVMTI_ERROR_INTERNAL; } + } else if (res != JVMTI_ERROR_NONE) { + return res; } #ifdef ASSERT @@ -2045,7 +2047,7 @@ bool VM_RedefineClasses::rewrite_cp_refs_in_record_attribute(InstanceKlass* scra AnnotationArray* type_annotations = component->type_annotations(); if (type_annotations != nullptr && type_annotations->length() != 0) { int byte_i = 0; // byte index into annotations - if (!rewrite_cp_refs_in_annotations_typeArray(type_annotations, byte_i)) { + if (!rewrite_cp_refs_in_type_annotations_typeArray(type_annotations, byte_i, "record_info")) { log_debug(redefine, class, annotation)("bad record_component_type_annotations at %d", i); // propagate failure back to caller return false; diff --git a/test/jdk/java/lang/instrument/RetransformRecordTypeAnn/MyRecord.java b/test/jdk/java/lang/instrument/RetransformRecordTypeAnn/MyRecord.java new file mode 100644 index 00000000000..e0f4ecc50f5 --- /dev/null +++ b/test/jdk/java/lang/instrument/RetransformRecordTypeAnn/MyRecord.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2026, Datadog, 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. + */ + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@MyTypeAnnotation +public record MyRecord(@MyTypeUseAnnotation String filter) { + public static MyRecord parse(String param) { + if (param == null) { + throw new IllegalArgumentException("Filter cannot be null"); + } + return new MyRecord(param); + } +} + +@Target({ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@interface MyTypeAnnotation { +} + +@Target({ElementType.TYPE_USE}) +@Retention(RetentionPolicy.RUNTIME) +@interface MyTypeUseAnnotation { +} diff --git a/test/jdk/java/lang/instrument/RetransformRecordTypeAnn/TestRetransformRecord.java b/test/jdk/java/lang/instrument/RetransformRecordTypeAnn/TestRetransformRecord.java new file mode 100644 index 00000000000..e8f1ba176d1 --- /dev/null +++ b/test/jdk/java/lang/instrument/RetransformRecordTypeAnn/TestRetransformRecord.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2026, Datadog, 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 8376185 + * @summary Class retransformation on a record type annotation + * @comment This is will rewrite the constant pool and process + * @comment the type annotation + * @library /test/lib + * @modules java.base/jdk.internal.misc + * @modules java.compiler + * java.instrument + * @compile ../NamedBuffer.java + * @compile altered/MyRecord.jcod + * @run driver jdk.test.lib.helpers.ClassFileInstaller MyRecord + * @compile MyRecord.java + * @run main RedefineClassHelper + * @run main/othervm -javaagent:redefineagent.jar -Xlog:redefine*=debug TestRetransformRecord + */ + +/* + * This test is loading a record with type annotation first, then by + * calling retransformClasses, we inject a slightly different record classfile + * where just some constants from the constant pools were swapped. + * It triggers, during the retransformation, a rewrite of the constant pool + * calling VM_RedefineClasses::rewrite_cp_refs_in_record_attribute method. + */ +import java.io.File; +import java.io.FileInputStream; +import java.lang.instrument.ClassFileTransformer; +import java.lang.instrument.Instrumentation; +import java.security.ProtectionDomain; + +public class TestRetransformRecord { + static final String SRC = System.getProperty("test.src"); + static final String DEST = System.getProperty("test.classes"); + + public static void main(String[] args) throws Exception { + MyRecord.parse("foo"); + File clsfile = new File("MyRecord.class"); + byte[] buf = null; + try (FileInputStream str = new FileInputStream(clsfile)) { + buf = NamedBuffer.loadBufferFromStream(str); + } + Instrumentation inst = RedefineClassHelper.instrumentation; + inst.addTransformer(new IdentityTransformer("MyRecord", buf), true); + inst.retransformClasses(MyRecord.class); + System.out.println(MyRecord.parse("foo")); + } +} + +class IdentityTransformer implements ClassFileTransformer { + private final String className; + private final byte[] buffer; + + public IdentityTransformer(String className, byte[] buffer) { + this.className = className; + this.buffer = buffer; + } + + @Override + public byte[] transform(ClassLoader loader, + String classPath, + Class classBeingRedefined, + ProtectionDomain protectionDomain, + byte[] classfileBuffer) { + if (classPath != null && classPath.equals(className.replace('.', '/'))) { + System.out.println("Transforming " + className); + return buffer; + } + return null; + } +} diff --git a/test/jdk/java/lang/instrument/RetransformRecordTypeAnn/altered/MyRecord.jcod b/test/jdk/java/lang/instrument/RetransformRecordTypeAnn/altered/MyRecord.jcod new file mode 100644 index 00000000000..88b4c038a39 --- /dev/null +++ b/test/jdk/java/lang/instrument/RetransformRecordTypeAnn/altered/MyRecord.jcod @@ -0,0 +1,421 @@ +/* + * Copyright (c) 2026, Datadog, 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. + */ + +/* + * This is a jcod version of the MyRecord classfile. + * Generated from runnning java -jar asmtools.jar jdec MyRecord.class + * Then slightly modified to trigger constant pool rewrite. + * Here the following modifications: + * - constants #10 and #11 were swapped + * - constants #14 and #34 were swapped + */ +class MyRecord { + 0xCAFEBABE; + 0; // minor version + 69; // version + [] { // Constant Pool + ; // first element is empty + Method #2 #3; // #1 + Class #4; // #2 + NameAndType #5 #6; // #3 + Utf8 "java/lang/Record"; // #4 + Utf8 ""; // #5 + Utf8 "()V"; // #6 + Field #8 #9; // #7 + Class #11; // #8 + NameAndType #10 #12; // #9 + Utf8 "filter"; // #10 + Utf8 "MyRecord"; // #11 + Utf8 "Ljava/lang/String;"; // #12 + Class #34; // #13 + Utf8 "LMyTypeUseAnnotation;"; // #14 + String #16; // #15 + Utf8 "Filter cannot be null"; // #16 + Method #13 #18; // #17 + NameAndType #5 #19; // #18 + Utf8 "(Ljava/lang/String;)V"; // #19 + Method #8 #18; // #20 + InvokeDynamic 0s #22; // #21 + NameAndType #23 #24; // #22 + Utf8 "toString"; // #23 + Utf8 "(LMyRecord;)Ljava/lang/String;"; // #24 + InvokeDynamic 0s #26; // #25 + NameAndType #27 #28; // #26 + Utf8 "hashCode"; // #27 + Utf8 "(LMyRecord;)I"; // #28 + InvokeDynamic 0s #30; // #29 + NameAndType #31 #32; // #30 + Utf8 "equals"; // #31 + Utf8 "(LMyRecord;Ljava/lang/Object;)Z"; // #32 + Utf8 "RuntimeVisibleTypeAnnotations"; // #33 + Utf8 "java/lang/IllegalArgumentException"; // #34 + Utf8 "Code"; // #35 + Utf8 "LineNumberTable"; // #36 + Utf8 "LocalVariableTable"; // #37 + Utf8 "this"; // #38 + Utf8 "LMyRecord;"; // #39 + Utf8 "MethodParameters"; // #40 + Utf8 "parse"; // #41 + Utf8 "(Ljava/lang/String;)LMyRecord;"; // #42 + Utf8 "param"; // #43 + Utf8 "StackMapTable"; // #44 + Utf8 "()Ljava/lang/String;"; // #45 + Utf8 "()I"; // #46 + Utf8 "(Ljava/lang/Object;)Z"; // #47 + Utf8 "o"; // #48 + Utf8 "Ljava/lang/Object;"; // #49 + Utf8 "SourceFile"; // #50 + Utf8 "MyRecord.java"; // #51 + Utf8 "RuntimeVisibleAnnotations"; // #52 + Utf8 "LMyTypeAnnotation;"; // #53 + Utf8 "Record"; // #54 + Utf8 "BootstrapMethods"; // #55 + String #10; // #56 + MethodHandle 1b #7; // #57 + MethodHandle 6b #59; // #58 + Method #60 #61; // #59 + Class #62; // #60 + NameAndType #63 #64; // #61 + Utf8 "java/lang/runtime/ObjectMethods"; // #62 + Utf8 "bootstrap"; // #63 + Utf8 "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/TypeDescriptor;Ljava/lang/Class;Ljava/lang/String;[Ljava/lang/invoke/MethodHandle;)Ljava/lang/Object;"; // #64 + Utf8 "InnerClasses"; // #65 + Class #67; // #66 + Utf8 "java/lang/invoke/MethodHandles$Lookup"; // #67 + Class #69; // #68 + Utf8 "java/lang/invoke/MethodHandles"; // #69 + Utf8 "Lookup"; // #70 + } + + 0x0031; // access + #8; // this_cpx + #2; // super_cpx + + [] { // Interfaces + } // end of Interfaces + + [] { // Fields + { // field + 0x0012; // access + #10; // name_index + #12; // descriptor_index + [] { // Attributes + Attr(#33) { // RuntimeVisibleTypeAnnotations + [] { // annotations + { // type_annotation + 0x13; // target_type: FIELD + []b { // type_paths + } + #14; + [] { // element_value_pairs + } // element_value_pairs + } // type_annotation + } + } // end of RuntimeVisibleTypeAnnotations + } // end of Attributes + } + } // end of Fields + + [] { // Methods + { // method + 0x0001; // access + #5; // name_index + #19; // descriptor_index + [] { // Attributes + Attr(#35) { // Code + 2; // max_stack + 2; // max_locals + Bytes[]{ + 0x2A 0xB7 0x00 0x01 0x2A 0x2B 0xB5 0x00 0x07 0xB1; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#36) { // LineNumberTable + [] { // line_number_table + 0 7; + } + } // end of LineNumberTable + ; + Attr(#37) { // LocalVariableTable + [] { // LocalVariableTable + 0 10 38 39 0; + 0 10 11 12 1; + } + } // end of LocalVariableTable + } // end of Attributes + } // end of Code + ; + Attr(#40) { // MethodParameters + []b { // MethodParameters + #10 0x0000; + } + } // end of MethodParameters + ; + Attr(#33) { // RuntimeVisibleTypeAnnotations + [] { // annotations + { // type_annotation + 0x16; // target_type: METHOD_FORMAL_PARAMETER + 0x00; // parameter_index + []b { // type_paths + } + #14; + [] { // element_value_pairs + } // element_value_pairs + } // type_annotation + } + } // end of RuntimeVisibleTypeAnnotations + } // end of Attributes + } + ; + { // method + 0x0009; // access + #41; // name_index + #42; // descriptor_index + [] { // Attributes + Attr(#35) { // Code + 3; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xC7 0x00 0x0D 0xBB 0x00 0x0D 0x59 0x12 0x0F 0xB7 0x00; + 0x11 0xBF 0xBB 0x00 0x08 0x59 0x2A 0xB7 0x00 0x14 0xB0; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#36) { // LineNumberTable + [] { // line_number_table + 0 9; + 4 10; + 14 12; + } + } // end of LineNumberTable + ; + Attr(#37) { // LocalVariableTable + [] { // LocalVariableTable + 0 23 43 12 0; + } + } // end of LocalVariableTable + ; + Attr(#44) { // StackMapTable + [] { // + 14b; // same_frame + } + } // end of StackMapTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0011; // access + #23; // name_index + #45; // descriptor_index + [] { // Attributes + Attr(#35) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xBA 0x00 0x15 0x00 0x00 0xB0; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#36) { // LineNumberTable + [] { // line_number_table + 0 6; + } + } // end of LineNumberTable + ; + Attr(#37) { // LocalVariableTable + [] { // LocalVariableTable + 0 7 38 39 0; + } + } // end of LocalVariableTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0011; // access + #27; // name_index + #46; // descriptor_index + [] { // Attributes + Attr(#35) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xBA 0x00 0x19 0x00 0x00 0xAC; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#36) { // LineNumberTable + [] { // line_number_table + 0 6; + } + } // end of LineNumberTable + ; + Attr(#37) { // LocalVariableTable + [] { // LocalVariableTable + 0 7 38 39 0; + } + } // end of LocalVariableTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0011; // access + #31; // name_index + #47; // descriptor_index + [] { // Attributes + Attr(#35) { // Code + 2; // max_stack + 2; // max_locals + Bytes[]{ + 0x2A 0x2B 0xBA 0x00 0x1D 0x00 0x00 0xAC } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#36) { // LineNumberTable + [] { // line_number_table + 0 6; + } + } // end of LineNumberTable + ; + Attr(#37) { // LocalVariableTable + [] { // LocalVariableTable + 0 8 38 39 0; + 0 8 48 49 1; + } + } // end of LocalVariableTable + } // end of Attributes + } // end of Code + } // end of Attributes + } + ; + { // method + 0x0001; // access + #10; // name_index + #45; // descriptor_index + [] { // Attributes + Attr(#35) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2A 0xB4 0x00 0x07 0xB0; + } + [] { // Traps + } // end of Traps + [] { // Attributes + Attr(#36) { // LineNumberTable + [] { // line_number_table + 0 6; + } + } // end of LineNumberTable + ; + Attr(#37) { // LocalVariableTable + [] { // LocalVariableTable + 0 5 38 39 0; + } + } // end of LocalVariableTable + } // end of Attributes + } // end of Code + ; + Attr(#33) { // RuntimeVisibleTypeAnnotations + [] { // annotations + { // type_annotation + 0x14; // target_type: METHOD_RETURN + []b { // type_paths + } + #14; + [] { // element_value_pairs + } // element_value_pairs + } // type_annotation + } + } // end of RuntimeVisibleTypeAnnotations + } // end of Attributes + } + } // end of Methods + + [] { // Attributes + Attr(#50) { // SourceFile + #51; + } // end of SourceFile + ; + Attr(#52) { // RuntimeVisibleAnnotations + [] { // annotations + { // annotation + #53; + [] { // element_value_pairs + } // element_value_pairs + } // annotation + } + } // end of RuntimeVisibleAnnotations + ; + Attr(#54) { // Record + [] { // components + { // component + #10; // name_index + #12; // descriptor_index + [] { // Attributes + Attr(#33) { // RuntimeVisibleTypeAnnotations + [] { // annotations + { // type_annotation + 0x13; // target_type: FIELD + []b { // type_paths + } + #14; + [] { // element_value_pairs + } // element_value_pairs + } // type_annotation + } + } // end of RuntimeVisibleTypeAnnotations + } // end of Attributes + } + } + } // end of Record + ; + Attr(#55) { // BootstrapMethods + [] { // bootstrap_methods + { // bootstrap_method + #58; // bootstrap_method_ref + [] { // bootstrap_arguments + #8; + #56; + #57; + } // bootstrap_arguments + } // bootstrap_method + } + } // end of BootstrapMethods + ; + Attr(#65) { // InnerClasses + [] { // classes + #66 #68 #70 25; + } + } // end of InnerClasses + } // end of Attributes +} diff --git a/test/lib/RedefineClassHelper.java b/test/lib/RedefineClassHelper.java index ce27fb33f44..064778b3a2a 100644 --- a/test/lib/RedefineClassHelper.java +++ b/test/lib/RedefineClassHelper.java @@ -107,7 +107,7 @@ public class RedefineClassHelper { * Main method to be invoked before test to create the redefineagent.jar */ public static void main(String[] args) throws Exception { - String manifest = "Premain-Class: RedefineClassHelper\nCan-Redefine-Classes: true\n"; + String manifest = "Premain-Class: RedefineClassHelper\nCan-Redefine-Classes: true\nCan-Retransform-Classes: true\n"; ClassFileInstaller.writeJar("redefineagent.jar", ClassFileInstaller.Manifest.fromString(manifest), "RedefineClassHelper"); } } From 0423483bfdd20e22751edc3b5e5d42f2380bad47 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Wed, 25 Mar 2026 07:03:08 +0000 Subject: [PATCH 023/359] 8380772: Rename _total_allocations to _total_allocated_size in ThreadLocalAllocStats Reviewed-by: stefank, aboldtch, tschatzl --- .../gc/shared/threadLocalAllocBuffer.cpp | 24 +++++++++---------- .../gc/shared/threadLocalAllocBuffer.hpp | 6 ++--- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/hotspot/share/gc/shared/threadLocalAllocBuffer.cpp b/src/hotspot/share/gc/shared/threadLocalAllocBuffer.cpp index 4c160929f5a..9d995234736 100644 --- a/src/hotspot/share/gc/shared/threadLocalAllocBuffer.cpp +++ b/src/hotspot/share/gc/shared/threadLocalAllocBuffer.cpp @@ -302,7 +302,7 @@ HeapWord* ThreadLocalAllocBuffer::hard_end() { PerfVariable* ThreadLocalAllocStats::_perf_allocating_threads; PerfVariable* ThreadLocalAllocStats::_perf_total_refills; PerfVariable* ThreadLocalAllocStats::_perf_max_refills; -PerfVariable* ThreadLocalAllocStats::_perf_total_allocations; +PerfVariable* ThreadLocalAllocStats::_perf_total_allocated_size; PerfVariable* ThreadLocalAllocStats::_perf_total_gc_waste; PerfVariable* ThreadLocalAllocStats::_perf_max_gc_waste; PerfVariable* ThreadLocalAllocStats::_perf_total_refill_waste; @@ -325,7 +325,7 @@ void ThreadLocalAllocStats::initialize() { _perf_allocating_threads = create_perf_variable("allocThreads", PerfData::U_None, CHECK); _perf_total_refills = create_perf_variable("fills", PerfData::U_None, CHECK); _perf_max_refills = create_perf_variable("maxFills", PerfData::U_None, CHECK); - _perf_total_allocations = create_perf_variable("alloc", PerfData::U_Bytes, CHECK); + _perf_total_allocated_size = create_perf_variable("alloc", PerfData::U_Bytes, CHECK); _perf_total_gc_waste = create_perf_variable("gcWaste", PerfData::U_Bytes, CHECK); _perf_max_gc_waste = create_perf_variable("maxGcWaste", PerfData::U_Bytes, CHECK); _perf_total_refill_waste = create_perf_variable("refillWaste", PerfData::U_Bytes, CHECK); @@ -339,7 +339,7 @@ ThreadLocalAllocStats::ThreadLocalAllocStats() : _allocating_threads(0), _total_refills(0), _max_refills(0), - _total_allocations(0), + _total_allocated_size(0), _total_gc_waste(0), _max_gc_waste(0), _total_refill_waste(0), @@ -352,13 +352,13 @@ unsigned int ThreadLocalAllocStats::allocating_threads_avg() { } void ThreadLocalAllocStats::update_fast_allocations(unsigned int refills, - size_t allocations, - size_t gc_waste, - size_t refill_waste) { + size_t allocated_size, + size_t gc_waste, + size_t refill_waste) { _allocating_threads += 1; _total_refills += refills; _max_refills = MAX2(_max_refills, refills); - _total_allocations += allocations; + _total_allocated_size += allocated_size; _total_gc_waste += gc_waste; _max_gc_waste = MAX2(_max_gc_waste, gc_waste); _total_refill_waste += refill_waste; @@ -374,7 +374,7 @@ void ThreadLocalAllocStats::update(const ThreadLocalAllocStats& other) { _allocating_threads += other._allocating_threads; _total_refills += other._total_refills; _max_refills = MAX2(_max_refills, other._max_refills); - _total_allocations += other._total_allocations; + _total_allocated_size += other._total_allocated_size; _total_gc_waste += other._total_gc_waste; _max_gc_waste = MAX2(_max_gc_waste, other._max_gc_waste); _total_refill_waste += other._total_refill_waste; @@ -387,7 +387,7 @@ void ThreadLocalAllocStats::reset() { _allocating_threads = 0; _total_refills = 0; _max_refills = 0; - _total_allocations = 0; + _total_allocated_size = 0; _total_gc_waste = 0; _max_gc_waste = 0; _total_refill_waste = 0; @@ -397,14 +397,14 @@ void ThreadLocalAllocStats::reset() { } void ThreadLocalAllocStats::publish() { - if (_total_allocations == 0) { + if (_total_allocated_size == 0) { return; } _allocating_threads_avg.sample(_allocating_threads); const size_t waste = _total_gc_waste + _total_refill_waste; - const double waste_percent = percent_of(waste, _total_allocations); + const double waste_percent = percent_of(waste, _total_allocated_size); log_debug(gc, tlab)("TLAB totals: thrds: %d refills: %d max: %d" " slow allocs: %d max %d waste: %4.1f%%" " gc: %zuB max: %zuB" @@ -418,7 +418,7 @@ void ThreadLocalAllocStats::publish() { _perf_allocating_threads ->set_value(_allocating_threads); _perf_total_refills ->set_value(_total_refills); _perf_max_refills ->set_value(_max_refills); - _perf_total_allocations ->set_value(_total_allocations); + _perf_total_allocated_size ->set_value(_total_allocated_size); _perf_total_gc_waste ->set_value(_total_gc_waste); _perf_max_gc_waste ->set_value(_max_gc_waste); _perf_total_refill_waste ->set_value(_total_refill_waste); diff --git a/src/hotspot/share/gc/shared/threadLocalAllocBuffer.hpp b/src/hotspot/share/gc/shared/threadLocalAllocBuffer.hpp index eb664d13961..8c99523557e 100644 --- a/src/hotspot/share/gc/shared/threadLocalAllocBuffer.hpp +++ b/src/hotspot/share/gc/shared/threadLocalAllocBuffer.hpp @@ -182,7 +182,7 @@ private: static PerfVariable* _perf_allocating_threads; static PerfVariable* _perf_total_refills; static PerfVariable* _perf_max_refills; - static PerfVariable* _perf_total_allocations; + static PerfVariable* _perf_total_allocated_size; static PerfVariable* _perf_total_gc_waste; static PerfVariable* _perf_max_gc_waste; static PerfVariable* _perf_total_refill_waste; @@ -195,7 +195,7 @@ private: unsigned int _allocating_threads; unsigned int _total_refills; unsigned int _max_refills; - size_t _total_allocations; + size_t _total_allocated_size; size_t _total_gc_waste; size_t _max_gc_waste; size_t _total_refill_waste; @@ -210,7 +210,7 @@ public: ThreadLocalAllocStats(); void update_fast_allocations(unsigned int refills, - size_t allocations, + size_t allocated_size, size_t gc_waste, size_t refill_waste); void update_slow_allocations(unsigned int allocations); From 3bf5022bc6b8bbc544502b3fc100c6debdb1b2c7 Mon Sep 17 00:00:00 2001 From: Alan Bateman Date: Wed, 25 Mar 2026 07:40:26 +0000 Subject: [PATCH 024/359] 8380641: Thread dump parsing and test improvements 8378946: threadDump.schema.json syntax error, missing comma after owner Reviewed-by: amenkov, sspitsyn --- .../doc-files/threadDump.schema.json | 2 +- .../HotSpotDiagnosticMXBean/DumpThreads.java | 84 +++++--- .../security/provider/acvp/ML_DSA_Test.java | 10 +- test/lib/jdk/test/lib/json/JSONValue.java | 94 +++++++-- .../jdk/test/lib/threaddump/ThreadDump.java | 193 +++++++++--------- 5 files changed, 240 insertions(+), 143 deletions(-) diff --git a/src/jdk.management/share/classes/com/sun/management/doc-files/threadDump.schema.json b/src/jdk.management/share/classes/com/sun/management/doc-files/threadDump.schema.json index bf52bb3915d..1da3e3941ef 100644 --- a/src/jdk.management/share/classes/com/sun/management/doc-files/threadDump.schema.json +++ b/src/jdk.management/share/classes/com/sun/management/doc-files/threadDump.schema.json @@ -81,7 +81,7 @@ "owner": { "type": "string", "description": "The thread identifier of the owner when the parkBlocker is an AbstractOwnableSynchronizer." - } + }, "required": [ "object" ] diff --git a/test/jdk/com/sun/management/HotSpotDiagnosticMXBean/DumpThreads.java b/test/jdk/com/sun/management/HotSpotDiagnosticMXBean/DumpThreads.java index 77020491c29..3878513d3f2 100644 --- a/test/jdk/com/sun/management/HotSpotDiagnosticMXBean/DumpThreads.java +++ b/test/jdk/com/sun/management/HotSpotDiagnosticMXBean/DumpThreads.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * 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,7 @@ import java.nio.file.FileAlreadyExistsException; import java.nio.file.Path; import java.time.ZonedDateTime; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.concurrent.CountDownLatch; @@ -238,6 +239,7 @@ class DumpThreads { void testBlockedThread(ThreadFactory factory, boolean pinned) throws Exception { var lock = new Object(); + String lockAsString = Objects.toIdentityString(lock); var started = new CountDownLatch(1); Thread thread = factory.newThread(() -> { @@ -258,9 +260,7 @@ class DumpThreads { thread.start(); started.await(); await(thread, Thread.State.BLOCKED); - long tid = thread.threadId(); - String lockAsString = Objects.toIdentityString(lock); // thread dump in plain text should include thread List lines = dumpThreadsToPlainText(); @@ -308,6 +308,7 @@ class DumpThreads { void testWaitingThread(ThreadFactory factory, boolean pinned) throws Exception { var lock = new Object(); + String lockAsString = Objects.toIdentityString(lock); var started = new CountDownLatch(1); Thread thread = factory.newThread(() -> { @@ -331,9 +332,7 @@ class DumpThreads { thread.start(); started.await(); await(thread, Thread.State.WAITING); - long tid = thread.threadId(); - String lockAsString = Objects.toIdentityString(lock); // thread dump in plain text should include thread List lines = dumpThreadsToPlainText(); @@ -417,7 +416,6 @@ class DumpThreads { thread.start(); started.await(); await(thread, Thread.State.WAITING); - long tid = thread.threadId(); // thread dump in plain text should include thread @@ -460,7 +458,7 @@ class DumpThreads { } /** - * Test thread dump with a thread owning a monitor. + * Test thread dump with a thread owning monitors. */ @ParameterizedTest @MethodSource("threadFactories") @@ -475,19 +473,26 @@ class DumpThreads { } void testThreadOwnsMonitor(ThreadFactory factory, boolean pinned) throws Exception { - var lock = new Object(); - var started = new CountDownLatch(1); + var lock1 = new Object(); + var lock2 = new Object(); + var lock3 = new Object(); + String lock1AsString = Objects.toIdentityString(lock1); + String lock2AsString = Objects.toIdentityString(lock2); + String lock3AsString = Objects.toIdentityString(lock3); + var started = new CountDownLatch(1); Thread thread = factory.newThread(() -> { - synchronized (lock) { - if (pinned) { - VThreadPinner.runPinned(() -> { + synchronized (lock1) { + synchronized (lock2) { + if (pinned) { + VThreadPinner.runPinned(() -> { + started.countDown(); + lockAndRun(lock3, LockSupport::park); + }); + } else { started.countDown(); - LockSupport.park(); - }); - } else { - started.countDown(); - LockSupport.park(); + lockAndRun(lock3, LockSupport::park); + } } } }); @@ -497,16 +502,16 @@ class DumpThreads { thread.start(); started.await(); await(thread, Thread.State.WAITING); - long tid = thread.threadId(); - String lockAsString = Objects.toIdentityString(lock); // thread dump in plain text should include thread List lines = dumpThreadsToPlainText(); ThreadFields fields = findThread(tid, lines); assertNotNull(fields, "thread not found"); assertEquals("WAITING", fields.state()); - assertTrue(contains(lines, "- locked <" + lockAsString)); + assertTrue(contains(lines, "- locked <" + lock1AsString)); + assertTrue(contains(lines, "- locked <" + lock2AsString)); + assertTrue(contains(lines, "- locked <" + lock3AsString)); // thread dump in JSON format should include thread in root container ThreadDump threadDump = dumpThreadsToJson(); @@ -516,18 +521,47 @@ class DumpThreads { assertNotNull(ti, "thread not found"); assertEquals(ti.isVirtual(), thread.isVirtual()); - // the lock should be in the ownedMonitors array - Set ownedMonitors = ti.ownedMonitors().values() + // depth -> list of locks + Map> ownedMonitors = ti.ownedMonitors(); + + // lock -> list of depths + Map> monitorDepths = ownedMonitors.entrySet() .stream() - .flatMap(List::stream) - .collect(Collectors.toSet()); - assertTrue(ownedMonitors.contains(lockAsString), lockAsString + " not found"); + .flatMap(e -> e.getValue() + .stream() + .map(monitor -> Map.entry(monitor, e.getKey()))) + .collect(Collectors.groupingBy( + Map.Entry::getKey, + Collectors.mapping(Map.Entry::getValue, Collectors.toList()) + )); + + // each lock should be owned + List lock1Depths = monitorDepths.getOrDefault(lock1AsString, List.of()); + List lock2Depths = monitorDepths.getOrDefault(lock2AsString, List.of()); + List lock3Depths = monitorDepths.getOrDefault(lock3AsString, List.of()); + assertEquals(1, lock1Depths.size()); + assertEquals(1, lock2Depths.size()); + assertEquals(1, lock3Depths.size()); + + // lock1 and lock2 owned at the same depth, lock3 is the innermost + int depth1 = lock1Depths.get(0); + int depth2 = lock2Depths.get(0); + int depth3 = lock3Depths.get(0); + assertEquals(depth1, depth2); + assertTrue(depth3 < depth1); + } finally { LockSupport.unpark(thread); thread.join(); } } + private void lockAndRun(Object lock, Runnable action) { + synchronized (lock) { + action.run(); + } + } + /** * Test mounted virtual thread. */ diff --git a/test/jdk/sun/security/provider/acvp/ML_DSA_Test.java b/test/jdk/sun/security/provider/acvp/ML_DSA_Test.java index ac56642b8d7..f76f3d8b9a8 100644 --- a/test/jdk/sun/security/provider/acvp/ML_DSA_Test.java +++ b/test/jdk/sun/security/provider/acvp/ML_DSA_Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. * 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,13 +88,13 @@ public class ML_DSA_Test { for (var t : kat.get("testGroups").asArray()) { var pname = t.get("parameterSet").asString(); System.out.println(">> " + pname + " sign"); - var det = Boolean.parseBoolean(t.get("deterministic").asString()); + var det = t.get("deterministic").asBoolean(); if (t.get("signatureInterface").asString().equals("internal")) { ML_DSA_Impls.version = ML_DSA_Impls.Version.DRAFT; } else { ML_DSA_Impls.version = ML_DSA_Impls.Version.FINAL; } - if (t.get("externalMu").asString().equals("true")) { + if (t.get("externalMu").asBoolean()) { continue; // Not supported } for (var c : t.get("tests").asArray()) { @@ -139,7 +139,7 @@ public class ML_DSA_Test { ML_DSA_Impls.version = ML_DSA_Impls.Version.FINAL; } - if (t.get("externalMu").asString().equals("true")) { + if (t.get("externalMu").asBoolean()) { continue; // Not supported } @@ -157,7 +157,7 @@ public class ML_DSA_Test { public byte[] getEncoded() { return toByteArray(c.get("pk").asString()); } }; // Only ML-DSA sigVer has negative tests - var expected = Boolean.parseBoolean(c.get("testPassed").asString()); + var expected = c.get("testPassed").asBoolean(); var actual = true; try { s.initVerify(pk); diff --git a/test/lib/jdk/test/lib/json/JSONValue.java b/test/lib/jdk/test/lib/json/JSONValue.java index f89d13b3bba..72ed2fd917c 100644 --- a/test/lib/jdk/test/lib/json/JSONValue.java +++ b/test/lib/jdk/test/lib/json/JSONValue.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,7 @@ import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Optional; public interface JSONValue { @@ -88,9 +89,6 @@ public interface JSONValue { @Override public String toString() { - if (value == null) { - return "null"; - } var builder = new StringBuilder(); builder.append("\""); @@ -172,6 +170,56 @@ public interface JSONValue { public Iterator iterator() { return values.iterator(); } + + @Override + public List elements() { + return List.copyOf(values); + } + } + + public final class JSONBoolean implements JSONValue { + private static JSONBoolean TRUE = new JSONBoolean(true); + private static JSONBoolean FALSE = new JSONBoolean(false); + + private final boolean value; + + private JSONBoolean(boolean value) { + this.value = value; + } + + @Override + public boolean asBoolean() { + return value; + } + + @Override + public String toString() { + return String.valueOf(value); + } + + public static JSONBoolean of(boolean value) { + return value ? TRUE : FALSE; + } + } + + public final class JSONNull implements JSONValue { + private static JSONNull NULL = new JSONNull(); + + private JSONNull() {} + + @Override + public Optional valueOrNull() { + return Optional.empty(); + } + + @Override + public String toString() { + return "null"; + } + + public static JSONNull of() { + return NULL; + } } class JSONParser { @@ -181,8 +229,8 @@ public interface JSONValue { JSONParser() { } - private IllegalStateException failure(String message) { - return new IllegalStateException(String.format("[%d]: %s : %s", pos, message, input)); + private IllegalArgumentException failure(String message) { + return new IllegalArgumentException(String.format("[%d]: %s : %s", pos, message, input)); } private char current() { @@ -220,13 +268,13 @@ public interface JSONValue { } } - private JSONString parseBoolean() { + private JSONBoolean parseBoolean() { if (current() == 't') { expect('r'); expect('u'); expect('e'); advance(); - return new JSONString("true"); + return JSONBoolean.of(true); } if (current() == 'f') { @@ -235,7 +283,7 @@ public interface JSONValue { expect('s'); expect('e'); advance(); - return new JSONString("false"); + return JSONBoolean.of(false); } throw failure("a boolean can only be 'true' or 'false'"); } @@ -400,12 +448,12 @@ public interface JSONValue { return new JSONArray(list); } - public JSONString parseNull() { + public JSONNull parseNull() { expect('u'); expect('l'); expect('l'); advance(); - return new JSONString(null); + return JSONNull.of(); } public JSONObject parseObject() { @@ -531,22 +579,38 @@ public interface JSONValue { } default int size() { - throw new IllegalStateException("Size operation unsupported"); + throw new UnsupportedOperationException("Size operation unsupported"); + } + + default List elements() { + throw new UnsupportedOperationException("Unsupported conversion to array"); } default String asString() { - throw new IllegalStateException("Unsupported conversion to String"); + throw new UnsupportedOperationException("Unsupported conversion to String"); } default JSONArray asArray() { - throw new IllegalStateException("Unsupported conversion to array"); + throw new UnsupportedOperationException("Unsupported conversion to array"); } default JSONObject asObject() { - throw new IllegalStateException("Unsupported conversion to object"); + throw new UnsupportedOperationException("Unsupported conversion to object"); + } + + default boolean asBoolean() { + throw new UnsupportedOperationException("Unsupported conversion to boolean"); } default JSONValue get(String field) { return asObject().get(field); } + + default Optional getOrAbsent(String field) { + return Optional.ofNullable(get(field)); + } + + default Optional valueOrNull() { + return Optional.of(this); + } } diff --git a/test/lib/jdk/test/lib/threaddump/ThreadDump.java b/test/lib/jdk/test/lib/threaddump/ThreadDump.java index ca728e625fc..972d46675f4 100644 --- a/test/lib/jdk/test/lib/threaddump/ThreadDump.java +++ b/test/lib/jdk/test/lib/threaddump/ThreadDump.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved. * 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,13 +32,17 @@ import java.util.Map; import java.util.Optional; import java.util.OptionalLong; import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; import java.util.stream.Stream; import jdk.test.lib.json.JSONValue; /** * Represents a thread dump that is obtained by parsing JSON text. A thread dump in JSON * format is generated with the {@code com.sun.management.HotSpotDiagnosticMXBean} API or - * using {@code jcmd Thread.dump_to_file -format=json }. + * using {@code jcmd Thread.dump_to_file -format=json }. The thread dump + * format is documented in {@code + * src/jdk.management/share/classes/com/sun/management/doc-files/threadDump.schema.json}. * *

The following is an example thread dump that is parsed by this class. Many of the * objects are collapsed to reduce the size. @@ -127,6 +131,20 @@ public final class ThreadDump { this.threadDumpObj = threadDumpObj; } + /** + * Assert that a JSONValue is a JSONString and parse the string as an int. + */ + private static int parseStringAsInt(JSONValue valueObj) { + return Integer.parseInt(valueObj.asString()); + } + + /** + * Assert that a JSONValue is a JSONString and parse the string as a long. + */ + private static long parseStringAsLong(JSONValue valueObj) { + return Long.parseLong(valueObj.asString()); + } + /** * Represents an element in the threadDump/threadContainers array. */ @@ -149,14 +167,6 @@ public final class ThreadDump { children.add(container); } - /** - * Returns the value of a property of this thread container, as a string. - */ - private String getStringProperty(String propertyName) { - JSONValue value = containerObj.get(propertyName); - return (value != null) ? value.asString() : null; - } - /** * Returns the thread container name. */ @@ -168,10 +178,10 @@ public final class ThreadDump { * Return the thread identifier of the owner or empty OptionalLong if not owned. */ public OptionalLong owner() { - String owner = getStringProperty("owner"); - return (owner != null) - ? OptionalLong.of(Long.parseLong(owner)) - : OptionalLong.empty(); + return containerObj.get("owner") // string or null + .valueOrNull() + .map(v -> OptionalLong.of(parseStringAsLong(v))) + .orElse(OptionalLong.empty()); } /** @@ -192,12 +202,10 @@ public final class ThreadDump { * Returns a stream of {@code ThreadInfo} objects for the threads in this container. */ public Stream threads() { - JSONValue.JSONArray threadsObj = containerObj.get("threads").asArray(); - Set threadInfos = new HashSet<>(); - for (JSONValue threadObj : threadsObj) { - threadInfos.add(new ThreadInfo(threadObj)); - } - return threadInfos.stream(); + return containerObj.get("threads") + .elements() + .stream() + .map(ThreadInfo::new); } /** @@ -237,29 +245,10 @@ public final class ThreadDump { private final JSONValue threadObj; ThreadInfo(JSONValue threadObj) { - this.tid = Long.parseLong(threadObj.get("tid").asString()); + this.tid = parseStringAsLong(threadObj.get("tid")); this.threadObj = threadObj; } - /** - * Returns the value of a property of this thread object, as a string. - */ - private String getStringProperty(String propertyName) { - JSONValue value = threadObj.get(propertyName); - return (value != null) ? value.asString() : null; - } - - /** - * Returns the value of a property of an object in this thread object, as a string. - */ - private String getStringProperty(String objectName, String propertyName) { - if (threadObj.get(objectName) instanceof JSONValue.JSONObject obj - && obj.get(propertyName) instanceof JSONValue value) { - return value.asString(); - } - return null; - } - /** * Returns the thread identifier. */ @@ -271,83 +260,92 @@ public final class ThreadDump { * Returns the thread name. */ public String name() { - return getStringProperty("name"); + return threadObj.get("name").asString(); } /** * Returns the thread state. */ public String state() { - return getStringProperty("state"); + return threadObj.get("state").asString(); } /** * Returns true if virtual thread. */ public boolean isVirtual() { - String s = getStringProperty("virtual"); - return (s != null) ? Boolean.parseBoolean(s) : false; + return threadObj.getOrAbsent("virtual") + .map(JSONValue::asBoolean) + .orElse(false); } /** - * Returns the thread's parkBlocker. + * Returns the thread's parkBlocker or null. */ public String parkBlocker() { - return getStringProperty("parkBlocker", "object"); + return threadObj.getOrAbsent("parkBlocker") + .map(v -> v.get("object").asString()) + .orElse(null); } /** * Returns the owner of the parkBlocker if the parkBlocker is an AbstractOwnableSynchronizer. */ public OptionalLong parkBlockerOwner() { - String owner = getStringProperty("parkBlocker", "owner"); - return (owner != null) - ? OptionalLong.of(Long.parseLong(owner)) - : OptionalLong.empty(); + return threadObj.getOrAbsent("parkBlocker") + .map(v -> OptionalLong.of(parseStringAsLong(v.get("owner")))) + .orElse(OptionalLong.empty()); } /** - * Returns the object that the thread is blocked entering its monitor. + * Returns the object that the thread is blocked entering its monitor or null. */ public String blockedOn() { - return getStringProperty("blockedOn"); + return threadObj.getOrAbsent("blockedOn") + .map(JSONValue::asString) + .orElse(null); } /** - * Return the object that is the therad is waiting on with Object.wait. + * Return the object that is the thread is waiting on with Object.wait or null. */ public String waitingOn() { - return getStringProperty("waitingOn"); + return threadObj.getOrAbsent("waitingOn") + .map(JSONValue::asString) + .orElse(null); } /** * Returns the thread stack. */ public Stream stack() { - JSONValue.JSONArray stackObj = threadObj.get("stack").asArray(); - List stack = new ArrayList<>(); - for (JSONValue steObject : stackObj) { - stack.add(steObject.asString()); - } - return stack.stream(); + return threadObj.get("stack") + .elements() + .stream() + .map(JSONValue::asString); } /** * Return a map of monitors owned. */ public Map> ownedMonitors() { - Map> ownedMonitors = new HashMap<>(); - JSONValue monitorsOwnedObj = threadObj.get("monitorsOwned"); - if (monitorsOwnedObj != null) { - for (JSONValue obj : monitorsOwnedObj.asArray()) { - int depth = Integer.parseInt(obj.get("depth").asString()); - for (JSONValue lock : obj.get("locks").asArray()) { - ownedMonitors.computeIfAbsent(depth, _ -> new ArrayList<>()) - .add(lock.asString()); - } - } - } - return ownedMonitors; + Map> result = new HashMap<>(); + threadObj.getOrAbsent("monitorsOwned") + .map(JSONValue::elements) + .orElse(List.of()) + .forEach(e -> { + int depth = parseStringAsInt(e.get("depth")); + List locks = e.get("locks") + .elements() + .stream() + .map(v -> v.valueOrNull() // string or null + .map(JSONValue::asString) + .orElse(null)) + .toList(); + result.computeIfAbsent(depth, _ -> new ArrayList<>()).addAll(locks); + }); + + return result; } /** @@ -355,10 +353,9 @@ public final class ThreadDump { * its carrier. */ public OptionalLong carrier() { - String s = getStringProperty("carrier"); - return (s != null) - ? OptionalLong.of(Long.parseLong(s)) - : OptionalLong.empty(); + return threadObj.getOrAbsent("carrier") + .map(s -> OptionalLong.of(parseStringAsLong(s))) + .orElse(OptionalLong.empty()); } @Override @@ -388,33 +385,25 @@ public final class ThreadDump { } } - /** - * Returns the value of a property of this thread dump, as a string. - */ - private String getStringProperty(String propertyName) { - JSONValue value = threadDumpObj.get(propertyName); - return (value != null) ? value.asString() : null; - } - /** * Returns the value of threadDump/processId. */ public long processId() { - return Long.parseLong(getStringProperty("processId")); + return parseStringAsLong(threadDumpObj.get("processId")); } /** * Returns the value of threadDump/time. */ public String time() { - return getStringProperty("time"); + return threadDumpObj.get("time").asString(); } /** * Returns the value of threadDump/runtimeVersion. */ public String runtimeVersion() { - return getStringProperty("runtimeVersion"); + return threadDumpObj.get("runtimeVersion").asString(); } /** @@ -449,24 +438,31 @@ public final class ThreadDump { JSONValue threadDumpObj = JSONValue.parse(json).get("threadDump"); // threadContainers array, preserve insertion order (parents are added before children) - Map containerObjs = new LinkedHashMap<>(); - JSONValue threadContainersObj = threadDumpObj.get("threadContainers"); - for (JSONValue containerObj : threadContainersObj.asArray()) { - String name = containerObj.get("container").asString(); - containerObjs.put(name, containerObj); - } + Map containerObjs = threadDumpObj.get("threadContainers") + .elements() + .stream() + .collect(Collectors.toMap( + c -> c.get("container").asString(), + Function.identity(), + (a, b) -> { throw new RuntimeException("Duplicate container"); }, + LinkedHashMap::new + )); // find root and create tree of thread containers ThreadContainer root = null; Map map = new HashMap<>(); for (String name : containerObjs.keySet()) { JSONValue containerObj = containerObjs.get(name); - String parentName = containerObj.get("parent").asString(); - if (parentName == null) { + JSONValue parentObj = containerObj.get("parent"); + if (parentObj instanceof JSONValue.JSONNull) { + if (root != null) { + throw new RuntimeException("More than one root container"); + } root = new ThreadContainer(name, null, containerObj); map.put(name, root); } else { - var parent = map.get(parentName); + String parentName = parentObj.asString(); + ThreadContainer parent = map.get(parentName); if (parent == null) { throw new RuntimeException("Thread container " + name + " found before " + parentName); } @@ -475,7 +471,10 @@ public final class ThreadDump { map.put(name, container); } } + if (root == null) { + throw new RuntimeException("No root container"); + } return new ThreadDump(root, map, threadDumpObj); } -} \ No newline at end of file +} From 1faee07b9546b8ba46e43093267b2b9ccbc7a1dc Mon Sep 17 00:00:00 2001 From: Jatin Bhateja Date: Wed, 25 Mar 2026 08:13:47 +0000 Subject: [PATCH 025/359] 8379362: C2: Buffer overrun in VectorSupport::lanetype2name Reviewed-by: liach, vlivanov, mhaessig --- src/hotspot/share/prims/vectorSupport.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/prims/vectorSupport.cpp b/src/hotspot/share/prims/vectorSupport.cpp index 58f22d38d33..7d80ed327fd 100644 --- a/src/hotspot/share/prims/vectorSupport.cpp +++ b/src/hotspot/share/prims/vectorSupport.cpp @@ -200,7 +200,6 @@ bool VectorSupport::is_unsigned_op(jint id) { } const char* VectorSupport::lanetype2name(LaneType lane_type) { - assert(lane_type >= LT_FLOAT && lane_type <= LT_LONG, ""); const char* lanetype2name[] = { "float", "double", @@ -209,7 +208,11 @@ const char* VectorSupport::lanetype2name(LaneType lane_type) { "int", "long" }; - return lanetype2name[lane_type]; + if (lane_type >= LT_FLOAT && lane_type <= LT_LONG) { + return lanetype2name[lane_type]; + } + assert(false, "unknown lane type: %d", (int)lane_type); + return "illegal"; } int VectorSupport::vop2ideal(jint id, LaneType lt) { From 7d24a096b4cb3fa73e77370e82d24caeada9003b Mon Sep 17 00:00:00 2001 From: Daniel Fuchs Date: Wed, 25 Mar 2026 10:21:07 +0000 Subject: [PATCH 026/359] 8380824: java/net/DatagramSocket/SendReceiveMaxSize.java could also test the loopback interface Reviewed-by: jpai --- .../DatagramSocket/SendReceiveMaxSize.java | 65 ++++++++++++++++++- 1 file changed, 62 insertions(+), 3 deletions(-) diff --git a/test/jdk/java/net/DatagramSocket/SendReceiveMaxSize.java b/test/jdk/java/net/DatagramSocket/SendReceiveMaxSize.java index ded087d35e8..86936ae41d0 100644 --- a/test/jdk/java/net/DatagramSocket/SendReceiveMaxSize.java +++ b/test/jdk/java/net/DatagramSocket/SendReceiveMaxSize.java @@ -22,7 +22,7 @@ */ /* - * @test + * @test id=default * @bug 8242885 8250886 8240901 * @key randomness * @summary This test verifies that on macOS, the send buffer size is configured @@ -34,13 +34,62 @@ * @library /test/lib * @build jdk.test.lib.net.IPSupport * @run testng/othervm SendReceiveMaxSize + */ +/* + * @test id=preferIPv4Stack + * @key randomness + * @summary Check that it is possible to send and receive datagrams of + * maximum size on macOS, using an IPv4 only socket. + * @library /test/lib + * @build jdk.test.lib.net.IPSupport * @run testng/othervm -Djava.net.preferIPv4Stack=true SendReceiveMaxSize + */ +/* + * @test id=preferIPv6Addresses + * @key randomness + * @summary Check that it is possible to send and receive datagrams of + * maximum size on macOS, using a dual socket and prefering + * IPv6 addresses. + * @library /test/lib + * @build jdk.test.lib.net.IPSupport * @run testng/othervm -Djava.net.preferIPv6Addresses=true SendReceiveMaxSize */ +/* + * @test id=preferLoopback + * @key randomness + * @summary Check that it is possible to send and receive datagrams of + * maximum size on macOS, using a dual socket and the loopback + * interface. + * @library /test/lib + * @build jdk.test.lib.net.IPSupport + * @run testng/othervm -Dtest.preferLoopback=true SendReceiveMaxSize + */ +/* + * @test id=preferIPv6Loopback + * @key randomness + * @summary Check that it is possible to send and receive datagrams of + * maximum size on macOS, using a dual socket and the loopback + * interface. + * @library /test/lib + * @build jdk.test.lib.net.IPSupport + * @run testng/othervm -Dtest.preferLoopback=true -Djava.net.preferIPv6Addresses=true SendReceiveMaxSize + */ +/* + * @test id=preferIPv4Loopback + * @key randomness + * @summary Check that it is possible to send and receive datagrams of + * maximum size on macOS, using an IPv4 only socket and the + * loopback interface + * @library /test/lib + * @build jdk.test.lib.net.IPSupport + * @run testng/othervm -Dtest.preferLoopback=true -Djava.net.preferIPv4Stack=true SendReceiveMaxSize + */ import jdk.test.lib.RandomFactory; import jdk.test.lib.Platform; import jdk.test.lib.net.IPSupport; +import jtreg.SkippedException; +import org.testng.SkipException; import org.testng.annotations.BeforeTest; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; @@ -61,6 +110,9 @@ import static org.testng.Assert.assertEquals; import static org.testng.Assert.expectThrows; public class SendReceiveMaxSize { + + private final static boolean PREFER_LOOPBACK = Boolean.getBoolean("test.preferLoopback"); + private int BUF_LIMIT; private InetAddress HOST_ADDR; private final static int IPV4_SNDBUF = 65507; @@ -75,8 +127,15 @@ public class SendReceiveMaxSize { @BeforeTest public void setUp() throws IOException { - IPSupport.throwSkippedExceptionIfNonOperational(); - HOST_ADDR = InetAddress.getLocalHost(); + try { + // This method throws jtreg.SkippedException, which is + // interpreted as a test failure by testng + IPSupport.throwSkippedExceptionIfNonOperational(); + } catch (SkippedException skip) { + // throws the appropriate TestNG SkipException + throw new SkipException(skip.getMessage(), skip); + } + HOST_ADDR = PREFER_LOOPBACK ? InetAddress.getLoopbackAddress() : InetAddress.getLocalHost(); BUF_LIMIT = (HOST_ADDR instanceof Inet6Address) ? IPV6_SNDBUF : IPV4_SNDBUF; System.out.printf("Host address: %s, Buffer limit: %d%n", HOST_ADDR, BUF_LIMIT); } From 3737cad6d9fc32ccaee5373b1d84d730f6ef42f9 Mon Sep 17 00:00:00 2001 From: Evgeny Astigeevich Date: Wed, 25 Mar 2026 12:46:25 +0000 Subject: [PATCH 027/359] 8370947: Mitigate Neoverse-N1 erratum 1542419 negative impact on GCs and JIT performance Co-authored-by: Axel Boldt-Christmas Reviewed-by: shade, eosterlund, aph, aboldtch --- .../gc/z/zBarrierSetAssembler_aarch64.cpp | 4 +- src/hotspot/cpu/aarch64/globals_aarch64.hpp | 2 + src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp | 7 +- .../cpu/aarch64/vm_version_aarch64.cpp | 45 ++ .../cpu/aarch64/vm_version_aarch64.hpp | 5 + .../linux_aarch64/icache_linux_aarch64.cpp | 28 ++ .../linux_aarch64/icache_linux_aarch64.hpp | 101 ++++- .../vm_version_linux_aarch64.cpp | 2 + src/hotspot/share/asm/codeBuffer.cpp | 3 - src/hotspot/share/code/codeBlob.cpp | 6 + src/hotspot/share/code/nmethod.cpp | 32 +- src/hotspot/share/code/nmethod.hpp | 7 +- src/hotspot/share/code/relocInfo.cpp | 9 - src/hotspot/share/code/relocInfo.hpp | 2 - src/hotspot/share/gc/z/zBarrierSetNMethod.cpp | 14 +- src/hotspot/share/gc/z/zGeneration.cpp | 14 +- src/hotspot/share/gc/z/zMark.cpp | 31 +- src/hotspot/share/gc/z/zNMethod.cpp | 16 +- src/hotspot/share/gc/z/zNMethod.hpp | 2 + src/hotspot/share/runtime/globals.hpp | 2 + src/hotspot/share/runtime/icache.hpp | 23 + ...tDeferredICacheInvalidationCmdOptions.java | 426 ++++++++++++++++++ .../gc/TestDeferredICacheInvalidation.java | 306 +++++++++++++ .../bench/vm/gc/GCPatchingNmethodCost.java | 206 +++++++++ 24 files changed, 1244 insertions(+), 49 deletions(-) create mode 100644 src/hotspot/os_cpu/linux_aarch64/icache_linux_aarch64.cpp create mode 100644 test/hotspot/jtreg/compiler/runtime/TestDeferredICacheInvalidationCmdOptions.java create mode 100644 test/hotspot/jtreg/gc/TestDeferredICacheInvalidation.java create mode 100644 test/micro/org/openjdk/bench/vm/gc/GCPatchingNmethodCost.java diff --git a/src/hotspot/cpu/aarch64/gc/z/zBarrierSetAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/z/zBarrierSetAssembler_aarch64.cpp index 4f0977a414f..f0885fee93d 100644 --- a/src/hotspot/cpu/aarch64/gc/z/zBarrierSetAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/gc/z/zBarrierSetAssembler_aarch64.cpp @@ -879,7 +879,9 @@ void ZBarrierSetAssembler::patch_barrier_relocation(address addr, int format) { ShouldNotReachHere(); } - ICache::invalidate_word((address)patch_addr); + if (!UseSingleICacheInvalidation) { + ICache::invalidate_word((address)patch_addr); + } } #ifdef COMPILER1 diff --git a/src/hotspot/cpu/aarch64/globals_aarch64.hpp b/src/hotspot/cpu/aarch64/globals_aarch64.hpp index e6de2c798b1..ba29646a828 100644 --- a/src/hotspot/cpu/aarch64/globals_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/globals_aarch64.hpp @@ -127,6 +127,8 @@ define_pd_global(intx, InlineSmallCode, 1000); "Branch Protection to use: none, standard, pac-ret") \ product(bool, AlwaysMergeDMB, true, DIAGNOSTIC, \ "Always merge DMB instructions in code emission") \ + product(bool, NeoverseN1ICacheErratumMitigation, false, DIAGNOSTIC, \ + "Enable workaround for Neoverse N1 erratum 1542419") \ // end of ARCH_FLAGS diff --git a/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp b/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp index dbec2d76d4f..f1b9fb213a2 100644 --- a/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp @@ -54,7 +54,12 @@ void Relocation::pd_set_data_value(address x, bool verify_only) { bytes = MacroAssembler::pd_patch_instruction_size(addr(), x); break; } - ICache::invalidate_range(addr(), bytes); + + if (UseSingleICacheInvalidation) { + assert(_binding != nullptr, "expect to be called with RelocIterator in use"); + } else { + ICache::invalidate_range(addr(), bytes); + } } address Relocation::pd_call_destination(address orig_addr) { diff --git a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp index 4423d9c5b58..0a40cd705cd 100644 --- a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp @@ -52,6 +52,9 @@ uintptr_t VM_Version::_pac_mask; SpinWait VM_Version::_spin_wait; +bool VM_Version::_cache_dic_enabled; +bool VM_Version::_cache_idc_enabled; + const char* VM_Version::_features_names[MAX_CPU_FEATURES] = { nullptr }; static SpinWait get_spin_wait_desc() { @@ -63,6 +66,19 @@ static SpinWait get_spin_wait_desc() { return spin_wait; } +static bool has_neoverse_n1_errata_1542419() { + const int major_rev_num = VM_Version::cpu_variant(); + const int minor_rev_num = VM_Version::cpu_revision(); + // Neoverse N1: 0xd0c + // Erratum 1542419 affects r3p0, r3p1 and r4p0. + // It is fixed in r4p1 and later revisions, which are not affected. + return (VM_Version::cpu_family() == VM_Version::CPU_ARM && + VM_Version::model_is(0xd0c) && + ((major_rev_num == 3 && minor_rev_num == 0) || + (major_rev_num == 3 && minor_rev_num == 1) || + (major_rev_num == 4 && minor_rev_num == 0))); +} + void VM_Version::initialize() { #define SET_CPU_FEATURE_NAME(id, name, bit) \ _features_names[bit] = XSTR(name); @@ -74,6 +90,9 @@ void VM_Version::initialize() { _supports_atomic_getset8 = true; _supports_atomic_getadd8 = true; + _cache_dic_enabled = false; + _cache_idc_enabled = false; + get_os_cpu_info(); int dcache_line = VM_Version::dcache_line_size(); @@ -661,6 +680,32 @@ void VM_Version::initialize() { clear_feature(CPU_SVE); } + if (FLAG_IS_DEFAULT(UseSingleICacheInvalidation) && is_cache_idc_enabled() && is_cache_dic_enabled()) { + FLAG_SET_DEFAULT(UseSingleICacheInvalidation, true); + } + + if (FLAG_IS_DEFAULT(NeoverseN1ICacheErratumMitigation) && has_neoverse_n1_errata_1542419()) { + FLAG_SET_DEFAULT(NeoverseN1ICacheErratumMitigation, true); + } + + if (NeoverseN1ICacheErratumMitigation) { + if (!has_neoverse_n1_errata_1542419()) { + vm_exit_during_initialization("NeoverseN1ICacheErratumMitigation is set for the CPU not having Neoverse N1 errata 1542419"); + } + if (FLAG_IS_DEFAULT(UseSingleICacheInvalidation)) { + FLAG_SET_DEFAULT(UseSingleICacheInvalidation, true); + } + + if (!UseSingleICacheInvalidation) { + vm_exit_during_initialization("NeoverseN1ICacheErratumMitigation is set but UseSingleICacheInvalidation is not enabled"); + } + } + + if (UseSingleICacheInvalidation + && (!is_cache_idc_enabled() || (!is_cache_dic_enabled() && !NeoverseN1ICacheErratumMitigation))) { + vm_exit_during_initialization("UseSingleICacheInvalidation is set but neither IDC nor DIC nor NeoverseN1ICacheErratumMitigation is enabled"); + } + // Construct the "features" string stringStream ss(512); ss.print("0x%02x:0x%x:0x%03x:%d", _cpu, _variant, _model, _revision); diff --git a/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp b/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp index e8681611234..6145990d0d6 100644 --- a/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp @@ -58,6 +58,8 @@ protected: // When _prefer_sve_merging_mode_cpy is true, `cpy (imm, zeroing)` is // implemented as `movi; cpy(imm, merging)`. static constexpr bool _prefer_sve_merging_mode_cpy = true; + static bool _cache_dic_enabled; + static bool _cache_idc_enabled; static SpinWait _spin_wait; @@ -253,6 +255,9 @@ public: return vector_length_in_bytes <= 16; } + static bool is_cache_dic_enabled() { return _cache_dic_enabled; } + static bool is_cache_idc_enabled() { return _cache_idc_enabled; } + static void get_cpu_features_name(void* features_buffer, stringStream& ss); // Returns names of features present in features_set1 but not in features_set2 diff --git a/src/hotspot/os_cpu/linux_aarch64/icache_linux_aarch64.cpp b/src/hotspot/os_cpu/linux_aarch64/icache_linux_aarch64.cpp new file mode 100644 index 00000000000..41cad5af325 --- /dev/null +++ b/src/hotspot/os_cpu/linux_aarch64/icache_linux_aarch64.cpp @@ -0,0 +1,28 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "runtime/icache.hpp" +#include "utilities/globalDefinitions.hpp" + +NOT_PRODUCT(THREAD_LOCAL AArch64ICacheInvalidationContext* AArch64ICacheInvalidationContext::_current_context = nullptr;) diff --git a/src/hotspot/os_cpu/linux_aarch64/icache_linux_aarch64.hpp b/src/hotspot/os_cpu/linux_aarch64/icache_linux_aarch64.hpp index 8fbaa7a6b6e..b410aebed7b 100644 --- a/src/hotspot/os_cpu/linux_aarch64/icache_linux_aarch64.hpp +++ b/src/hotspot/os_cpu/linux_aarch64/icache_linux_aarch64.hpp @@ -26,6 +26,10 @@ #ifndef OS_CPU_LINUX_AARCH64_ICACHE_AARCH64_HPP #define OS_CPU_LINUX_AARCH64_ICACHE_AARCH64_HPP +#include "memory/allocation.hpp" +#include "runtime/vm_version.hpp" +#include "utilities/globalDefinitions.hpp" + // Interface for updating the instruction cache. Whenever the VM // modifies code, part of the processor instruction cache potentially // has to be flushed. @@ -37,8 +41,103 @@ class ICache : public AbstractICache { __builtin___clear_cache((char *)addr, (char *)(addr + 4)); } static void invalidate_range(address start, int nbytes) { - __builtin___clear_cache((char *)start, (char *)(start + nbytes)); + if (NeoverseN1ICacheErratumMitigation) { + assert(VM_Version::is_cache_idc_enabled(), + "Expect CTR_EL0.IDC to be enabled for Neoverse N1 with erratum " + "1542419"); + assert(!VM_Version::is_cache_dic_enabled(), + "Expect CTR_EL0.DIC to be disabled for Neoverse N1 with erratum " + "1542419"); + asm volatile("dsb ish \n" + "ic ivau, xzr \n" + "dsb ish \n" + "isb \n" + : : : "memory"); + } else { + __builtin___clear_cache((char *)start, (char *)(start + nbytes)); + } } }; +class AArch64ICacheInvalidationContext : StackObj { + private: + +#ifdef ASSERT + static THREAD_LOCAL AArch64ICacheInvalidationContext* _current_context; +#endif + + bool _has_modified_code; + + public: + NONCOPYABLE(AArch64ICacheInvalidationContext); + + AArch64ICacheInvalidationContext() + : _has_modified_code(false) { + assert(_current_context == nullptr, "nested ICacheInvalidationContext not supported"); +#ifdef ASSERT + _current_context = this; +#endif + } + + ~AArch64ICacheInvalidationContext() { + NOT_PRODUCT(_current_context = nullptr); + + if (!_has_modified_code || !UseSingleICacheInvalidation) { + return; + } + + assert(VM_Version::is_cache_idc_enabled(), "Expect CTR_EL0.IDC to be enabled"); + + asm volatile("dsb ish" : : : "memory"); + + if (NeoverseN1ICacheErratumMitigation) { + assert(!VM_Version::is_cache_dic_enabled(), + "Expect CTR_EL0.DIC to be disabled for Neoverse N1 with erratum " + "1542419"); + + // Errata 1542419: Neoverse N1 cores with the 'COHERENT_ICACHE' feature + // may fetch stale instructions when software depends on + // prefetch-speculation-protection instead of explicit synchronization. + // + // Neoverse-N1 implementation mitigates the errata 1542419 with a + // workaround: + // - Disable coherent icache. + // - Trap IC IVAU instructions. + // - Execute: + // - tlbi vae3is, xzr + // - dsb sy + // - Ignore trapped IC IVAU instructions. + // + // `tlbi vae3is, xzr` invalidates all translation entries (all VAs, all + // possible levels). It waits for all memory accesses using in-scope old + // translation information to complete before it is considered complete. + // + // As this workaround has significant overhead, Arm Neoverse N1 (MP050) + // Software Developer Errata Notice version 29.0 suggests: + // + // "Since one TLB inner-shareable invalidation is enough to avoid this + // erratum, the number of injected TLB invalidations should be minimized + // in the trap handler to mitigate the performance impact due to this + // workaround." + // As the address for icache invalidation is not relevant and + // IC IVAU instruction is ignored, we use XZR in it. + asm volatile( + "ic ivau, xzr \n" + "dsb ish \n" + : + : + : "memory"); + } else { + assert(VM_Version::is_cache_dic_enabled(), "Expect CTR_EL0.DIC to be enabled"); + } + asm volatile("isb" : : : "memory"); + } + + void set_has_modified_code() { + _has_modified_code = true; + } +}; + +#define PD_ICACHE_INVALIDATION_CONTEXT AArch64ICacheInvalidationContext + #endif // OS_CPU_LINUX_AARCH64_ICACHE_AARCH64_HPP diff --git a/src/hotspot/os_cpu/linux_aarch64/vm_version_linux_aarch64.cpp b/src/hotspot/os_cpu/linux_aarch64/vm_version_linux_aarch64.cpp index 1fe06dc640d..dad7161a3cb 100644 --- a/src/hotspot/os_cpu/linux_aarch64/vm_version_linux_aarch64.cpp +++ b/src/hotspot/os_cpu/linux_aarch64/vm_version_linux_aarch64.cpp @@ -169,6 +169,8 @@ void VM_Version::get_os_cpu_info() { _icache_line_size = (1 << (ctr_el0 & 0x0f)) * 4; _dcache_line_size = (1 << ((ctr_el0 >> 16) & 0x0f)) * 4; + _cache_idc_enabled = ((ctr_el0 >> 28) & 0x1) != 0; + _cache_dic_enabled = ((ctr_el0 >> 29) & 0x1) != 0; if (!(dczid_el0 & 0x10)) { _zva_length = 4 << (dczid_el0 & 0xf); diff --git a/src/hotspot/share/asm/codeBuffer.cpp b/src/hotspot/share/asm/codeBuffer.cpp index ba525588f32..964aec8b501 100644 --- a/src/hotspot/share/asm/codeBuffer.cpp +++ b/src/hotspot/share/asm/codeBuffer.cpp @@ -745,9 +745,6 @@ void CodeBuffer::copy_code_to(CodeBlob* dest_blob) { // Done moving code bytes; were they the right size? assert((int)align_up(dest.total_content_size(), oopSize) == dest_blob->content_size(), "sanity"); - - // Flush generated code - ICache::invalidate_range(dest_blob->code_begin(), dest_blob->code_size()); } // Move all my code into another code buffer. Consult applicable diff --git a/src/hotspot/share/code/codeBlob.cpp b/src/hotspot/share/code/codeBlob.cpp index fcc0b42a461..d07386bd795 100644 --- a/src/hotspot/share/code/codeBlob.cpp +++ b/src/hotspot/share/code/codeBlob.cpp @@ -331,7 +331,13 @@ RuntimeBlob::RuntimeBlob( : CodeBlob(name, kind, cb, size, header_size, frame_complete, frame_size, oop_maps, caller_must_gc_arguments, align_up(cb->total_relocation_size(), oopSize)) { + if (code_size() == 0) { + // Nothing to copy + return; + } + cb->copy_code_and_locs_to(this); + ICache::invalidate_range(code_begin(), code_size()); } void RuntimeBlob::free(RuntimeBlob* blob) { diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 5a6ed8ab3ed..5cb795a4723 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1328,6 +1328,7 @@ nmethod::nmethod( code_buffer->copy_values_to(this); post_init(); + ICache::invalidate_range(code_begin(), code_size()); } if (PrintNativeNMethods || PrintDebugInfo || PrintRelocations || PrintDependencies) { @@ -1809,6 +1810,7 @@ nmethod::nmethod( init_immutable_data_ref_count(); post_init(); + ICache::invalidate_range(code_begin(), code_size()); // we use the information of entry points to find out if a method is // static or non static @@ -2036,7 +2038,7 @@ void nmethod::copy_values(GrowableArray* array) { // The code and relocations have already been initialized by the // CodeBlob constructor, so it is valid even at this early point to // iterate over relocations and patch the code. - fix_oop_relocations(nullptr, nullptr, /*initialize_immediates=*/ true); + fix_oop_relocations(/*initialize_immediates=*/ true); } void nmethod::copy_values(GrowableArray* array) { @@ -2048,24 +2050,42 @@ void nmethod::copy_values(GrowableArray* array) { } } -void nmethod::fix_oop_relocations(address begin, address end, bool initialize_immediates) { +bool nmethod::fix_oop_relocations(bool initialize_immediates) { // re-patch all oop-bearing instructions, just in case some oops moved - RelocIterator iter(this, begin, end); + RelocIterator iter(this); + bool modified_code = false; while (iter.next()) { if (iter.type() == relocInfo::oop_type) { oop_Relocation* reloc = iter.oop_reloc(); - if (initialize_immediates && reloc->oop_is_immediate()) { + if (!reloc->oop_is_immediate()) { + // Refresh the oop-related bits of this instruction. + reloc->set_value(reloc->value()); + modified_code = true; + } else if (initialize_immediates) { oop* dest = reloc->oop_addr(); jobject obj = *reinterpret_cast(dest); initialize_immediate_oop(dest, obj); } - // Refresh the oop-related bits of this instruction. - reloc->fix_oop_relocation(); } else if (iter.type() == relocInfo::metadata_type) { metadata_Relocation* reloc = iter.metadata_reloc(); reloc->fix_metadata_relocation(); + modified_code |= !reloc->metadata_is_immediate(); } } + return modified_code; +} + +void nmethod::fix_oop_relocations() { + ICacheInvalidationContext icic; + fix_oop_relocations(&icic); +} + +void nmethod::fix_oop_relocations(ICacheInvalidationContext* icic) { + assert(icic != nullptr, "must provide context to track if code was modified"); + bool modified_code = fix_oop_relocations(/*initialize_immediates=*/ false); + if (modified_code) { + icic->set_has_modified_code(); + } } static void install_post_call_nop_displacement(nmethod* nm, address pc) { diff --git a/src/hotspot/share/code/nmethod.hpp b/src/hotspot/share/code/nmethod.hpp index 092da181f12..ea8c0e2ad5d 100644 --- a/src/hotspot/share/code/nmethod.hpp +++ b/src/hotspot/share/code/nmethod.hpp @@ -41,6 +41,7 @@ class Dependencies; class DirectiveSet; class DebugInformationRecorder; class ExceptionHandlerTable; +class ICacheInvalidationContext; class ImplicitExceptionTable; class JvmtiThreadState; class MetadataClosure; @@ -801,15 +802,15 @@ public: // Relocation support private: - void fix_oop_relocations(address begin, address end, bool initialize_immediates); + bool fix_oop_relocations(bool initialize_immediates); inline void initialize_immediate_oop(oop* dest, jobject handle); protected: address oops_reloc_begin() const; public: - void fix_oop_relocations(address begin, address end) { fix_oop_relocations(begin, end, false); } - void fix_oop_relocations() { fix_oop_relocations(nullptr, nullptr, false); } + void fix_oop_relocations(ICacheInvalidationContext* icic); + void fix_oop_relocations(); bool is_at_poll_return(address pc); bool is_at_poll_or_poll_return(address pc); diff --git a/src/hotspot/share/code/relocInfo.cpp b/src/hotspot/share/code/relocInfo.cpp index 2a6335e2118..25d91edc20f 100644 --- a/src/hotspot/share/code/relocInfo.cpp +++ b/src/hotspot/share/code/relocInfo.cpp @@ -590,15 +590,6 @@ oop oop_Relocation::oop_value() { return *oop_addr(); } - -void oop_Relocation::fix_oop_relocation() { - if (!oop_is_immediate()) { - // get the oop from the pool, and re-insert it into the instruction: - set_value(value()); - } -} - - void oop_Relocation::verify_oop_relocation() { if (!oop_is_immediate()) { // get the oop from the pool, and re-insert it into the instruction: diff --git a/src/hotspot/share/code/relocInfo.hpp b/src/hotspot/share/code/relocInfo.hpp index 6f1778ef479..bb2b2b5693f 100644 --- a/src/hotspot/share/code/relocInfo.hpp +++ b/src/hotspot/share/code/relocInfo.hpp @@ -988,8 +988,6 @@ class oop_Relocation : public DataRelocation { void pack_data_to(CodeSection* dest) override; void unpack_data() override; - void fix_oop_relocation(); // reasserts oop value - void verify_oop_relocation(); address value() override { return *reinterpret_cast(oop_addr()); } diff --git a/src/hotspot/share/gc/z/zBarrierSetNMethod.cpp b/src/hotspot/share/gc/z/zBarrierSetNMethod.cpp index d80ce4e149d..a439b3a167b 100644 --- a/src/hotspot/share/gc/z/zBarrierSetNMethod.cpp +++ b/src/hotspot/share/gc/z/zBarrierSetNMethod.cpp @@ -33,6 +33,7 @@ #include "gc/z/zThreadLocalData.hpp" #include "gc/z/zUncoloredRoot.inline.hpp" #include "logging/log.hpp" +#include "runtime/icache.hpp" #include "runtime/threadWXSetters.inline.hpp" bool ZBarrierSetNMethod::nmethod_entry_barrier(nmethod* nm) { @@ -70,12 +71,15 @@ bool ZBarrierSetNMethod::nmethod_entry_barrier(nmethod* nm) { return false; } - // Heal barriers - ZNMethod::nmethod_patch_barriers(nm); + { + ICacheInvalidationContext icic; + // Heal barriers + ZNMethod::nmethod_patch_barriers(nm, &icic); - // Heal oops - ZUncoloredRootProcessWeakOopClosure cl(ZNMethod::color(nm)); - ZNMethod::nmethod_oops_do_inner(nm, &cl); + // Heal oops + ZUncoloredRootProcessWeakOopClosure cl(ZNMethod::color(nm)); + ZNMethod::nmethod_oops_do_inner(nm, &cl, &icic); + } const uintptr_t prev_color = ZNMethod::color(nm); const uintptr_t new_color = *ZPointerStoreGoodMaskLowOrderBitsAddr; diff --git a/src/hotspot/share/gc/z/zGeneration.cpp b/src/hotspot/share/gc/z/zGeneration.cpp index 27f352a624f..0f9f4e34a5e 100644 --- a/src/hotspot/share/gc/z/zGeneration.cpp +++ b/src/hotspot/share/gc/z/zGeneration.cpp @@ -58,6 +58,7 @@ #include "prims/jvmtiTagMap.hpp" #include "runtime/continuation.hpp" #include "runtime/handshake.hpp" +#include "runtime/icache.hpp" #include "runtime/safepoint.hpp" #include "runtime/threads.hpp" #include "runtime/vmOperations.hpp" @@ -1434,12 +1435,15 @@ public: virtual void do_nmethod(nmethod* nm) { ZLocker locker(ZNMethod::lock_for_nmethod(nm)); if (_bs_nm->is_armed(nm)) { - // Heal barriers - ZNMethod::nmethod_patch_barriers(nm); + { + ICacheInvalidationContext icic; + // Heal barriers + ZNMethod::nmethod_patch_barriers(nm, &icic); - // Heal oops - ZUncoloredRootProcessOopClosure cl(ZNMethod::color(nm)); - ZNMethod::nmethod_oops_do_inner(nm, &cl); + // Heal oops + ZUncoloredRootProcessOopClosure cl(ZNMethod::color(nm)); + ZNMethod::nmethod_oops_do_inner(nm, &cl, &icic); + } log_trace(gc, nmethod)("nmethod: " PTR_FORMAT " visited by old remapping", p2i(nm)); diff --git a/src/hotspot/share/gc/z/zMark.cpp b/src/hotspot/share/gc/z/zMark.cpp index 03701ae9998..ac7d86db240 100644 --- a/src/hotspot/share/gc/z/zMark.cpp +++ b/src/hotspot/share/gc/z/zMark.cpp @@ -59,6 +59,7 @@ #include "oops/oop.inline.hpp" #include "runtime/continuation.hpp" #include "runtime/handshake.hpp" +#include "runtime/icache.hpp" #include "runtime/javaThread.hpp" #include "runtime/prefetch.inline.hpp" #include "runtime/safepointMechanism.hpp" @@ -718,12 +719,15 @@ public: virtual void do_nmethod(nmethod* nm) { ZLocker locker(ZNMethod::lock_for_nmethod(nm)); if (_bs_nm->is_armed(nm)) { - // Heal barriers - ZNMethod::nmethod_patch_barriers(nm); + { + ICacheInvalidationContext icic; + // Heal barriers + ZNMethod::nmethod_patch_barriers(nm, &icic); - // Heal oops - ZUncoloredRootMarkOopClosure cl(ZNMethod::color(nm)); - ZNMethod::nmethod_oops_do_inner(nm, &cl); + // Heal oops + ZUncoloredRootMarkOopClosure cl(ZNMethod::color(nm)); + ZNMethod::nmethod_oops_do_inner(nm, &cl, &icic); + } // CodeCache unloading support nm->mark_as_maybe_on_stack(); @@ -753,10 +757,6 @@ public: if (_bs_nm->is_armed(nm)) { const uintptr_t prev_color = ZNMethod::color(nm); - // Heal oops - ZUncoloredRootMarkYoungOopClosure cl(prev_color); - ZNMethod::nmethod_oops_do_inner(nm, &cl); - // Disarm only the young marking, not any potential old marking cycle const uintptr_t old_marked_mask = ZPointerMarkedMask ^ (ZPointerMarkedYoung0 | ZPointerMarkedYoung1); @@ -767,9 +767,16 @@ public: // Check if disarming for young mark, completely disarms the nmethod entry barrier const bool complete_disarm = ZPointer::is_store_good(new_disarm_value_ptr); - if (complete_disarm) { - // We are about to completely disarm the nmethod, must take responsibility to patch all barriers before disarming - ZNMethod::nmethod_patch_barriers(nm); + { + ICacheInvalidationContext icic; + if (complete_disarm) { + // We are about to completely disarm the nmethod, must take responsibility to patch all barriers before disarming + ZNMethod::nmethod_patch_barriers(nm, &icic); + } + + // Heal oops + ZUncoloredRootMarkYoungOopClosure cl(prev_color); + ZNMethod::nmethod_oops_do_inner(nm, &cl, &icic); } _bs_nm->guard_with(nm, (int)untype(new_disarm_value_ptr)); diff --git a/src/hotspot/share/gc/z/zNMethod.cpp b/src/hotspot/share/gc/z/zNMethod.cpp index 780bc9e3bf7..a1348b63b6f 100644 --- a/src/hotspot/share/gc/z/zNMethod.cpp +++ b/src/hotspot/share/gc/z/zNMethod.cpp @@ -50,6 +50,7 @@ #include "oops/oop.inline.hpp" #include "runtime/atomicAccess.hpp" #include "runtime/continuation.hpp" +#include "runtime/icache.hpp" #include "utilities/debug.hpp" static ZNMethodData* gc_data(const nmethod* nm) { @@ -245,8 +246,16 @@ void ZNMethod::set_guard_value(nmethod* nm, int value) { } void ZNMethod::nmethod_patch_barriers(nmethod* nm) { + ICacheInvalidationContext icic; + nmethod_patch_barriers(nm, &icic); +} + +void ZNMethod::nmethod_patch_barriers(nmethod* nm, ICacheInvalidationContext* icic) { ZBarrierSetAssembler* const bs_asm = ZBarrierSet::assembler(); ZArrayIterator iter(gc_data(nm)->barriers()); + if (gc_data(nm)->barriers()->is_nonempty()) { + icic->set_has_modified_code(); + } for (ZNMethodDataBarrier barrier; iter.next(&barrier);) { bs_asm->patch_barrier_relocation(barrier._reloc_addr, barrier._reloc_format); } @@ -258,6 +267,11 @@ void ZNMethod::nmethod_oops_do(nmethod* nm, OopClosure* cl) { } void ZNMethod::nmethod_oops_do_inner(nmethod* nm, OopClosure* cl) { + ICacheInvalidationContext icic; + nmethod_oops_do_inner(nm, cl, &icic); +} + +void ZNMethod::nmethod_oops_do_inner(nmethod* nm, OopClosure* cl, ICacheInvalidationContext* icic) { // Process oops table { oop* const begin = nm->oops_begin(); @@ -283,7 +297,7 @@ void ZNMethod::nmethod_oops_do_inner(nmethod* nm, OopClosure* cl) { // Process non-immediate oops if (data->has_non_immediate_oops()) { - nm->fix_oop_relocations(); + nm->fix_oop_relocations(icic); } } diff --git a/src/hotspot/share/gc/z/zNMethod.hpp b/src/hotspot/share/gc/z/zNMethod.hpp index 865ea11e7b9..2779151c576 100644 --- a/src/hotspot/share/gc/z/zNMethod.hpp +++ b/src/hotspot/share/gc/z/zNMethod.hpp @@ -56,9 +56,11 @@ public: static void set_guard_value(nmethod* nm, int value); static void nmethod_patch_barriers(nmethod* nm); + static void nmethod_patch_barriers(nmethod* nm, ICacheInvalidationContext* icic); static void nmethod_oops_do(nmethod* nm, OopClosure* cl); static void nmethod_oops_do_inner(nmethod* nm, OopClosure* cl); + static void nmethod_oops_do_inner(nmethod* nm, OopClosure* cl, ICacheInvalidationContext* icic); static void nmethods_do_begin(bool secondary); static void nmethods_do_end(bool secondary); diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp index 60feddde09b..296c5dedf8a 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -1978,6 +1978,8 @@ const int ObjectAlignmentInBytes = 8; develop(uint, BinarySearchThreshold, 16, \ "Minimal number of elements in a sorted collection to prefer" \ "binary search over simple linear search." ) \ + product(bool, UseSingleICacheInvalidation, false, DIAGNOSTIC, \ + "Defer multiple ICache invalidation to single invalidation") \ \ // end of RUNTIME_FLAGS diff --git a/src/hotspot/share/runtime/icache.hpp b/src/hotspot/share/runtime/icache.hpp index bc153862323..692a876d9a6 100644 --- a/src/hotspot/share/runtime/icache.hpp +++ b/src/hotspot/share/runtime/icache.hpp @@ -129,4 +129,27 @@ class ICacheStubGenerator : public StubCodeGenerator { void generate_icache_flush(ICache::flush_icache_stub_t* flush_icache_stub); }; +class DefaultICacheInvalidationContext : StackObj { + public: + NONCOPYABLE(DefaultICacheInvalidationContext); + + DefaultICacheInvalidationContext() {} + + ~DefaultICacheInvalidationContext() {} + + void set_has_modified_code() {} +}; + +#ifndef PD_ICACHE_INVALIDATION_CONTEXT +#define PD_ICACHE_INVALIDATION_CONTEXT DefaultICacheInvalidationContext +#endif // PD_ICACHE_INVALIDATION_CONTEXT + +class ICacheInvalidationContext final : public PD_ICACHE_INVALIDATION_CONTEXT { + private: + NONCOPYABLE(ICacheInvalidationContext); + + public: + using PD_ICACHE_INVALIDATION_CONTEXT::PD_ICACHE_INVALIDATION_CONTEXT; +}; + #endif // SHARE_RUNTIME_ICACHE_HPP diff --git a/test/hotspot/jtreg/compiler/runtime/TestDeferredICacheInvalidationCmdOptions.java b/test/hotspot/jtreg/compiler/runtime/TestDeferredICacheInvalidationCmdOptions.java new file mode 100644 index 00000000000..8bc74be5c62 --- /dev/null +++ b/test/hotspot/jtreg/compiler/runtime/TestDeferredICacheInvalidationCmdOptions.java @@ -0,0 +1,426 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package compiler.runtime; + +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; +import jdk.test.whitebox.WhiteBox; +import jtreg.SkippedException; + +/* + * @test + * @bug 8370947 + * @summary Test command-line options for UseSingleICacheInvalidation and NeoverseN1ICacheErratumMitigation + * @library /test/lib + * @requires os.arch == "aarch64" + * @requires os.family == "linux" + * @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.runtime.TestDeferredICacheInvalidationCmdOptions + */ + +public class TestDeferredICacheInvalidationCmdOptions { + + // CPU identifiers + private static final int CPU_ARM = 0x41; + private static final int NEOVERSE_N1_MODEL = 0xd0c; + + private static boolean isAffected; + + public static void main(String[] args) throws Exception { + // Parse CPU features and print CPU info + parseCPUFeatures(); + + System.out.println("Testing UseSingleICacheInvalidation and NeoverseN1ICacheErratumMitigation command-line options..."); + + // Test case 1: Check defaults on Neoverse N1 pre-r4p1 (if applicable) + testCase1_DefaultsOnNeoverseN1(); + + // Test case 2: Check NeoverseN1ICacheErratumMitigation is false on unaffected CPUs + testCase2_DefaultsOnUnaffectedCPUs(); + + // Test case 3: Check if NeoverseN1ICacheErratumMitigation is set to false on affected CPUs, + // UseSingleICacheInvalidation is also set to false + testCase3_ExplicitlyDisableErrataAffectsDeferred(); + + // Test case 4: Check JVM error if UseSingleICacheInvalidation=true + // but NeoverseN1ICacheErratumMitigation=false on affected CPUs + testCase4_ConflictingFlagsOnAffectedCPUs(); + + // Test case 5: Check explicit NeoverseN1ICacheErratumMitigation=true enables UseSingleICacheInvalidation + testCase5_ExplicitlyEnableErrataEnablesDeferred(); + + // Test case 6: Check both flags can be explicitly set to false + testCase6_ExplicitlyDisableBothFlags(); + + // Test case 7: Check UseSingleICacheInvalidation=false with NeoverseN1ICacheErratumMitigation=true + testCase7_ConflictingErrataWithoutDeferred(); + + // Test case 8: Check setting NeoverseN1ICacheErratumMitigation=true on unaffected CPU causes an error + testCase8_EnablingErrataOnUnaffectedCPU(); + + System.out.println("All test cases passed!"); + } + + /** + * Parse CPU features string from WhiteBox.getCPUFeatures() to extract: + * - cpuFamily: 0x41 for ARM + * - cpuVariant: major revision + * - cpuModel: e.g., 0xd0c for Neoverse N1 + * - cpuRevision: minor revision + * - cpuModel2: secondary model (if present, in parentheses) + * + * Sets the static field isAffected and prints CPU info. + * + * Format: 0x%02x:0x%x:0x%03x:%d[(0x%03x)] + * Example: "0x41:0x3:0xd0c:0" or "0x41:0x3:0xd0c:0(0xd0c)" + * + * @throws SkippedException if not running on ARM CPU + */ + private static void parseCPUFeatures() { + WhiteBox wb = WhiteBox.getWhiteBox(); + String cpuFeatures = wb.getCPUFeatures(); + System.out.println("CPU Features string: " + cpuFeatures); + + if (cpuFeatures == null || cpuFeatures.isEmpty()) { + throw new RuntimeException("No CPU features available"); + } + + int commaIndex = cpuFeatures.indexOf(","); + if (commaIndex == -1) { + throw new RuntimeException("Unexpected CPU features format (no comma): " + cpuFeatures); + } + + String cpuPart = cpuFeatures.substring(0, commaIndex).trim(); + + String[] parts = cpuPart.split(":"); + if (parts.length < 4) { + throw new RuntimeException("Unexpected CPU features format: " + cpuPart); + } + + int cpuFamily = Integer.parseInt(parts[0].substring(2), 16); + if (cpuFamily != CPU_ARM) { + throw new SkippedException("Not running on ARM CPU (cpuFamily=0x" + Integer.toHexString(cpuFamily) + ")"); + } + + int cpuVariant = Integer.parseInt(parts[1].substring(2), 16); + int cpuModel = Integer.parseInt(parts[2].substring(2), 16); + int cpuModel2 = 0; + + int model2Start = parts[3].indexOf("("); + String revisionStr = parts[3]; + if (model2Start != -1) { + if (!parts[3].endsWith(")")) { + throw new RuntimeException("Unexpected CPU features format (missing closing parenthesis): " + parts[3]); + } + String model2Str = parts[3].substring(model2Start + 1, parts[3].length() - 1); + cpuModel2 = Integer.parseInt(model2Str.substring(2), 16); + revisionStr = parts[3].substring(0, model2Start); + } + int cpuRevision = Integer.parseInt(revisionStr); + + // Neoverse N1 errata 1542419 affects r3p0, r3p1 and r4p0. + // It is fixed in r4p1 and later revisions. + if (cpuModel == NEOVERSE_N1_MODEL || cpuModel2 == NEOVERSE_N1_MODEL) { + isAffected = (cpuVariant == 3 && cpuRevision == 0) || + (cpuVariant == 3 && cpuRevision == 1) || + (cpuVariant == 4 && cpuRevision == 0); + } + + printCPUInfo(cpuFamily, cpuVariant, cpuModel, cpuModel2, cpuRevision); + } + + private static void printCPUInfo(int cpuFamily, int cpuVariant, int cpuModel, int cpuModel2, int cpuRevision) { + boolean isNeoverseN1 = (cpuFamily == CPU_ARM) && + (cpuModel == NEOVERSE_N1_MODEL || cpuModel2 == NEOVERSE_N1_MODEL); + System.out.println("\n=== CPU Information ==="); + System.out.println("CPU Family: 0x" + Integer.toHexString(cpuFamily)); + System.out.println("CPU Variant: 0x" + Integer.toHexString(cpuVariant)); + System.out.println("CPU Model: 0x" + Integer.toHexString(cpuModel)); + if (cpuModel2 != 0) { + System.out.println("CPU Model2: 0x" + Integer.toHexString(cpuModel2)); + } + System.out.println("CPU Revision: " + cpuRevision); + System.out.println("Is Neoverse N1: " + isNeoverseN1); + System.out.println("Is affected by errata 1542419: " + isAffected); + System.out.println("======================\n"); + } + + /** + * Test case 1: Check the UseSingleICacheInvalidation and NeoverseN1ICacheErratumMitigation + * are set to true for Neoverse N1 pre-r4p1. + */ + private static void testCase1_DefaultsOnNeoverseN1() throws Exception { + if (!isAffected) { + System.out.println("\nTest case 1: Skipping since CPU is not affected by Neoverse N1 errata 1542419"); + return; + } + + System.out.println("\nTest case 1: Check defaults on Neoverse N1 affected revisions"); + + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+PrintFlagsFinal", + "-version"); + + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldHaveExitValue(0); + + String output_str = output.getOutput(); + boolean hasSingleEnabled = output_str.matches("(?s).*bool\\s+UseSingleICacheInvalidation\\s*=\\s*true.*"); + boolean hasErrataEnabled = output_str.matches("(?s).*bool\\s+NeoverseN1ICacheErratumMitigation\\s*=\\s*true.*"); + + System.out.println("UseSingleICacheInvalidation enabled: " + hasSingleEnabled); + System.out.println("NeoverseN1ICacheErratumMitigation enabled: " + hasErrataEnabled); + + // If running on affected Neoverse N1, both should be true + if (!hasSingleEnabled || !hasErrataEnabled) { + throw new RuntimeException("On affected Neoverse N1, both flags should be enabled by default"); + } + System.out.println("Correctly enabled on affected Neoverse N1"); + } + + /** + * Test case 2: Check NeoverseN1ICacheErratumMitigation is false on unaffected CPUs. + */ + private static void testCase2_DefaultsOnUnaffectedCPUs() throws Exception { + if (isAffected) { + System.out.println("\nTest case 2: Skipping since CPU is affected by Neoverse N1 errata 1542419"); + return; + } + + System.out.println("\nTest case 2: Check NeoverseN1ICacheErratumMitigation is false on unaffected CPUs"); + + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+PrintFlagsFinal", + "-version"); + + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldHaveExitValue(0); + + String output_str = output.getOutput(); + boolean hasErrataEnabled = output_str.matches("(?s).*bool\\s+NeoverseN1ICacheErratumMitigation\\s*=\\s*true.*"); + + System.out.println("NeoverseN1ICacheErratumMitigation enabled: " + hasErrataEnabled); + + // On non-Neoverse N1 or unaffected Neoverse N1 CPUs, NeoverseN1ICacheErratumMitigation should be false + if (hasErrataEnabled) { + throw new RuntimeException("On unaffected CPUs, NeoverseN1ICacheErratumMitigation should be disabled"); + } + System.out.println("Correctly disabled on unaffected CPU"); + } + + /** + * Test case 3: Check if NeoverseN1ICacheErratumMitigation is set to false via cmd on affected CPUs, + * UseSingleICacheInvalidation is set to false. + */ + private static void testCase3_ExplicitlyDisableErrataAffectsDeferred() throws Exception { + if (!isAffected) { + System.out.println("\nTest case 3: Skipping since CPU is not affected by Neoverse N1 errata 1542419"); + return; + } + + System.out.println("\nTest case 3: Explicitly disable NeoverseN1ICacheErratumMitigation, check UseSingleICacheInvalidation"); + + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( + "-XX:+UnlockDiagnosticVMOptions", + "-XX:-NeoverseN1ICacheErratumMitigation", + "-XX:+PrintFlagsFinal", + "-version"); + + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldHaveExitValue(0); + + String output_str = output.getOutput(); + boolean hasSingleDisabled = output_str.matches("(?s).*bool\\s+UseSingleICacheInvalidation\\s*=\\s*false.*"); + boolean hasErrataDisabled = output_str.matches("(?s).*bool\\s+NeoverseN1ICacheErratumMitigation\\s*=\\s*false.*"); + + System.out.println("NeoverseN1ICacheErratumMitigation disabled: " + hasErrataDisabled); + System.out.println("UseSingleICacheInvalidation disabled: " + hasSingleDisabled); + + if (!hasErrataDisabled) { + throw new RuntimeException("Failed to disable NeoverseN1ICacheErratumMitigation via command line"); + } + + // On affected CPUs, disabling errata should also disable UseSingleICacheInvalidation + if (!hasSingleDisabled) { + throw new RuntimeException("On affected CPU, disabling NeoverseN1ICacheErratumMitigation should also disable UseSingleICacheInvalidation"); + } + System.out.println("Correctly synchronized on affected CPU"); + } + + /** + * Test case 4: Check JVM reports an error if UseSingleICacheInvalidation is set to true + * but NeoverseN1ICacheErratumMitigation is set to false on affected CPUs. + */ + private static void testCase4_ConflictingFlagsOnAffectedCPUs() throws Exception { + if (!isAffected) { + System.out.println("\nTest case 4: Skipping since CPU is not affected by Neoverse N1 errata 1542419"); + return; + } + + System.out.println("\nTest case 4: Try to set UseSingleICacheInvalidation=true with NeoverseN1ICacheErratumMitigation=false"); + + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+UseSingleICacheInvalidation", + "-XX:-NeoverseN1ICacheErratumMitigation", + "-version"); + + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + + if (output.getExitValue() == 0) { + throw new RuntimeException("On affected CPU, conflicting flags should cause error"); + } + output.shouldContain("Error"); + System.out.println("JVM correctly rejected conflicting flags on affected CPU"); + } + + /** + * Test case 5: Check explicit NeoverseN1ICacheErratumMitigation=true enables UseSingleICacheInvalidation. + */ + private static void testCase5_ExplicitlyEnableErrataEnablesDeferred() throws Exception { + if (!isAffected) { + System.out.println("\nTest case 5: Skipping since CPU is not affected by Neoverse N1 errata 1542419"); + return; + } + + System.out.println("\nTest case 5: Explicitly enable NeoverseN1ICacheErratumMitigation, check UseSingleICacheInvalidation"); + + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+NeoverseN1ICacheErratumMitigation", + "-XX:+PrintFlagsFinal", + "-version"); + + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldHaveExitValue(0); + + String output_str = output.getOutput(); + boolean hasSingleEnabled = output_str.matches("(?s).*bool\\s+UseSingleICacheInvalidation\\s*=\\s*true.*"); + boolean hasErrataEnabled = output_str.matches("(?s).*bool\\s+NeoverseN1ICacheErratumMitigation\\s*=\\s*true.*"); + + System.out.println("NeoverseN1ICacheErratumMitigation enabled: " + hasErrataEnabled); + System.out.println("UseSingleICacheInvalidation enabled: " + hasSingleEnabled); + + if (!hasErrataEnabled) { + throw new RuntimeException("Failed to enable NeoverseN1ICacheErratumMitigation via command line"); + } + + if (!hasSingleEnabled) { + throw new RuntimeException("On affected CPU, enabling NeoverseN1ICacheErratumMitigation should also enable UseSingleICacheInvalidation"); + } + System.out.println("Correctly synchronized on affected CPU"); + } + + /** + * Test case 6: Check both flags can be explicitly set to false. + */ + private static void testCase6_ExplicitlyDisableBothFlags() throws Exception { + System.out.println("\nTest case 6: Explicitly disable both flags"); + + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( + "-XX:+UnlockDiagnosticVMOptions", + "-XX:-UseSingleICacheInvalidation", + "-XX:-NeoverseN1ICacheErratumMitigation", + "-XX:+PrintFlagsFinal", + "-version"); + + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldHaveExitValue(0); + + String output_str = output.getOutput(); + boolean hasSingleDisabled = output_str.matches("(?s).*bool\\s+UseSingleICacheInvalidation\\s*=\\s*false.*"); + boolean hasErrataDisabled = output_str.matches("(?s).*bool\\s+NeoverseN1ICacheErratumMitigation\\s*=\\s*false.*"); + + System.out.println("UseSingleICacheInvalidation disabled: " + hasSingleDisabled); + System.out.println("NeoverseN1ICacheErratumMitigation disabled: " + hasErrataDisabled); + + if (!hasErrataDisabled) { + throw new RuntimeException("Failed to disable NeoverseN1ICacheErratumMitigation via command line"); + } + + if (!hasSingleDisabled) { + throw new RuntimeException("Failed to disable UseSingleICacheInvalidation via command line"); + } + + System.out.println("Successfully disabled both flags"); + } + + /** + * Test case 7: Check UseSingleICacheInvalidation=false with NeoverseN1ICacheErratumMitigation=true. + * On affected CPUs, this should error (conflicting requirement). + */ + private static void testCase7_ConflictingErrataWithoutDeferred() throws Exception { + if (!isAffected) { + System.out.println("\nTest case 7: Skipping since CPU is not affected by Neoverse N1 errata 1542419"); + return; + } + System.out.println("\nTest case 7: Try to set NeoverseN1ICacheErratumMitigation=true with UseSingleICacheInvalidation=false"); + + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( + "-XX:+UnlockDiagnosticVMOptions", + "-XX:-UseSingleICacheInvalidation", + "-XX:+NeoverseN1ICacheErratumMitigation", + "-XX:+PrintFlagsFinal", + "-version"); + + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + + // This should fail on affected CPUs (conflicting requirement) + if (output.getExitValue() == 0) { + throw new RuntimeException("On affected CPU, setting NeoverseN1ICacheErratumMitigation=true with UseSingleICacheInvalidation=false should cause an error"); + } + output.shouldContain("Error"); + System.out.println("JVM correctly rejected conflicting flags on affected CPU"); + } + + /** + * Test case 8: Check setting NeoverseN1ICacheErratumMitigation=true on unaffected CPU causes an error. + */ + private static void testCase8_EnablingErrataOnUnaffectedCPU() throws Exception { + if (isAffected) { + System.out.println("\nTest case 8: Skipping since CPU is affected by Neoverse N1 errata 1542419"); + return; + } + + System.out.println("\nTest case 8: Try to set NeoverseN1ICacheErratumMitigation=true on unaffected CPU"); + + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+NeoverseN1ICacheErratumMitigation", + "-version"); + + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + + // This should fail on unaffected CPUs (errata not present) + if (output.getExitValue() == 0) { + throw new RuntimeException("On unaffected CPU, setting NeoverseN1ICacheErratumMitigation=true should cause error"); + } + output.shouldContain("Error"); + System.out.println("JVM correctly rejected enabling errata flag on unaffected CPU"); + } +} diff --git a/test/hotspot/jtreg/gc/TestDeferredICacheInvalidation.java b/test/hotspot/jtreg/gc/TestDeferredICacheInvalidation.java new file mode 100644 index 00000000000..70cd1ab6d8c --- /dev/null +++ b/test/hotspot/jtreg/gc/TestDeferredICacheInvalidation.java @@ -0,0 +1,306 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package gc; + +/* + * @test id=parallel + * @bug 8370947 + * @summary Check no assertion is triggered when UseSingleICacheInvalidation is enabled for ParallelGC + * @library /test/lib + * @requires vm.debug + * @requires vm.gc.Parallel + * @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 -XX:+UseParallelGC -XX:-UseCodeCacheFlushing gc.TestDeferredICacheInvalidation youngGC C1 + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseParallelGC -XX:-UseCodeCacheFlushing gc.TestDeferredICacheInvalidation fullGC C1 + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseParallelGC -XX:-UseCodeCacheFlushing gc.TestDeferredICacheInvalidation youngGC C2 + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseParallelGC -XX:-UseCodeCacheFlushing gc.TestDeferredICacheInvalidation fullGC C2 + */ + +/* + * @test id=g1 + * @bug 8370947 + * @summary Check no assertion is triggered when UseSingleICacheInvalidation is enabled for G1GC + * @library /test/lib + * @requires vm.debug + * @requires vm.gc.G1 + * @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 -XX:+UseG1GC -XX:-UseCodeCacheFlushing gc.TestDeferredICacheInvalidation youngGC C1 + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseG1GC -XX:-UseCodeCacheFlushing gc.TestDeferredICacheInvalidation fullGC C1 + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseG1GC -XX:-UseCodeCacheFlushing gc.TestDeferredICacheInvalidation youngGC C2 + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseG1GC -XX:-UseCodeCacheFlushing gc.TestDeferredICacheInvalidation fullGC C2 + */ + +/* + * @test id=shenandoah + * @bug 8370947 + * @summary Check no assertion is triggered when UseSingleICacheInvalidation is enabled for ShenandoahGC + * @library /test/lib + * @requires vm.debug + * @requires vm.gc.Shenandoah + * @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 -XX:+UseShenandoahGC -XX:-UseCodeCacheFlushing gc.TestDeferredICacheInvalidation fullGC C1 + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseShenandoahGC -XX:-UseCodeCacheFlushing gc.TestDeferredICacheInvalidation fullGC C2 + */ + +/* + * @test id=genshen + * @bug 8370947 + * @summary Check no assertion is triggered when UseSingleICacheInvalidation is enabled for generational ShenandoahGC + * @library /test/lib + * @requires vm.debug + * @requires vm.gc.Shenandoah + * @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 -XX:+UseShenandoahGC -XX:+UnlockExperimentalVMOptions -XX:ShenandoahGCMode=generational -XX:-UseCodeCacheFlushing gc.TestDeferredICacheInvalidation youngGC C1 + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseShenandoahGC -XX:+UnlockExperimentalVMOptions -XX:ShenandoahGCMode=generational -XX:-UseCodeCacheFlushing gc.TestDeferredICacheInvalidation fullGC C1 + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseShenandoahGC -XX:+UnlockExperimentalVMOptions -XX:ShenandoahGCMode=generational -XX:-UseCodeCacheFlushing gc.TestDeferredICacheInvalidation youngGC C2 + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseShenandoahGC -XX:+UnlockExperimentalVMOptions -XX:ShenandoahGCMode=generational -XX:-UseCodeCacheFlushing gc.TestDeferredICacheInvalidation fullGC C2 + */ + +/* + * @test id=z + * @bug 8370947 + * @summary Check no assertion is triggered when UseSingleICacheInvalidation is enabled for ZGC + * @library /test/lib + * @requires vm.debug + * @requires vm.gc.Z + * @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 -XX:+UseZGC -XX:-UseCodeCacheFlushing gc.TestDeferredICacheInvalidation youngGC C1 + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseZGC -XX:-UseCodeCacheFlushing gc.TestDeferredICacheInvalidation fullGC C1 + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseZGC -XX:-UseCodeCacheFlushing gc.TestDeferredICacheInvalidation youngGC C2 + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseZGC -XX:-UseCodeCacheFlushing gc.TestDeferredICacheInvalidation fullGC C2 + */ + +/* + * Nmethods have GC barriers and OOPs embedded into their code. GCs can patch nmethod's code + * which requires icache invalidation. Doing invalidation per instruction can be expensive. + * CPU can support hardware dcache and icache coherence. This would allow to defer cache + * invalidation. + * + * There are assertions for deferred cache invalidation. This test checks that all of them + * are passed. + */ + +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +import jdk.test.whitebox.WhiteBox; + +public class TestDeferredICacheInvalidation { + + private static final WhiteBox WB = WhiteBox.getWhiteBox(); + + public static class A { + public String s1; + public String s2; + public String s3; + public String s4; + public String s5; + public String s6; + public String s7; + public String s8; + public String s9; + } + + public static A a = new A(); + + private static int compLevel; + + public static class B { + public static void test0() { + } + + public static void test1() { + a.s1 = a.s1 + "1"; + } + + public static void test2() { + a.s1 = a.s1 + "1"; + a.s2 = a.s2 + "2"; + } + + public static void test3() { + a.s1 = a.s1 + "1"; + a.s2 = a.s2 + "2"; + a.s3 = a.s3 + "3"; + } + + public static void test4() { + a.s1 = a.s1 + "1"; + a.s2 = a.s2 + "2"; + a.s3 = a.s3 + "3"; + a.s4 = a.s4 + "4"; + } + + public static void test5() { + a.s1 = a.s1 + "1"; + a.s2 = a.s2 + "2"; + a.s3 = a.s3 + "3"; + a.s4 = a.s4 + "4"; + a.s5 = a.s5 + "5"; + } + + public static void test6() { + a.s1 = a.s1 + "1"; + a.s2 = a.s2 + "2"; + a.s3 = a.s3 + "3"; + a.s4 = a.s4 + "4"; + a.s5 = a.s5 + "5"; + a.s6 = a.s6 + "6"; + } + + public static void test7() { + a.s1 = a.s1 + "1"; + a.s2 = a.s2 + "2"; + a.s3 = a.s3 + "3"; + a.s4 = a.s4 + "4"; + a.s5 = a.s5 + "5"; + a.s6 = a.s6 + "6"; + a.s7 = a.s7 + "7"; + } + + public static void test8() { + a.s1 = a.s1 + "1"; + a.s2 = a.s2 + "2"; + a.s3 = a.s3 + "3"; + a.s4 = a.s4 + "4"; + a.s5 = a.s5 + "5"; + a.s6 = a.s6 + "6"; + a.s7 = a.s7 + "7"; + a.s8 = a.s8 + "8"; + } + + public static void test9() { + a.s1 = a.s1 + "1"; + a.s2 = a.s2 + "2"; + a.s3 = a.s3 + "3"; + a.s4 = a.s4 + "4"; + a.s5 = a.s5 + "5"; + a.s6 = a.s6 + "6"; + a.s7 = a.s7 + "7"; + a.s8 = a.s8 + "8"; + a.s9 = a.s9 + "9"; + } + } + + private static void compileMethods() throws Exception { + for (var m : B.class.getDeclaredMethods()) { + if (!m.getName().startsWith("test")) { + continue; + } + m.invoke(null); + WB.markMethodProfiled(m); + WB.enqueueMethodForCompilation(m, compLevel); + while (WB.isMethodQueuedForCompilation(m)) { + Thread.sleep(100); + } + if (WB.getMethodCompilationLevel(m) != compLevel) { + throw new IllegalStateException("Method " + m + " is not compiled at the compilation level: " + compLevel + ". Got: " + WB.getMethodCompilationLevel(m)); + } + } + } + + public static void youngGC() throws Exception { + a = null; + WB.youngGC(); + } + + public static void fullGC() throws Exception { + // Thread synchronization + final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock(); + final ReentrantReadWriteLock.ReadLock readLock = rwLock.readLock(); + final ReentrantReadWriteLock.WriteLock writeLock = rwLock.writeLock(); + final AtomicBoolean running = new AtomicBoolean(true); + + // Thread 1: GC thread that runs for 1 second with 100ms sleep intervals + Thread gcThread = new Thread(() -> { + final long startTime = System.currentTimeMillis(); + final long duration = 1000; + try { + while (System.currentTimeMillis() - startTime < duration) { + writeLock.lock(); + try { + a = new A(); + WB.fullGC(); + } finally { + writeLock.unlock(); + } + Thread.sleep(100); + } + } catch (InterruptedException e) { + // Thread interrupted, exit + } + running.set(false); + }); + + // Threads 2-11: Test threads that execute test0() through test9() + Thread[] testThreads = new Thread[10]; + for (int i = 0; i < 10; i++) { + final int testIdx = i; + testThreads[i] = new Thread(() -> { + try { + var method = B.class.getDeclaredMethod("test" + testIdx); + while (running.get()) { + readLock.lock(); + try { + method.invoke(null); + } finally { + readLock.unlock(); + } + } + } catch (Exception e) { + e.printStackTrace(); + System.exit(10); + } + }); + } + + // Start all threads + gcThread.start(); + for (Thread t : testThreads) { + t.start(); + } + + // Wait for all threads to complete + gcThread.join(); + for (Thread t : testThreads) { + t.join(); + } + } + + public static void main(String[] args) throws Exception { + if (!Boolean.TRUE.equals(WB.getBooleanVMFlag("UseSingleICacheInvalidation"))) { + System.out.println("Skip. Test requires UseSingleICacheInvalidation enabled."); + return; + } + compLevel = (args[1].equals("C1")) ? 1 : 4; + compileMethods(); + TestDeferredICacheInvalidation.class.getMethod(args[0]).invoke(null); + } +} diff --git a/test/micro/org/openjdk/bench/vm/gc/GCPatchingNmethodCost.java b/test/micro/org/openjdk/bench/vm/gc/GCPatchingNmethodCost.java new file mode 100644 index 00000000000..53fa2378ead --- /dev/null +++ b/test/micro/org/openjdk/bench/vm/gc/GCPatchingNmethodCost.java @@ -0,0 +1,206 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.openjdk.bench.vm.gc; + +import java.lang.reflect.Method; +import java.util.*; +import java.util.concurrent.TimeUnit; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.CompilerControl; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; + +import org.openjdk.bench.util.InMemoryJavaCompiler; + +import jdk.test.whitebox.WhiteBox; +import jdk.test.whitebox.code.NMethod; + +/* + * Nmethods have OOPs and GC barriers emmedded into their code. + * GCs patch them which causes invalidation of nmethods' code. + * + * This benchmark can be used to estimate the cost of patching + * OOPs and GC barriers. + * + * We create 5000 nmethods which access fields of a class. + * We measure the time of different GC cycles to see + * the impact of patching nmethods. + * + * The benchmark parameters are method count and accessed field count. + */ + +@BenchmarkMode(Mode.SingleShotTime) +@OutputTimeUnit(TimeUnit.MILLISECONDS) +@State(Scope.Benchmark) +@Fork(value = 1, jvmArgsAppend = { + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+UnlockExperimentalVMOptions", + "-XX:+WhiteBoxAPI", + "-Xbootclasspath/a:lib-test/wb.jar", + "-XX:-UseCodeCacheFlushing" +}) +@Warmup(iterations = 5) +@Measurement(iterations = 5) +public class GCPatchingNmethodCost { + + private static final int COMP_LEVEL = 1; + private static final String FIELD_USER = "FieldUser"; + + public static Fields fields; + + private static TestMethod[] methods = {}; + private static byte[] BYTE_CODE; + private static WhiteBox WB; + + @Param({"5000"}) + public int methodCount; + + @Param({"0", "2", "4", "8"}) + public int accessedFieldCount; + + public static class Fields { + public String f1; + public String f2; + public String f3; + public String f4; + public String f5; + public String f6; + public String f7; + public String f8; + public String f9; + } + + private static final class TestMethod { + private final Method method; + + public TestMethod(Method method) throws Exception { + this.method = method; + WB.testSetDontInlineMethod(method, true); + } + + public void profile() throws Exception { + method.invoke(null); + WB.markMethodProfiled(method); + } + + public void invoke() throws Exception { + method.invoke(null); + } + + public void compile() throws Exception { + WB.enqueueMethodForCompilation(method, COMP_LEVEL); + while (WB.isMethodQueuedForCompilation(method)) { + Thread.onSpinWait(); + } + if (WB.getMethodCompilationLevel(method) != COMP_LEVEL) { + throw new IllegalStateException("Method " + method + " is not compiled at the compilation level: " + COMP_LEVEL + ". Got: " + WB.getMethodCompilationLevel(method)); + } + } + + public NMethod getNMethod() { + return NMethod.get(method, false); + } + } + + private static ClassLoader createClassLoader() { + return new ClassLoader() { + @Override + public Class loadClass(String name) throws ClassNotFoundException { + if (!name.equals(FIELD_USER)) { + return super.loadClass(name); + } + + return defineClass(name, BYTE_CODE, 0, BYTE_CODE.length); + } + }; + } + + private static void createTestMethods(int accessedFieldCount, int count) throws Exception { + String javaCode = "public class " + FIELD_USER + " {"; + String field = GCPatchingNmethodCost.class.getName() + ".fields.f"; + javaCode += "public static void accessFields() {"; + for (int i = 1; i <= accessedFieldCount; i++) { + javaCode += field + i + "= " + field + i + " + " + i + ";"; + } + javaCode += "}}"; + + BYTE_CODE = InMemoryJavaCompiler.compile(FIELD_USER, javaCode); + + fields = new Fields(); + + methods = new TestMethod[count]; + for (int i = 0; i < count; i++) { + var cl = createClassLoader().loadClass(FIELD_USER); + Method method = cl.getMethod("accessFields"); + methods[i] = new TestMethod(method); + methods[i].profile(); + methods[i].compile(); + } + } + + private static void initWhiteBox() { + WB = WhiteBox.getWhiteBox(); + } + + @Setup(Level.Trial) + public void setupCodeCache() throws Exception { + initWhiteBox(); + createTestMethods(accessedFieldCount, methodCount); + System.gc(); + } + + @Setup(Level.Iteration) + public void setupIteration() { + fields = new Fields(); + } + + @Benchmark + public void youngGC() throws Exception { + fields = null; + WB.youngGC(); + } + + @Benchmark + public void fullGC() throws Exception { + fields = null; + WB.fullGC(); + } + + @Benchmark + public void systemGC() throws Exception { + fields = null; + System.gc(); + } +} From 46e6b26bf8c3124bf4e0c5d26c3eb04e220bd0cb Mon Sep 17 00:00:00 2001 From: Saranya Natarajan Date: Wed, 25 Mar 2026 12:47:41 +0000 Subject: [PATCH 028/359] 8372646: C2: Stress Counted Loop creation Reviewed-by: rcastanedalo, chagedorn, dfenacci --- src/hotspot/share/opto/c2_globals.hpp | 3 +++ src/hotspot/share/opto/compile.cpp | 12 +++++++++--- src/hotspot/share/opto/loopnode.cpp | 15 +++++++++++++-- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/hotspot/share/opto/c2_globals.hpp b/src/hotspot/share/opto/c2_globals.hpp index e0833afa29d..a4f6d04f6a3 100644 --- a/src/hotspot/share/opto/c2_globals.hpp +++ b/src/hotspot/share/opto/c2_globals.hpp @@ -907,6 +907,9 @@ \ develop(bool, StressLoopPeeling, false, \ "Randomize loop peeling decision") \ + \ + develop(bool, StressCountedLoop, false, \ + "Randomly delay conversion to counted loops") \ // end of C2_FLAGS diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index f1ea8231df9..f34c75656a4 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -741,7 +741,7 @@ Compile::Compile(ciEnv* ci_env, ciMethod* target, int osr_bci, if (StressLCM || StressGCM || StressIGVN || StressCCP || StressIncrementalInlining || StressMacroExpansion || StressMacroElimination || StressUnstableIfTraps || - StressBailout || StressLoopPeeling) { + StressBailout || StressLoopPeeling || StressCountedLoop) { initialize_stress_seed(directive); } @@ -2257,7 +2257,9 @@ bool Compile::optimize_loops(PhaseIterGVN& igvn, LoopOptsMode mode) { PhaseIdealLoop::optimize(igvn, mode); _loop_opts_cnt--; if (failing()) return false; - if (major_progress()) print_method(PHASE_PHASEIDEALLOOP_ITERATIONS, 2); + if (major_progress()) { + print_method(PHASE_PHASEIDEALLOOP_ITERATIONS, 2); + } } } return true; @@ -3798,7 +3800,11 @@ void Compile::final_graph_reshaping_main_switch(Node* n, Final_Reshape_Counts& f } break; case Op_Loop: - assert(!n->as_Loop()->is_loop_nest_inner_loop() || _loop_opts_cnt == 0, "should have been turned into a counted loop"); + // When StressCountedLoop is enabled, this loop may intentionally avoid a counted loop conversion. + // This is expected behavior for the stress mode, which exercises alternative compilation paths. + if (!StressCountedLoop) { + assert(!n->as_Loop()->is_loop_nest_inner_loop() || _loop_opts_cnt == 0, "should have been turned into a counted loop"); + } case Op_CountedLoop: case Op_LongCountedLoop: case Op_OuterStripMinedLoop: diff --git a/src/hotspot/share/opto/loopnode.cpp b/src/hotspot/share/opto/loopnode.cpp index b2eb0c47458..686a0a05f66 100644 --- a/src/hotspot/share/opto/loopnode.cpp +++ b/src/hotspot/share/opto/loopnode.cpp @@ -2137,7 +2137,6 @@ bool CountedLoopConverter::is_counted_loop() { } assert(_head->Opcode() == Op_Loop || _head->Opcode() == Op_LongCountedLoop, "regular loops only"); - _phase->C->print_method(PHASE_BEFORE_CLOOPS, 3, _head); // =================================================== // We can only convert this loop to a counted loop if we can guarantee that the iv phi will never overflow at runtime. @@ -2411,6 +2410,12 @@ bool CountedLoopConverter::is_counted_loop() { _checked_for_counted_loop = true; #endif +#ifndef PRODUCT + if (StressCountedLoop && (_phase->C->random() % 2 == 0)) { + return false; + } +#endif + return true; } @@ -2553,6 +2558,8 @@ IdealLoopTree* CountedLoopConverter::convert() { PhaseIterGVN* igvn = &_phase->igvn(); + _phase->C->print_method(PHASE_BEFORE_CLOOPS, 3, _head); + if (_should_insert_stride_overflow_limit_check) { insert_stride_overflow_limit_check(); } @@ -4734,7 +4741,11 @@ void IdealLoopTree::counted_loop( PhaseIdealLoop *phase ) { } else if (_head->is_LongCountedLoop() || phase->try_convert_to_counted_loop(_head, loop, T_LONG)) { remove_safepoints(phase, true); } else { - assert(!_head->is_Loop() || !_head->as_Loop()->is_loop_nest_inner_loop(), "transformation to counted loop should not fail"); + // When StressCountedLoop is enabled, this loop may intentionally avoid a counted loop conversion. + // This is expected behavior for the stress mode, which exercises alternative compilation paths. + if (!StressCountedLoop) { + assert(!_head->is_Loop() || !_head->as_Loop()->is_loop_nest_inner_loop(), "transformation to counted loop should not fail"); + } if (_parent != nullptr && !_irreducible) { // Not a counted loop. Keep one safepoint. bool keep_one_sfpt = true; From 6466d9809c80bdf1353b36efc67f7977ee4f45b6 Mon Sep 17 00:00:00 2001 From: Frederic Thevenet Date: Wed, 25 Mar 2026 13:11:02 +0000 Subject: [PATCH 029/359] 8380776: No longer necessary to disable calloc-transposed-args warnings when building harfbuzz Reviewed-by: erikj, kbarrett, jwaters, aivanov --- make/modules/java.desktop/lib/ClientLibraries.gmk | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/make/modules/java.desktop/lib/ClientLibraries.gmk b/make/modules/java.desktop/lib/ClientLibraries.gmk index b76cb8dc4e3..13a74ab409f 100644 --- a/make/modules/java.desktop/lib/ClientLibraries.gmk +++ b/make/modules/java.desktop/lib/ClientLibraries.gmk @@ -338,11 +338,8 @@ else # noexcept-type required for GCC 7 builds. Not required for GCC 8+. # expansion-to-defined required for GCC 9 builds. Not required for GCC 10+. # maybe-uninitialized required for GCC 8 builds. Not required for GCC 9+. - # calloc-transposed-args required for GCC 14 builds. (fixed upstream in - # Harfbuzz 032c931e1c0cfb20f18e5acb8ba005775242bd92) HARFBUZZ_DISABLED_WARNINGS_CXX_gcc := class-memaccess noexcept-type \ - expansion-to-defined dangling-reference maybe-uninitialized \ - calloc-transposed-args + expansion-to-defined dangling-reference maybe-uninitialized HARFBUZZ_DISABLED_WARNINGS_clang := missing-field-initializers \ range-loop-analysis unused-variable HARFBUZZ_DISABLED_WARNINGS_microsoft := 4267 4244 From 4dca6e4ca89e3468c48247ddc7fabab769b72ee0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20Sikstr=C3=B6m?= Date: Wed, 25 Mar 2026 14:01:26 +0000 Subject: [PATCH 030/359] 8380903: [BACKOUT] Mitigate Neoverse-N1 erratum 1542419 negative impact on GCs and JIT performance Reviewed-by: aboldtch --- .../gc/z/zBarrierSetAssembler_aarch64.cpp | 4 +- src/hotspot/cpu/aarch64/globals_aarch64.hpp | 2 - src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp | 7 +- .../cpu/aarch64/vm_version_aarch64.cpp | 45 -- .../cpu/aarch64/vm_version_aarch64.hpp | 5 - .../linux_aarch64/icache_linux_aarch64.cpp | 28 -- .../linux_aarch64/icache_linux_aarch64.hpp | 101 +---- .../vm_version_linux_aarch64.cpp | 2 - src/hotspot/share/asm/codeBuffer.cpp | 3 + src/hotspot/share/code/codeBlob.cpp | 6 - src/hotspot/share/code/nmethod.cpp | 32 +- src/hotspot/share/code/nmethod.hpp | 7 +- src/hotspot/share/code/relocInfo.cpp | 9 + src/hotspot/share/code/relocInfo.hpp | 2 + src/hotspot/share/gc/z/zBarrierSetNMethod.cpp | 14 +- src/hotspot/share/gc/z/zGeneration.cpp | 14 +- src/hotspot/share/gc/z/zMark.cpp | 31 +- src/hotspot/share/gc/z/zNMethod.cpp | 16 +- src/hotspot/share/gc/z/zNMethod.hpp | 2 - src/hotspot/share/runtime/globals.hpp | 2 - src/hotspot/share/runtime/icache.hpp | 23 - ...tDeferredICacheInvalidationCmdOptions.java | 426 ------------------ .../gc/TestDeferredICacheInvalidation.java | 306 ------------- .../bench/vm/gc/GCPatchingNmethodCost.java | 206 --------- 24 files changed, 49 insertions(+), 1244 deletions(-) delete mode 100644 src/hotspot/os_cpu/linux_aarch64/icache_linux_aarch64.cpp delete mode 100644 test/hotspot/jtreg/compiler/runtime/TestDeferredICacheInvalidationCmdOptions.java delete mode 100644 test/hotspot/jtreg/gc/TestDeferredICacheInvalidation.java delete mode 100644 test/micro/org/openjdk/bench/vm/gc/GCPatchingNmethodCost.java diff --git a/src/hotspot/cpu/aarch64/gc/z/zBarrierSetAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/z/zBarrierSetAssembler_aarch64.cpp index f0885fee93d..4f0977a414f 100644 --- a/src/hotspot/cpu/aarch64/gc/z/zBarrierSetAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/gc/z/zBarrierSetAssembler_aarch64.cpp @@ -879,9 +879,7 @@ void ZBarrierSetAssembler::patch_barrier_relocation(address addr, int format) { ShouldNotReachHere(); } - if (!UseSingleICacheInvalidation) { - ICache::invalidate_word((address)patch_addr); - } + ICache::invalidate_word((address)patch_addr); } #ifdef COMPILER1 diff --git a/src/hotspot/cpu/aarch64/globals_aarch64.hpp b/src/hotspot/cpu/aarch64/globals_aarch64.hpp index ba29646a828..e6de2c798b1 100644 --- a/src/hotspot/cpu/aarch64/globals_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/globals_aarch64.hpp @@ -127,8 +127,6 @@ define_pd_global(intx, InlineSmallCode, 1000); "Branch Protection to use: none, standard, pac-ret") \ product(bool, AlwaysMergeDMB, true, DIAGNOSTIC, \ "Always merge DMB instructions in code emission") \ - product(bool, NeoverseN1ICacheErratumMitigation, false, DIAGNOSTIC, \ - "Enable workaround for Neoverse N1 erratum 1542419") \ // end of ARCH_FLAGS diff --git a/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp b/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp index f1b9fb213a2..dbec2d76d4f 100644 --- a/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp @@ -54,12 +54,7 @@ void Relocation::pd_set_data_value(address x, bool verify_only) { bytes = MacroAssembler::pd_patch_instruction_size(addr(), x); break; } - - if (UseSingleICacheInvalidation) { - assert(_binding != nullptr, "expect to be called with RelocIterator in use"); - } else { - ICache::invalidate_range(addr(), bytes); - } + ICache::invalidate_range(addr(), bytes); } address Relocation::pd_call_destination(address orig_addr) { diff --git a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp index 0a40cd705cd..4423d9c5b58 100644 --- a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp @@ -52,9 +52,6 @@ uintptr_t VM_Version::_pac_mask; SpinWait VM_Version::_spin_wait; -bool VM_Version::_cache_dic_enabled; -bool VM_Version::_cache_idc_enabled; - const char* VM_Version::_features_names[MAX_CPU_FEATURES] = { nullptr }; static SpinWait get_spin_wait_desc() { @@ -66,19 +63,6 @@ static SpinWait get_spin_wait_desc() { return spin_wait; } -static bool has_neoverse_n1_errata_1542419() { - const int major_rev_num = VM_Version::cpu_variant(); - const int minor_rev_num = VM_Version::cpu_revision(); - // Neoverse N1: 0xd0c - // Erratum 1542419 affects r3p0, r3p1 and r4p0. - // It is fixed in r4p1 and later revisions, which are not affected. - return (VM_Version::cpu_family() == VM_Version::CPU_ARM && - VM_Version::model_is(0xd0c) && - ((major_rev_num == 3 && minor_rev_num == 0) || - (major_rev_num == 3 && minor_rev_num == 1) || - (major_rev_num == 4 && minor_rev_num == 0))); -} - void VM_Version::initialize() { #define SET_CPU_FEATURE_NAME(id, name, bit) \ _features_names[bit] = XSTR(name); @@ -90,9 +74,6 @@ void VM_Version::initialize() { _supports_atomic_getset8 = true; _supports_atomic_getadd8 = true; - _cache_dic_enabled = false; - _cache_idc_enabled = false; - get_os_cpu_info(); int dcache_line = VM_Version::dcache_line_size(); @@ -680,32 +661,6 @@ void VM_Version::initialize() { clear_feature(CPU_SVE); } - if (FLAG_IS_DEFAULT(UseSingleICacheInvalidation) && is_cache_idc_enabled() && is_cache_dic_enabled()) { - FLAG_SET_DEFAULT(UseSingleICacheInvalidation, true); - } - - if (FLAG_IS_DEFAULT(NeoverseN1ICacheErratumMitigation) && has_neoverse_n1_errata_1542419()) { - FLAG_SET_DEFAULT(NeoverseN1ICacheErratumMitigation, true); - } - - if (NeoverseN1ICacheErratumMitigation) { - if (!has_neoverse_n1_errata_1542419()) { - vm_exit_during_initialization("NeoverseN1ICacheErratumMitigation is set for the CPU not having Neoverse N1 errata 1542419"); - } - if (FLAG_IS_DEFAULT(UseSingleICacheInvalidation)) { - FLAG_SET_DEFAULT(UseSingleICacheInvalidation, true); - } - - if (!UseSingleICacheInvalidation) { - vm_exit_during_initialization("NeoverseN1ICacheErratumMitigation is set but UseSingleICacheInvalidation is not enabled"); - } - } - - if (UseSingleICacheInvalidation - && (!is_cache_idc_enabled() || (!is_cache_dic_enabled() && !NeoverseN1ICacheErratumMitigation))) { - vm_exit_during_initialization("UseSingleICacheInvalidation is set but neither IDC nor DIC nor NeoverseN1ICacheErratumMitigation is enabled"); - } - // Construct the "features" string stringStream ss(512); ss.print("0x%02x:0x%x:0x%03x:%d", _cpu, _variant, _model, _revision); diff --git a/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp b/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp index 6145990d0d6..e8681611234 100644 --- a/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp @@ -58,8 +58,6 @@ protected: // When _prefer_sve_merging_mode_cpy is true, `cpy (imm, zeroing)` is // implemented as `movi; cpy(imm, merging)`. static constexpr bool _prefer_sve_merging_mode_cpy = true; - static bool _cache_dic_enabled; - static bool _cache_idc_enabled; static SpinWait _spin_wait; @@ -255,9 +253,6 @@ public: return vector_length_in_bytes <= 16; } - static bool is_cache_dic_enabled() { return _cache_dic_enabled; } - static bool is_cache_idc_enabled() { return _cache_idc_enabled; } - static void get_cpu_features_name(void* features_buffer, stringStream& ss); // Returns names of features present in features_set1 but not in features_set2 diff --git a/src/hotspot/os_cpu/linux_aarch64/icache_linux_aarch64.cpp b/src/hotspot/os_cpu/linux_aarch64/icache_linux_aarch64.cpp deleted file mode 100644 index 41cad5af325..00000000000 --- a/src/hotspot/os_cpu/linux_aarch64/icache_linux_aarch64.cpp +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#include "runtime/icache.hpp" -#include "utilities/globalDefinitions.hpp" - -NOT_PRODUCT(THREAD_LOCAL AArch64ICacheInvalidationContext* AArch64ICacheInvalidationContext::_current_context = nullptr;) diff --git a/src/hotspot/os_cpu/linux_aarch64/icache_linux_aarch64.hpp b/src/hotspot/os_cpu/linux_aarch64/icache_linux_aarch64.hpp index b410aebed7b..8fbaa7a6b6e 100644 --- a/src/hotspot/os_cpu/linux_aarch64/icache_linux_aarch64.hpp +++ b/src/hotspot/os_cpu/linux_aarch64/icache_linux_aarch64.hpp @@ -26,10 +26,6 @@ #ifndef OS_CPU_LINUX_AARCH64_ICACHE_AARCH64_HPP #define OS_CPU_LINUX_AARCH64_ICACHE_AARCH64_HPP -#include "memory/allocation.hpp" -#include "runtime/vm_version.hpp" -#include "utilities/globalDefinitions.hpp" - // Interface for updating the instruction cache. Whenever the VM // modifies code, part of the processor instruction cache potentially // has to be flushed. @@ -41,103 +37,8 @@ class ICache : public AbstractICache { __builtin___clear_cache((char *)addr, (char *)(addr + 4)); } static void invalidate_range(address start, int nbytes) { - if (NeoverseN1ICacheErratumMitigation) { - assert(VM_Version::is_cache_idc_enabled(), - "Expect CTR_EL0.IDC to be enabled for Neoverse N1 with erratum " - "1542419"); - assert(!VM_Version::is_cache_dic_enabled(), - "Expect CTR_EL0.DIC to be disabled for Neoverse N1 with erratum " - "1542419"); - asm volatile("dsb ish \n" - "ic ivau, xzr \n" - "dsb ish \n" - "isb \n" - : : : "memory"); - } else { - __builtin___clear_cache((char *)start, (char *)(start + nbytes)); - } + __builtin___clear_cache((char *)start, (char *)(start + nbytes)); } }; -class AArch64ICacheInvalidationContext : StackObj { - private: - -#ifdef ASSERT - static THREAD_LOCAL AArch64ICacheInvalidationContext* _current_context; -#endif - - bool _has_modified_code; - - public: - NONCOPYABLE(AArch64ICacheInvalidationContext); - - AArch64ICacheInvalidationContext() - : _has_modified_code(false) { - assert(_current_context == nullptr, "nested ICacheInvalidationContext not supported"); -#ifdef ASSERT - _current_context = this; -#endif - } - - ~AArch64ICacheInvalidationContext() { - NOT_PRODUCT(_current_context = nullptr); - - if (!_has_modified_code || !UseSingleICacheInvalidation) { - return; - } - - assert(VM_Version::is_cache_idc_enabled(), "Expect CTR_EL0.IDC to be enabled"); - - asm volatile("dsb ish" : : : "memory"); - - if (NeoverseN1ICacheErratumMitigation) { - assert(!VM_Version::is_cache_dic_enabled(), - "Expect CTR_EL0.DIC to be disabled for Neoverse N1 with erratum " - "1542419"); - - // Errata 1542419: Neoverse N1 cores with the 'COHERENT_ICACHE' feature - // may fetch stale instructions when software depends on - // prefetch-speculation-protection instead of explicit synchronization. - // - // Neoverse-N1 implementation mitigates the errata 1542419 with a - // workaround: - // - Disable coherent icache. - // - Trap IC IVAU instructions. - // - Execute: - // - tlbi vae3is, xzr - // - dsb sy - // - Ignore trapped IC IVAU instructions. - // - // `tlbi vae3is, xzr` invalidates all translation entries (all VAs, all - // possible levels). It waits for all memory accesses using in-scope old - // translation information to complete before it is considered complete. - // - // As this workaround has significant overhead, Arm Neoverse N1 (MP050) - // Software Developer Errata Notice version 29.0 suggests: - // - // "Since one TLB inner-shareable invalidation is enough to avoid this - // erratum, the number of injected TLB invalidations should be minimized - // in the trap handler to mitigate the performance impact due to this - // workaround." - // As the address for icache invalidation is not relevant and - // IC IVAU instruction is ignored, we use XZR in it. - asm volatile( - "ic ivau, xzr \n" - "dsb ish \n" - : - : - : "memory"); - } else { - assert(VM_Version::is_cache_dic_enabled(), "Expect CTR_EL0.DIC to be enabled"); - } - asm volatile("isb" : : : "memory"); - } - - void set_has_modified_code() { - _has_modified_code = true; - } -}; - -#define PD_ICACHE_INVALIDATION_CONTEXT AArch64ICacheInvalidationContext - #endif // OS_CPU_LINUX_AARCH64_ICACHE_AARCH64_HPP diff --git a/src/hotspot/os_cpu/linux_aarch64/vm_version_linux_aarch64.cpp b/src/hotspot/os_cpu/linux_aarch64/vm_version_linux_aarch64.cpp index dad7161a3cb..1fe06dc640d 100644 --- a/src/hotspot/os_cpu/linux_aarch64/vm_version_linux_aarch64.cpp +++ b/src/hotspot/os_cpu/linux_aarch64/vm_version_linux_aarch64.cpp @@ -169,8 +169,6 @@ void VM_Version::get_os_cpu_info() { _icache_line_size = (1 << (ctr_el0 & 0x0f)) * 4; _dcache_line_size = (1 << ((ctr_el0 >> 16) & 0x0f)) * 4; - _cache_idc_enabled = ((ctr_el0 >> 28) & 0x1) != 0; - _cache_dic_enabled = ((ctr_el0 >> 29) & 0x1) != 0; if (!(dczid_el0 & 0x10)) { _zva_length = 4 << (dczid_el0 & 0xf); diff --git a/src/hotspot/share/asm/codeBuffer.cpp b/src/hotspot/share/asm/codeBuffer.cpp index 964aec8b501..ba525588f32 100644 --- a/src/hotspot/share/asm/codeBuffer.cpp +++ b/src/hotspot/share/asm/codeBuffer.cpp @@ -745,6 +745,9 @@ void CodeBuffer::copy_code_to(CodeBlob* dest_blob) { // Done moving code bytes; were they the right size? assert((int)align_up(dest.total_content_size(), oopSize) == dest_blob->content_size(), "sanity"); + + // Flush generated code + ICache::invalidate_range(dest_blob->code_begin(), dest_blob->code_size()); } // Move all my code into another code buffer. Consult applicable diff --git a/src/hotspot/share/code/codeBlob.cpp b/src/hotspot/share/code/codeBlob.cpp index d07386bd795..fcc0b42a461 100644 --- a/src/hotspot/share/code/codeBlob.cpp +++ b/src/hotspot/share/code/codeBlob.cpp @@ -331,13 +331,7 @@ RuntimeBlob::RuntimeBlob( : CodeBlob(name, kind, cb, size, header_size, frame_complete, frame_size, oop_maps, caller_must_gc_arguments, align_up(cb->total_relocation_size(), oopSize)) { - if (code_size() == 0) { - // Nothing to copy - return; - } - cb->copy_code_and_locs_to(this); - ICache::invalidate_range(code_begin(), code_size()); } void RuntimeBlob::free(RuntimeBlob* blob) { diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 5cb795a4723..5a6ed8ab3ed 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1328,7 +1328,6 @@ nmethod::nmethod( code_buffer->copy_values_to(this); post_init(); - ICache::invalidate_range(code_begin(), code_size()); } if (PrintNativeNMethods || PrintDebugInfo || PrintRelocations || PrintDependencies) { @@ -1810,7 +1809,6 @@ nmethod::nmethod( init_immutable_data_ref_count(); post_init(); - ICache::invalidate_range(code_begin(), code_size()); // we use the information of entry points to find out if a method is // static or non static @@ -2038,7 +2036,7 @@ void nmethod::copy_values(GrowableArray* array) { // The code and relocations have already been initialized by the // CodeBlob constructor, so it is valid even at this early point to // iterate over relocations and patch the code. - fix_oop_relocations(/*initialize_immediates=*/ true); + fix_oop_relocations(nullptr, nullptr, /*initialize_immediates=*/ true); } void nmethod::copy_values(GrowableArray* array) { @@ -2050,42 +2048,24 @@ void nmethod::copy_values(GrowableArray* array) { } } -bool nmethod::fix_oop_relocations(bool initialize_immediates) { +void nmethod::fix_oop_relocations(address begin, address end, bool initialize_immediates) { // re-patch all oop-bearing instructions, just in case some oops moved - RelocIterator iter(this); - bool modified_code = false; + RelocIterator iter(this, begin, end); while (iter.next()) { if (iter.type() == relocInfo::oop_type) { oop_Relocation* reloc = iter.oop_reloc(); - if (!reloc->oop_is_immediate()) { - // Refresh the oop-related bits of this instruction. - reloc->set_value(reloc->value()); - modified_code = true; - } else if (initialize_immediates) { + if (initialize_immediates && reloc->oop_is_immediate()) { oop* dest = reloc->oop_addr(); jobject obj = *reinterpret_cast(dest); initialize_immediate_oop(dest, obj); } + // Refresh the oop-related bits of this instruction. + reloc->fix_oop_relocation(); } else if (iter.type() == relocInfo::metadata_type) { metadata_Relocation* reloc = iter.metadata_reloc(); reloc->fix_metadata_relocation(); - modified_code |= !reloc->metadata_is_immediate(); } } - return modified_code; -} - -void nmethod::fix_oop_relocations() { - ICacheInvalidationContext icic; - fix_oop_relocations(&icic); -} - -void nmethod::fix_oop_relocations(ICacheInvalidationContext* icic) { - assert(icic != nullptr, "must provide context to track if code was modified"); - bool modified_code = fix_oop_relocations(/*initialize_immediates=*/ false); - if (modified_code) { - icic->set_has_modified_code(); - } } static void install_post_call_nop_displacement(nmethod* nm, address pc) { diff --git a/src/hotspot/share/code/nmethod.hpp b/src/hotspot/share/code/nmethod.hpp index ea8c0e2ad5d..092da181f12 100644 --- a/src/hotspot/share/code/nmethod.hpp +++ b/src/hotspot/share/code/nmethod.hpp @@ -41,7 +41,6 @@ class Dependencies; class DirectiveSet; class DebugInformationRecorder; class ExceptionHandlerTable; -class ICacheInvalidationContext; class ImplicitExceptionTable; class JvmtiThreadState; class MetadataClosure; @@ -802,15 +801,15 @@ public: // Relocation support private: - bool fix_oop_relocations(bool initialize_immediates); + void fix_oop_relocations(address begin, address end, bool initialize_immediates); inline void initialize_immediate_oop(oop* dest, jobject handle); protected: address oops_reloc_begin() const; public: - void fix_oop_relocations(ICacheInvalidationContext* icic); - void fix_oop_relocations(); + void fix_oop_relocations(address begin, address end) { fix_oop_relocations(begin, end, false); } + void fix_oop_relocations() { fix_oop_relocations(nullptr, nullptr, false); } bool is_at_poll_return(address pc); bool is_at_poll_or_poll_return(address pc); diff --git a/src/hotspot/share/code/relocInfo.cpp b/src/hotspot/share/code/relocInfo.cpp index 25d91edc20f..2a6335e2118 100644 --- a/src/hotspot/share/code/relocInfo.cpp +++ b/src/hotspot/share/code/relocInfo.cpp @@ -590,6 +590,15 @@ oop oop_Relocation::oop_value() { return *oop_addr(); } + +void oop_Relocation::fix_oop_relocation() { + if (!oop_is_immediate()) { + // get the oop from the pool, and re-insert it into the instruction: + set_value(value()); + } +} + + void oop_Relocation::verify_oop_relocation() { if (!oop_is_immediate()) { // get the oop from the pool, and re-insert it into the instruction: diff --git a/src/hotspot/share/code/relocInfo.hpp b/src/hotspot/share/code/relocInfo.hpp index bb2b2b5693f..6f1778ef479 100644 --- a/src/hotspot/share/code/relocInfo.hpp +++ b/src/hotspot/share/code/relocInfo.hpp @@ -988,6 +988,8 @@ class oop_Relocation : public DataRelocation { void pack_data_to(CodeSection* dest) override; void unpack_data() override; + void fix_oop_relocation(); // reasserts oop value + void verify_oop_relocation(); address value() override { return *reinterpret_cast(oop_addr()); } diff --git a/src/hotspot/share/gc/z/zBarrierSetNMethod.cpp b/src/hotspot/share/gc/z/zBarrierSetNMethod.cpp index a439b3a167b..d80ce4e149d 100644 --- a/src/hotspot/share/gc/z/zBarrierSetNMethod.cpp +++ b/src/hotspot/share/gc/z/zBarrierSetNMethod.cpp @@ -33,7 +33,6 @@ #include "gc/z/zThreadLocalData.hpp" #include "gc/z/zUncoloredRoot.inline.hpp" #include "logging/log.hpp" -#include "runtime/icache.hpp" #include "runtime/threadWXSetters.inline.hpp" bool ZBarrierSetNMethod::nmethod_entry_barrier(nmethod* nm) { @@ -71,15 +70,12 @@ bool ZBarrierSetNMethod::nmethod_entry_barrier(nmethod* nm) { return false; } - { - ICacheInvalidationContext icic; - // Heal barriers - ZNMethod::nmethod_patch_barriers(nm, &icic); + // Heal barriers + ZNMethod::nmethod_patch_barriers(nm); - // Heal oops - ZUncoloredRootProcessWeakOopClosure cl(ZNMethod::color(nm)); - ZNMethod::nmethod_oops_do_inner(nm, &cl, &icic); - } + // Heal oops + ZUncoloredRootProcessWeakOopClosure cl(ZNMethod::color(nm)); + ZNMethod::nmethod_oops_do_inner(nm, &cl); const uintptr_t prev_color = ZNMethod::color(nm); const uintptr_t new_color = *ZPointerStoreGoodMaskLowOrderBitsAddr; diff --git a/src/hotspot/share/gc/z/zGeneration.cpp b/src/hotspot/share/gc/z/zGeneration.cpp index 0f9f4e34a5e..27f352a624f 100644 --- a/src/hotspot/share/gc/z/zGeneration.cpp +++ b/src/hotspot/share/gc/z/zGeneration.cpp @@ -58,7 +58,6 @@ #include "prims/jvmtiTagMap.hpp" #include "runtime/continuation.hpp" #include "runtime/handshake.hpp" -#include "runtime/icache.hpp" #include "runtime/safepoint.hpp" #include "runtime/threads.hpp" #include "runtime/vmOperations.hpp" @@ -1435,15 +1434,12 @@ public: virtual void do_nmethod(nmethod* nm) { ZLocker locker(ZNMethod::lock_for_nmethod(nm)); if (_bs_nm->is_armed(nm)) { - { - ICacheInvalidationContext icic; - // Heal barriers - ZNMethod::nmethod_patch_barriers(nm, &icic); + // Heal barriers + ZNMethod::nmethod_patch_barriers(nm); - // Heal oops - ZUncoloredRootProcessOopClosure cl(ZNMethod::color(nm)); - ZNMethod::nmethod_oops_do_inner(nm, &cl, &icic); - } + // Heal oops + ZUncoloredRootProcessOopClosure cl(ZNMethod::color(nm)); + ZNMethod::nmethod_oops_do_inner(nm, &cl); log_trace(gc, nmethod)("nmethod: " PTR_FORMAT " visited by old remapping", p2i(nm)); diff --git a/src/hotspot/share/gc/z/zMark.cpp b/src/hotspot/share/gc/z/zMark.cpp index ac7d86db240..03701ae9998 100644 --- a/src/hotspot/share/gc/z/zMark.cpp +++ b/src/hotspot/share/gc/z/zMark.cpp @@ -59,7 +59,6 @@ #include "oops/oop.inline.hpp" #include "runtime/continuation.hpp" #include "runtime/handshake.hpp" -#include "runtime/icache.hpp" #include "runtime/javaThread.hpp" #include "runtime/prefetch.inline.hpp" #include "runtime/safepointMechanism.hpp" @@ -719,15 +718,12 @@ public: virtual void do_nmethod(nmethod* nm) { ZLocker locker(ZNMethod::lock_for_nmethod(nm)); if (_bs_nm->is_armed(nm)) { - { - ICacheInvalidationContext icic; - // Heal barriers - ZNMethod::nmethod_patch_barriers(nm, &icic); + // Heal barriers + ZNMethod::nmethod_patch_barriers(nm); - // Heal oops - ZUncoloredRootMarkOopClosure cl(ZNMethod::color(nm)); - ZNMethod::nmethod_oops_do_inner(nm, &cl, &icic); - } + // Heal oops + ZUncoloredRootMarkOopClosure cl(ZNMethod::color(nm)); + ZNMethod::nmethod_oops_do_inner(nm, &cl); // CodeCache unloading support nm->mark_as_maybe_on_stack(); @@ -757,6 +753,10 @@ public: if (_bs_nm->is_armed(nm)) { const uintptr_t prev_color = ZNMethod::color(nm); + // Heal oops + ZUncoloredRootMarkYoungOopClosure cl(prev_color); + ZNMethod::nmethod_oops_do_inner(nm, &cl); + // Disarm only the young marking, not any potential old marking cycle const uintptr_t old_marked_mask = ZPointerMarkedMask ^ (ZPointerMarkedYoung0 | ZPointerMarkedYoung1); @@ -767,16 +767,9 @@ public: // Check if disarming for young mark, completely disarms the nmethod entry barrier const bool complete_disarm = ZPointer::is_store_good(new_disarm_value_ptr); - { - ICacheInvalidationContext icic; - if (complete_disarm) { - // We are about to completely disarm the nmethod, must take responsibility to patch all barriers before disarming - ZNMethod::nmethod_patch_barriers(nm, &icic); - } - - // Heal oops - ZUncoloredRootMarkYoungOopClosure cl(prev_color); - ZNMethod::nmethod_oops_do_inner(nm, &cl, &icic); + if (complete_disarm) { + // We are about to completely disarm the nmethod, must take responsibility to patch all barriers before disarming + ZNMethod::nmethod_patch_barriers(nm); } _bs_nm->guard_with(nm, (int)untype(new_disarm_value_ptr)); diff --git a/src/hotspot/share/gc/z/zNMethod.cpp b/src/hotspot/share/gc/z/zNMethod.cpp index a1348b63b6f..780bc9e3bf7 100644 --- a/src/hotspot/share/gc/z/zNMethod.cpp +++ b/src/hotspot/share/gc/z/zNMethod.cpp @@ -50,7 +50,6 @@ #include "oops/oop.inline.hpp" #include "runtime/atomicAccess.hpp" #include "runtime/continuation.hpp" -#include "runtime/icache.hpp" #include "utilities/debug.hpp" static ZNMethodData* gc_data(const nmethod* nm) { @@ -246,16 +245,8 @@ void ZNMethod::set_guard_value(nmethod* nm, int value) { } void ZNMethod::nmethod_patch_barriers(nmethod* nm) { - ICacheInvalidationContext icic; - nmethod_patch_barriers(nm, &icic); -} - -void ZNMethod::nmethod_patch_barriers(nmethod* nm, ICacheInvalidationContext* icic) { ZBarrierSetAssembler* const bs_asm = ZBarrierSet::assembler(); ZArrayIterator iter(gc_data(nm)->barriers()); - if (gc_data(nm)->barriers()->is_nonempty()) { - icic->set_has_modified_code(); - } for (ZNMethodDataBarrier barrier; iter.next(&barrier);) { bs_asm->patch_barrier_relocation(barrier._reloc_addr, barrier._reloc_format); } @@ -267,11 +258,6 @@ void ZNMethod::nmethod_oops_do(nmethod* nm, OopClosure* cl) { } void ZNMethod::nmethod_oops_do_inner(nmethod* nm, OopClosure* cl) { - ICacheInvalidationContext icic; - nmethod_oops_do_inner(nm, cl, &icic); -} - -void ZNMethod::nmethod_oops_do_inner(nmethod* nm, OopClosure* cl, ICacheInvalidationContext* icic) { // Process oops table { oop* const begin = nm->oops_begin(); @@ -297,7 +283,7 @@ void ZNMethod::nmethod_oops_do_inner(nmethod* nm, OopClosure* cl, ICacheInvalida // Process non-immediate oops if (data->has_non_immediate_oops()) { - nm->fix_oop_relocations(icic); + nm->fix_oop_relocations(); } } diff --git a/src/hotspot/share/gc/z/zNMethod.hpp b/src/hotspot/share/gc/z/zNMethod.hpp index 2779151c576..865ea11e7b9 100644 --- a/src/hotspot/share/gc/z/zNMethod.hpp +++ b/src/hotspot/share/gc/z/zNMethod.hpp @@ -56,11 +56,9 @@ public: static void set_guard_value(nmethod* nm, int value); static void nmethod_patch_barriers(nmethod* nm); - static void nmethod_patch_barriers(nmethod* nm, ICacheInvalidationContext* icic); static void nmethod_oops_do(nmethod* nm, OopClosure* cl); static void nmethod_oops_do_inner(nmethod* nm, OopClosure* cl); - static void nmethod_oops_do_inner(nmethod* nm, OopClosure* cl, ICacheInvalidationContext* icic); static void nmethods_do_begin(bool secondary); static void nmethods_do_end(bool secondary); diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp index 296c5dedf8a..60feddde09b 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -1978,8 +1978,6 @@ const int ObjectAlignmentInBytes = 8; develop(uint, BinarySearchThreshold, 16, \ "Minimal number of elements in a sorted collection to prefer" \ "binary search over simple linear search." ) \ - product(bool, UseSingleICacheInvalidation, false, DIAGNOSTIC, \ - "Defer multiple ICache invalidation to single invalidation") \ \ // end of RUNTIME_FLAGS diff --git a/src/hotspot/share/runtime/icache.hpp b/src/hotspot/share/runtime/icache.hpp index 692a876d9a6..bc153862323 100644 --- a/src/hotspot/share/runtime/icache.hpp +++ b/src/hotspot/share/runtime/icache.hpp @@ -129,27 +129,4 @@ class ICacheStubGenerator : public StubCodeGenerator { void generate_icache_flush(ICache::flush_icache_stub_t* flush_icache_stub); }; -class DefaultICacheInvalidationContext : StackObj { - public: - NONCOPYABLE(DefaultICacheInvalidationContext); - - DefaultICacheInvalidationContext() {} - - ~DefaultICacheInvalidationContext() {} - - void set_has_modified_code() {} -}; - -#ifndef PD_ICACHE_INVALIDATION_CONTEXT -#define PD_ICACHE_INVALIDATION_CONTEXT DefaultICacheInvalidationContext -#endif // PD_ICACHE_INVALIDATION_CONTEXT - -class ICacheInvalidationContext final : public PD_ICACHE_INVALIDATION_CONTEXT { - private: - NONCOPYABLE(ICacheInvalidationContext); - - public: - using PD_ICACHE_INVALIDATION_CONTEXT::PD_ICACHE_INVALIDATION_CONTEXT; -}; - #endif // SHARE_RUNTIME_ICACHE_HPP diff --git a/test/hotspot/jtreg/compiler/runtime/TestDeferredICacheInvalidationCmdOptions.java b/test/hotspot/jtreg/compiler/runtime/TestDeferredICacheInvalidationCmdOptions.java deleted file mode 100644 index 8bc74be5c62..00000000000 --- a/test/hotspot/jtreg/compiler/runtime/TestDeferredICacheInvalidationCmdOptions.java +++ /dev/null @@ -1,426 +0,0 @@ -/* - * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -package compiler.runtime; - -import jdk.test.lib.process.OutputAnalyzer; -import jdk.test.lib.process.ProcessTools; -import jdk.test.whitebox.WhiteBox; -import jtreg.SkippedException; - -/* - * @test - * @bug 8370947 - * @summary Test command-line options for UseSingleICacheInvalidation and NeoverseN1ICacheErratumMitigation - * @library /test/lib - * @requires os.arch == "aarch64" - * @requires os.family == "linux" - * @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.runtime.TestDeferredICacheInvalidationCmdOptions - */ - -public class TestDeferredICacheInvalidationCmdOptions { - - // CPU identifiers - private static final int CPU_ARM = 0x41; - private static final int NEOVERSE_N1_MODEL = 0xd0c; - - private static boolean isAffected; - - public static void main(String[] args) throws Exception { - // Parse CPU features and print CPU info - parseCPUFeatures(); - - System.out.println("Testing UseSingleICacheInvalidation and NeoverseN1ICacheErratumMitigation command-line options..."); - - // Test case 1: Check defaults on Neoverse N1 pre-r4p1 (if applicable) - testCase1_DefaultsOnNeoverseN1(); - - // Test case 2: Check NeoverseN1ICacheErratumMitigation is false on unaffected CPUs - testCase2_DefaultsOnUnaffectedCPUs(); - - // Test case 3: Check if NeoverseN1ICacheErratumMitigation is set to false on affected CPUs, - // UseSingleICacheInvalidation is also set to false - testCase3_ExplicitlyDisableErrataAffectsDeferred(); - - // Test case 4: Check JVM error if UseSingleICacheInvalidation=true - // but NeoverseN1ICacheErratumMitigation=false on affected CPUs - testCase4_ConflictingFlagsOnAffectedCPUs(); - - // Test case 5: Check explicit NeoverseN1ICacheErratumMitigation=true enables UseSingleICacheInvalidation - testCase5_ExplicitlyEnableErrataEnablesDeferred(); - - // Test case 6: Check both flags can be explicitly set to false - testCase6_ExplicitlyDisableBothFlags(); - - // Test case 7: Check UseSingleICacheInvalidation=false with NeoverseN1ICacheErratumMitigation=true - testCase7_ConflictingErrataWithoutDeferred(); - - // Test case 8: Check setting NeoverseN1ICacheErratumMitigation=true on unaffected CPU causes an error - testCase8_EnablingErrataOnUnaffectedCPU(); - - System.out.println("All test cases passed!"); - } - - /** - * Parse CPU features string from WhiteBox.getCPUFeatures() to extract: - * - cpuFamily: 0x41 for ARM - * - cpuVariant: major revision - * - cpuModel: e.g., 0xd0c for Neoverse N1 - * - cpuRevision: minor revision - * - cpuModel2: secondary model (if present, in parentheses) - * - * Sets the static field isAffected and prints CPU info. - * - * Format: 0x%02x:0x%x:0x%03x:%d[(0x%03x)] - * Example: "0x41:0x3:0xd0c:0" or "0x41:0x3:0xd0c:0(0xd0c)" - * - * @throws SkippedException if not running on ARM CPU - */ - private static void parseCPUFeatures() { - WhiteBox wb = WhiteBox.getWhiteBox(); - String cpuFeatures = wb.getCPUFeatures(); - System.out.println("CPU Features string: " + cpuFeatures); - - if (cpuFeatures == null || cpuFeatures.isEmpty()) { - throw new RuntimeException("No CPU features available"); - } - - int commaIndex = cpuFeatures.indexOf(","); - if (commaIndex == -1) { - throw new RuntimeException("Unexpected CPU features format (no comma): " + cpuFeatures); - } - - String cpuPart = cpuFeatures.substring(0, commaIndex).trim(); - - String[] parts = cpuPart.split(":"); - if (parts.length < 4) { - throw new RuntimeException("Unexpected CPU features format: " + cpuPart); - } - - int cpuFamily = Integer.parseInt(parts[0].substring(2), 16); - if (cpuFamily != CPU_ARM) { - throw new SkippedException("Not running on ARM CPU (cpuFamily=0x" + Integer.toHexString(cpuFamily) + ")"); - } - - int cpuVariant = Integer.parseInt(parts[1].substring(2), 16); - int cpuModel = Integer.parseInt(parts[2].substring(2), 16); - int cpuModel2 = 0; - - int model2Start = parts[3].indexOf("("); - String revisionStr = parts[3]; - if (model2Start != -1) { - if (!parts[3].endsWith(")")) { - throw new RuntimeException("Unexpected CPU features format (missing closing parenthesis): " + parts[3]); - } - String model2Str = parts[3].substring(model2Start + 1, parts[3].length() - 1); - cpuModel2 = Integer.parseInt(model2Str.substring(2), 16); - revisionStr = parts[3].substring(0, model2Start); - } - int cpuRevision = Integer.parseInt(revisionStr); - - // Neoverse N1 errata 1542419 affects r3p0, r3p1 and r4p0. - // It is fixed in r4p1 and later revisions. - if (cpuModel == NEOVERSE_N1_MODEL || cpuModel2 == NEOVERSE_N1_MODEL) { - isAffected = (cpuVariant == 3 && cpuRevision == 0) || - (cpuVariant == 3 && cpuRevision == 1) || - (cpuVariant == 4 && cpuRevision == 0); - } - - printCPUInfo(cpuFamily, cpuVariant, cpuModel, cpuModel2, cpuRevision); - } - - private static void printCPUInfo(int cpuFamily, int cpuVariant, int cpuModel, int cpuModel2, int cpuRevision) { - boolean isNeoverseN1 = (cpuFamily == CPU_ARM) && - (cpuModel == NEOVERSE_N1_MODEL || cpuModel2 == NEOVERSE_N1_MODEL); - System.out.println("\n=== CPU Information ==="); - System.out.println("CPU Family: 0x" + Integer.toHexString(cpuFamily)); - System.out.println("CPU Variant: 0x" + Integer.toHexString(cpuVariant)); - System.out.println("CPU Model: 0x" + Integer.toHexString(cpuModel)); - if (cpuModel2 != 0) { - System.out.println("CPU Model2: 0x" + Integer.toHexString(cpuModel2)); - } - System.out.println("CPU Revision: " + cpuRevision); - System.out.println("Is Neoverse N1: " + isNeoverseN1); - System.out.println("Is affected by errata 1542419: " + isAffected); - System.out.println("======================\n"); - } - - /** - * Test case 1: Check the UseSingleICacheInvalidation and NeoverseN1ICacheErratumMitigation - * are set to true for Neoverse N1 pre-r4p1. - */ - private static void testCase1_DefaultsOnNeoverseN1() throws Exception { - if (!isAffected) { - System.out.println("\nTest case 1: Skipping since CPU is not affected by Neoverse N1 errata 1542419"); - return; - } - - System.out.println("\nTest case 1: Check defaults on Neoverse N1 affected revisions"); - - ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( - "-XX:+UnlockDiagnosticVMOptions", - "-XX:+PrintFlagsFinal", - "-version"); - - OutputAnalyzer output = new OutputAnalyzer(pb.start()); - output.shouldHaveExitValue(0); - - String output_str = output.getOutput(); - boolean hasSingleEnabled = output_str.matches("(?s).*bool\\s+UseSingleICacheInvalidation\\s*=\\s*true.*"); - boolean hasErrataEnabled = output_str.matches("(?s).*bool\\s+NeoverseN1ICacheErratumMitigation\\s*=\\s*true.*"); - - System.out.println("UseSingleICacheInvalidation enabled: " + hasSingleEnabled); - System.out.println("NeoverseN1ICacheErratumMitigation enabled: " + hasErrataEnabled); - - // If running on affected Neoverse N1, both should be true - if (!hasSingleEnabled || !hasErrataEnabled) { - throw new RuntimeException("On affected Neoverse N1, both flags should be enabled by default"); - } - System.out.println("Correctly enabled on affected Neoverse N1"); - } - - /** - * Test case 2: Check NeoverseN1ICacheErratumMitigation is false on unaffected CPUs. - */ - private static void testCase2_DefaultsOnUnaffectedCPUs() throws Exception { - if (isAffected) { - System.out.println("\nTest case 2: Skipping since CPU is affected by Neoverse N1 errata 1542419"); - return; - } - - System.out.println("\nTest case 2: Check NeoverseN1ICacheErratumMitigation is false on unaffected CPUs"); - - ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( - "-XX:+UnlockDiagnosticVMOptions", - "-XX:+PrintFlagsFinal", - "-version"); - - OutputAnalyzer output = new OutputAnalyzer(pb.start()); - output.shouldHaveExitValue(0); - - String output_str = output.getOutput(); - boolean hasErrataEnabled = output_str.matches("(?s).*bool\\s+NeoverseN1ICacheErratumMitigation\\s*=\\s*true.*"); - - System.out.println("NeoverseN1ICacheErratumMitigation enabled: " + hasErrataEnabled); - - // On non-Neoverse N1 or unaffected Neoverse N1 CPUs, NeoverseN1ICacheErratumMitigation should be false - if (hasErrataEnabled) { - throw new RuntimeException("On unaffected CPUs, NeoverseN1ICacheErratumMitigation should be disabled"); - } - System.out.println("Correctly disabled on unaffected CPU"); - } - - /** - * Test case 3: Check if NeoverseN1ICacheErratumMitigation is set to false via cmd on affected CPUs, - * UseSingleICacheInvalidation is set to false. - */ - private static void testCase3_ExplicitlyDisableErrataAffectsDeferred() throws Exception { - if (!isAffected) { - System.out.println("\nTest case 3: Skipping since CPU is not affected by Neoverse N1 errata 1542419"); - return; - } - - System.out.println("\nTest case 3: Explicitly disable NeoverseN1ICacheErratumMitigation, check UseSingleICacheInvalidation"); - - ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( - "-XX:+UnlockDiagnosticVMOptions", - "-XX:-NeoverseN1ICacheErratumMitigation", - "-XX:+PrintFlagsFinal", - "-version"); - - OutputAnalyzer output = new OutputAnalyzer(pb.start()); - output.shouldHaveExitValue(0); - - String output_str = output.getOutput(); - boolean hasSingleDisabled = output_str.matches("(?s).*bool\\s+UseSingleICacheInvalidation\\s*=\\s*false.*"); - boolean hasErrataDisabled = output_str.matches("(?s).*bool\\s+NeoverseN1ICacheErratumMitigation\\s*=\\s*false.*"); - - System.out.println("NeoverseN1ICacheErratumMitigation disabled: " + hasErrataDisabled); - System.out.println("UseSingleICacheInvalidation disabled: " + hasSingleDisabled); - - if (!hasErrataDisabled) { - throw new RuntimeException("Failed to disable NeoverseN1ICacheErratumMitigation via command line"); - } - - // On affected CPUs, disabling errata should also disable UseSingleICacheInvalidation - if (!hasSingleDisabled) { - throw new RuntimeException("On affected CPU, disabling NeoverseN1ICacheErratumMitigation should also disable UseSingleICacheInvalidation"); - } - System.out.println("Correctly synchronized on affected CPU"); - } - - /** - * Test case 4: Check JVM reports an error if UseSingleICacheInvalidation is set to true - * but NeoverseN1ICacheErratumMitigation is set to false on affected CPUs. - */ - private static void testCase4_ConflictingFlagsOnAffectedCPUs() throws Exception { - if (!isAffected) { - System.out.println("\nTest case 4: Skipping since CPU is not affected by Neoverse N1 errata 1542419"); - return; - } - - System.out.println("\nTest case 4: Try to set UseSingleICacheInvalidation=true with NeoverseN1ICacheErratumMitigation=false"); - - ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( - "-XX:+UnlockDiagnosticVMOptions", - "-XX:+UseSingleICacheInvalidation", - "-XX:-NeoverseN1ICacheErratumMitigation", - "-version"); - - OutputAnalyzer output = new OutputAnalyzer(pb.start()); - - if (output.getExitValue() == 0) { - throw new RuntimeException("On affected CPU, conflicting flags should cause error"); - } - output.shouldContain("Error"); - System.out.println("JVM correctly rejected conflicting flags on affected CPU"); - } - - /** - * Test case 5: Check explicit NeoverseN1ICacheErratumMitigation=true enables UseSingleICacheInvalidation. - */ - private static void testCase5_ExplicitlyEnableErrataEnablesDeferred() throws Exception { - if (!isAffected) { - System.out.println("\nTest case 5: Skipping since CPU is not affected by Neoverse N1 errata 1542419"); - return; - } - - System.out.println("\nTest case 5: Explicitly enable NeoverseN1ICacheErratumMitigation, check UseSingleICacheInvalidation"); - - ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( - "-XX:+UnlockDiagnosticVMOptions", - "-XX:+NeoverseN1ICacheErratumMitigation", - "-XX:+PrintFlagsFinal", - "-version"); - - OutputAnalyzer output = new OutputAnalyzer(pb.start()); - output.shouldHaveExitValue(0); - - String output_str = output.getOutput(); - boolean hasSingleEnabled = output_str.matches("(?s).*bool\\s+UseSingleICacheInvalidation\\s*=\\s*true.*"); - boolean hasErrataEnabled = output_str.matches("(?s).*bool\\s+NeoverseN1ICacheErratumMitigation\\s*=\\s*true.*"); - - System.out.println("NeoverseN1ICacheErratumMitigation enabled: " + hasErrataEnabled); - System.out.println("UseSingleICacheInvalidation enabled: " + hasSingleEnabled); - - if (!hasErrataEnabled) { - throw new RuntimeException("Failed to enable NeoverseN1ICacheErratumMitigation via command line"); - } - - if (!hasSingleEnabled) { - throw new RuntimeException("On affected CPU, enabling NeoverseN1ICacheErratumMitigation should also enable UseSingleICacheInvalidation"); - } - System.out.println("Correctly synchronized on affected CPU"); - } - - /** - * Test case 6: Check both flags can be explicitly set to false. - */ - private static void testCase6_ExplicitlyDisableBothFlags() throws Exception { - System.out.println("\nTest case 6: Explicitly disable both flags"); - - ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( - "-XX:+UnlockDiagnosticVMOptions", - "-XX:-UseSingleICacheInvalidation", - "-XX:-NeoverseN1ICacheErratumMitigation", - "-XX:+PrintFlagsFinal", - "-version"); - - OutputAnalyzer output = new OutputAnalyzer(pb.start()); - output.shouldHaveExitValue(0); - - String output_str = output.getOutput(); - boolean hasSingleDisabled = output_str.matches("(?s).*bool\\s+UseSingleICacheInvalidation\\s*=\\s*false.*"); - boolean hasErrataDisabled = output_str.matches("(?s).*bool\\s+NeoverseN1ICacheErratumMitigation\\s*=\\s*false.*"); - - System.out.println("UseSingleICacheInvalidation disabled: " + hasSingleDisabled); - System.out.println("NeoverseN1ICacheErratumMitigation disabled: " + hasErrataDisabled); - - if (!hasErrataDisabled) { - throw new RuntimeException("Failed to disable NeoverseN1ICacheErratumMitigation via command line"); - } - - if (!hasSingleDisabled) { - throw new RuntimeException("Failed to disable UseSingleICacheInvalidation via command line"); - } - - System.out.println("Successfully disabled both flags"); - } - - /** - * Test case 7: Check UseSingleICacheInvalidation=false with NeoverseN1ICacheErratumMitigation=true. - * On affected CPUs, this should error (conflicting requirement). - */ - private static void testCase7_ConflictingErrataWithoutDeferred() throws Exception { - if (!isAffected) { - System.out.println("\nTest case 7: Skipping since CPU is not affected by Neoverse N1 errata 1542419"); - return; - } - System.out.println("\nTest case 7: Try to set NeoverseN1ICacheErratumMitigation=true with UseSingleICacheInvalidation=false"); - - ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( - "-XX:+UnlockDiagnosticVMOptions", - "-XX:-UseSingleICacheInvalidation", - "-XX:+NeoverseN1ICacheErratumMitigation", - "-XX:+PrintFlagsFinal", - "-version"); - - OutputAnalyzer output = new OutputAnalyzer(pb.start()); - - // This should fail on affected CPUs (conflicting requirement) - if (output.getExitValue() == 0) { - throw new RuntimeException("On affected CPU, setting NeoverseN1ICacheErratumMitigation=true with UseSingleICacheInvalidation=false should cause an error"); - } - output.shouldContain("Error"); - System.out.println("JVM correctly rejected conflicting flags on affected CPU"); - } - - /** - * Test case 8: Check setting NeoverseN1ICacheErratumMitigation=true on unaffected CPU causes an error. - */ - private static void testCase8_EnablingErrataOnUnaffectedCPU() throws Exception { - if (isAffected) { - System.out.println("\nTest case 8: Skipping since CPU is affected by Neoverse N1 errata 1542419"); - return; - } - - System.out.println("\nTest case 8: Try to set NeoverseN1ICacheErratumMitigation=true on unaffected CPU"); - - ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( - "-XX:+UnlockDiagnosticVMOptions", - "-XX:+NeoverseN1ICacheErratumMitigation", - "-version"); - - OutputAnalyzer output = new OutputAnalyzer(pb.start()); - - // This should fail on unaffected CPUs (errata not present) - if (output.getExitValue() == 0) { - throw new RuntimeException("On unaffected CPU, setting NeoverseN1ICacheErratumMitigation=true should cause error"); - } - output.shouldContain("Error"); - System.out.println("JVM correctly rejected enabling errata flag on unaffected CPU"); - } -} diff --git a/test/hotspot/jtreg/gc/TestDeferredICacheInvalidation.java b/test/hotspot/jtreg/gc/TestDeferredICacheInvalidation.java deleted file mode 100644 index 70cd1ab6d8c..00000000000 --- a/test/hotspot/jtreg/gc/TestDeferredICacheInvalidation.java +++ /dev/null @@ -1,306 +0,0 @@ -/* - * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -package gc; - -/* - * @test id=parallel - * @bug 8370947 - * @summary Check no assertion is triggered when UseSingleICacheInvalidation is enabled for ParallelGC - * @library /test/lib - * @requires vm.debug - * @requires vm.gc.Parallel - * @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 -XX:+UseParallelGC -XX:-UseCodeCacheFlushing gc.TestDeferredICacheInvalidation youngGC C1 - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseParallelGC -XX:-UseCodeCacheFlushing gc.TestDeferredICacheInvalidation fullGC C1 - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseParallelGC -XX:-UseCodeCacheFlushing gc.TestDeferredICacheInvalidation youngGC C2 - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseParallelGC -XX:-UseCodeCacheFlushing gc.TestDeferredICacheInvalidation fullGC C2 - */ - -/* - * @test id=g1 - * @bug 8370947 - * @summary Check no assertion is triggered when UseSingleICacheInvalidation is enabled for G1GC - * @library /test/lib - * @requires vm.debug - * @requires vm.gc.G1 - * @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 -XX:+UseG1GC -XX:-UseCodeCacheFlushing gc.TestDeferredICacheInvalidation youngGC C1 - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseG1GC -XX:-UseCodeCacheFlushing gc.TestDeferredICacheInvalidation fullGC C1 - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseG1GC -XX:-UseCodeCacheFlushing gc.TestDeferredICacheInvalidation youngGC C2 - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseG1GC -XX:-UseCodeCacheFlushing gc.TestDeferredICacheInvalidation fullGC C2 - */ - -/* - * @test id=shenandoah - * @bug 8370947 - * @summary Check no assertion is triggered when UseSingleICacheInvalidation is enabled for ShenandoahGC - * @library /test/lib - * @requires vm.debug - * @requires vm.gc.Shenandoah - * @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 -XX:+UseShenandoahGC -XX:-UseCodeCacheFlushing gc.TestDeferredICacheInvalidation fullGC C1 - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseShenandoahGC -XX:-UseCodeCacheFlushing gc.TestDeferredICacheInvalidation fullGC C2 - */ - -/* - * @test id=genshen - * @bug 8370947 - * @summary Check no assertion is triggered when UseSingleICacheInvalidation is enabled for generational ShenandoahGC - * @library /test/lib - * @requires vm.debug - * @requires vm.gc.Shenandoah - * @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 -XX:+UseShenandoahGC -XX:+UnlockExperimentalVMOptions -XX:ShenandoahGCMode=generational -XX:-UseCodeCacheFlushing gc.TestDeferredICacheInvalidation youngGC C1 - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseShenandoahGC -XX:+UnlockExperimentalVMOptions -XX:ShenandoahGCMode=generational -XX:-UseCodeCacheFlushing gc.TestDeferredICacheInvalidation fullGC C1 - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseShenandoahGC -XX:+UnlockExperimentalVMOptions -XX:ShenandoahGCMode=generational -XX:-UseCodeCacheFlushing gc.TestDeferredICacheInvalidation youngGC C2 - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseShenandoahGC -XX:+UnlockExperimentalVMOptions -XX:ShenandoahGCMode=generational -XX:-UseCodeCacheFlushing gc.TestDeferredICacheInvalidation fullGC C2 - */ - -/* - * @test id=z - * @bug 8370947 - * @summary Check no assertion is triggered when UseSingleICacheInvalidation is enabled for ZGC - * @library /test/lib - * @requires vm.debug - * @requires vm.gc.Z - * @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 -XX:+UseZGC -XX:-UseCodeCacheFlushing gc.TestDeferredICacheInvalidation youngGC C1 - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseZGC -XX:-UseCodeCacheFlushing gc.TestDeferredICacheInvalidation fullGC C1 - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseZGC -XX:-UseCodeCacheFlushing gc.TestDeferredICacheInvalidation youngGC C2 - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseZGC -XX:-UseCodeCacheFlushing gc.TestDeferredICacheInvalidation fullGC C2 - */ - -/* - * Nmethods have GC barriers and OOPs embedded into their code. GCs can patch nmethod's code - * which requires icache invalidation. Doing invalidation per instruction can be expensive. - * CPU can support hardware dcache and icache coherence. This would allow to defer cache - * invalidation. - * - * There are assertions for deferred cache invalidation. This test checks that all of them - * are passed. - */ - -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.locks.ReentrantReadWriteLock; - -import jdk.test.whitebox.WhiteBox; - -public class TestDeferredICacheInvalidation { - - private static final WhiteBox WB = WhiteBox.getWhiteBox(); - - public static class A { - public String s1; - public String s2; - public String s3; - public String s4; - public String s5; - public String s6; - public String s7; - public String s8; - public String s9; - } - - public static A a = new A(); - - private static int compLevel; - - public static class B { - public static void test0() { - } - - public static void test1() { - a.s1 = a.s1 + "1"; - } - - public static void test2() { - a.s1 = a.s1 + "1"; - a.s2 = a.s2 + "2"; - } - - public static void test3() { - a.s1 = a.s1 + "1"; - a.s2 = a.s2 + "2"; - a.s3 = a.s3 + "3"; - } - - public static void test4() { - a.s1 = a.s1 + "1"; - a.s2 = a.s2 + "2"; - a.s3 = a.s3 + "3"; - a.s4 = a.s4 + "4"; - } - - public static void test5() { - a.s1 = a.s1 + "1"; - a.s2 = a.s2 + "2"; - a.s3 = a.s3 + "3"; - a.s4 = a.s4 + "4"; - a.s5 = a.s5 + "5"; - } - - public static void test6() { - a.s1 = a.s1 + "1"; - a.s2 = a.s2 + "2"; - a.s3 = a.s3 + "3"; - a.s4 = a.s4 + "4"; - a.s5 = a.s5 + "5"; - a.s6 = a.s6 + "6"; - } - - public static void test7() { - a.s1 = a.s1 + "1"; - a.s2 = a.s2 + "2"; - a.s3 = a.s3 + "3"; - a.s4 = a.s4 + "4"; - a.s5 = a.s5 + "5"; - a.s6 = a.s6 + "6"; - a.s7 = a.s7 + "7"; - } - - public static void test8() { - a.s1 = a.s1 + "1"; - a.s2 = a.s2 + "2"; - a.s3 = a.s3 + "3"; - a.s4 = a.s4 + "4"; - a.s5 = a.s5 + "5"; - a.s6 = a.s6 + "6"; - a.s7 = a.s7 + "7"; - a.s8 = a.s8 + "8"; - } - - public static void test9() { - a.s1 = a.s1 + "1"; - a.s2 = a.s2 + "2"; - a.s3 = a.s3 + "3"; - a.s4 = a.s4 + "4"; - a.s5 = a.s5 + "5"; - a.s6 = a.s6 + "6"; - a.s7 = a.s7 + "7"; - a.s8 = a.s8 + "8"; - a.s9 = a.s9 + "9"; - } - } - - private static void compileMethods() throws Exception { - for (var m : B.class.getDeclaredMethods()) { - if (!m.getName().startsWith("test")) { - continue; - } - m.invoke(null); - WB.markMethodProfiled(m); - WB.enqueueMethodForCompilation(m, compLevel); - while (WB.isMethodQueuedForCompilation(m)) { - Thread.sleep(100); - } - if (WB.getMethodCompilationLevel(m) != compLevel) { - throw new IllegalStateException("Method " + m + " is not compiled at the compilation level: " + compLevel + ". Got: " + WB.getMethodCompilationLevel(m)); - } - } - } - - public static void youngGC() throws Exception { - a = null; - WB.youngGC(); - } - - public static void fullGC() throws Exception { - // Thread synchronization - final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock(); - final ReentrantReadWriteLock.ReadLock readLock = rwLock.readLock(); - final ReentrantReadWriteLock.WriteLock writeLock = rwLock.writeLock(); - final AtomicBoolean running = new AtomicBoolean(true); - - // Thread 1: GC thread that runs for 1 second with 100ms sleep intervals - Thread gcThread = new Thread(() -> { - final long startTime = System.currentTimeMillis(); - final long duration = 1000; - try { - while (System.currentTimeMillis() - startTime < duration) { - writeLock.lock(); - try { - a = new A(); - WB.fullGC(); - } finally { - writeLock.unlock(); - } - Thread.sleep(100); - } - } catch (InterruptedException e) { - // Thread interrupted, exit - } - running.set(false); - }); - - // Threads 2-11: Test threads that execute test0() through test9() - Thread[] testThreads = new Thread[10]; - for (int i = 0; i < 10; i++) { - final int testIdx = i; - testThreads[i] = new Thread(() -> { - try { - var method = B.class.getDeclaredMethod("test" + testIdx); - while (running.get()) { - readLock.lock(); - try { - method.invoke(null); - } finally { - readLock.unlock(); - } - } - } catch (Exception e) { - e.printStackTrace(); - System.exit(10); - } - }); - } - - // Start all threads - gcThread.start(); - for (Thread t : testThreads) { - t.start(); - } - - // Wait for all threads to complete - gcThread.join(); - for (Thread t : testThreads) { - t.join(); - } - } - - public static void main(String[] args) throws Exception { - if (!Boolean.TRUE.equals(WB.getBooleanVMFlag("UseSingleICacheInvalidation"))) { - System.out.println("Skip. Test requires UseSingleICacheInvalidation enabled."); - return; - } - compLevel = (args[1].equals("C1")) ? 1 : 4; - compileMethods(); - TestDeferredICacheInvalidation.class.getMethod(args[0]).invoke(null); - } -} diff --git a/test/micro/org/openjdk/bench/vm/gc/GCPatchingNmethodCost.java b/test/micro/org/openjdk/bench/vm/gc/GCPatchingNmethodCost.java deleted file mode 100644 index 53fa2378ead..00000000000 --- a/test/micro/org/openjdk/bench/vm/gc/GCPatchingNmethodCost.java +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -package org.openjdk.bench.vm.gc; - -import java.lang.reflect.Method; -import java.util.*; -import java.util.concurrent.TimeUnit; - -import org.openjdk.jmh.annotations.Benchmark; -import org.openjdk.jmh.annotations.BenchmarkMode; -import org.openjdk.jmh.annotations.CompilerControl; -import org.openjdk.jmh.annotations.Fork; -import org.openjdk.jmh.annotations.Level; -import org.openjdk.jmh.annotations.Mode; -import org.openjdk.jmh.annotations.Measurement; -import org.openjdk.jmh.annotations.OutputTimeUnit; -import org.openjdk.jmh.annotations.Param; -import org.openjdk.jmh.annotations.Scope; -import org.openjdk.jmh.annotations.Setup; -import org.openjdk.jmh.annotations.State; -import org.openjdk.jmh.annotations.Warmup; - -import org.openjdk.bench.util.InMemoryJavaCompiler; - -import jdk.test.whitebox.WhiteBox; -import jdk.test.whitebox.code.NMethod; - -/* - * Nmethods have OOPs and GC barriers emmedded into their code. - * GCs patch them which causes invalidation of nmethods' code. - * - * This benchmark can be used to estimate the cost of patching - * OOPs and GC barriers. - * - * We create 5000 nmethods which access fields of a class. - * We measure the time of different GC cycles to see - * the impact of patching nmethods. - * - * The benchmark parameters are method count and accessed field count. - */ - -@BenchmarkMode(Mode.SingleShotTime) -@OutputTimeUnit(TimeUnit.MILLISECONDS) -@State(Scope.Benchmark) -@Fork(value = 1, jvmArgsAppend = { - "-XX:+UnlockDiagnosticVMOptions", - "-XX:+UnlockExperimentalVMOptions", - "-XX:+WhiteBoxAPI", - "-Xbootclasspath/a:lib-test/wb.jar", - "-XX:-UseCodeCacheFlushing" -}) -@Warmup(iterations = 5) -@Measurement(iterations = 5) -public class GCPatchingNmethodCost { - - private static final int COMP_LEVEL = 1; - private static final String FIELD_USER = "FieldUser"; - - public static Fields fields; - - private static TestMethod[] methods = {}; - private static byte[] BYTE_CODE; - private static WhiteBox WB; - - @Param({"5000"}) - public int methodCount; - - @Param({"0", "2", "4", "8"}) - public int accessedFieldCount; - - public static class Fields { - public String f1; - public String f2; - public String f3; - public String f4; - public String f5; - public String f6; - public String f7; - public String f8; - public String f9; - } - - private static final class TestMethod { - private final Method method; - - public TestMethod(Method method) throws Exception { - this.method = method; - WB.testSetDontInlineMethod(method, true); - } - - public void profile() throws Exception { - method.invoke(null); - WB.markMethodProfiled(method); - } - - public void invoke() throws Exception { - method.invoke(null); - } - - public void compile() throws Exception { - WB.enqueueMethodForCompilation(method, COMP_LEVEL); - while (WB.isMethodQueuedForCompilation(method)) { - Thread.onSpinWait(); - } - if (WB.getMethodCompilationLevel(method) != COMP_LEVEL) { - throw new IllegalStateException("Method " + method + " is not compiled at the compilation level: " + COMP_LEVEL + ". Got: " + WB.getMethodCompilationLevel(method)); - } - } - - public NMethod getNMethod() { - return NMethod.get(method, false); - } - } - - private static ClassLoader createClassLoader() { - return new ClassLoader() { - @Override - public Class loadClass(String name) throws ClassNotFoundException { - if (!name.equals(FIELD_USER)) { - return super.loadClass(name); - } - - return defineClass(name, BYTE_CODE, 0, BYTE_CODE.length); - } - }; - } - - private static void createTestMethods(int accessedFieldCount, int count) throws Exception { - String javaCode = "public class " + FIELD_USER + " {"; - String field = GCPatchingNmethodCost.class.getName() + ".fields.f"; - javaCode += "public static void accessFields() {"; - for (int i = 1; i <= accessedFieldCount; i++) { - javaCode += field + i + "= " + field + i + " + " + i + ";"; - } - javaCode += "}}"; - - BYTE_CODE = InMemoryJavaCompiler.compile(FIELD_USER, javaCode); - - fields = new Fields(); - - methods = new TestMethod[count]; - for (int i = 0; i < count; i++) { - var cl = createClassLoader().loadClass(FIELD_USER); - Method method = cl.getMethod("accessFields"); - methods[i] = new TestMethod(method); - methods[i].profile(); - methods[i].compile(); - } - } - - private static void initWhiteBox() { - WB = WhiteBox.getWhiteBox(); - } - - @Setup(Level.Trial) - public void setupCodeCache() throws Exception { - initWhiteBox(); - createTestMethods(accessedFieldCount, methodCount); - System.gc(); - } - - @Setup(Level.Iteration) - public void setupIteration() { - fields = new Fields(); - } - - @Benchmark - public void youngGC() throws Exception { - fields = null; - WB.youngGC(); - } - - @Benchmark - public void fullGC() throws Exception { - fields = null; - WB.fullGC(); - } - - @Benchmark - public void systemGC() throws Exception { - fields = null; - System.gc(); - } -} From 2a6d92fd2725ad0bc26c54275aecf591a83d20a4 Mon Sep 17 00:00:00 2001 From: Ashutosh Mehra Date: Wed, 25 Mar 2026 14:59:18 +0000 Subject: [PATCH 031/359] 8380703: Assertion failure in TestCodeEntryAlignment.java Reviewed-by: kvn, adinn --- src/hotspot/share/runtime/stubRoutines.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/runtime/stubRoutines.cpp b/src/hotspot/share/runtime/stubRoutines.cpp index 5246613738e..56d832d3fef 100644 --- a/src/hotspot/share/runtime/stubRoutines.cpp +++ b/src/hotspot/share/runtime/stubRoutines.cpp @@ -219,12 +219,12 @@ static BufferBlob* initialize_stubs(BlobId blob_id, if (STUBGEN_BLOB_FIELD_NAME(blob_name) == nullptr) { \ BlobId blob_id = BlobId:: JOIN3(stubgen, blob_name, id); \ int size = _ ## blob_name ## _code_size; \ - int max_aligned_size = 10; \ + int max_aligned_stubs = StubInfo::stub_count(blob_id); \ const char* timer_msg = "StubRoutines generation " # blob_name " stubs"; \ const char* name = "StubRoutines (" # blob_name " stubs)"; \ const char* assert_msg = "_" # blob_name "_code_size"; \ STUBGEN_BLOB_FIELD_NAME(blob_name) = \ - initialize_stubs(blob_id, size, max_aligned_size, timer_msg, \ + initialize_stubs(blob_id, size, max_aligned_stubs, timer_msg, \ name, assert_msg); \ } \ } From ca0bee78f51d5ff21cb318b9d4c8a702eca28c13 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Wed, 25 Mar 2026 15:19:32 +0000 Subject: [PATCH 032/359] 8374915: Move assertion in GenericTaskQueue<>::pop_global() Reviewed-by: tschatzl, ayang --- src/hotspot/share/gc/shared/taskqueue.inline.hpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/hotspot/share/gc/shared/taskqueue.inline.hpp b/src/hotspot/share/gc/shared/taskqueue.inline.hpp index e77645f4fcf..b142aadc580 100644 --- a/src/hotspot/share/gc/shared/taskqueue.inline.hpp +++ b/src/hotspot/share/gc/shared/taskqueue.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -279,13 +279,11 @@ typename GenericTaskQueue::PopResult GenericTaskQueue::pop_g // Increment top; if it wraps, also increment tag, to distinguish it // from any recent _age for the same top() index. idx_t new_top = increment_index(oldAge.top()); + // Don't use bottom, since a pop_local might have decremented it. + assert_not_underflow(localBot, new_top); idx_t new_tag = oldAge.tag() + ((new_top == 0) ? 1 : 0); Age newAge(new_top, new_tag); bool result = par_set_age(oldAge, newAge); - - // Note that using "bottom" here might fail, since a pop_local might - // have decremented it. - assert_not_underflow(localBot, newAge.top()); return result ? PopResult::Success : PopResult::Contended; } From cf424480f42ac220adee7034e0319cee0e9039db Mon Sep 17 00:00:00 2001 From: Hai-May Chao Date: Wed, 25 Mar 2026 15:29:34 +0000 Subject: [PATCH 033/359] 8375275: Error handling to raise illegal_parameter or internal_error alert in hybrid key exchange Reviewed-by: wetmore, mpowers --- .../classes/sun/security/ssl/DHasKEM.java | 37 ++++++++++++- .../sun/security/ssl/KAKeyDerivation.java | 53 +++++++++++++++---- 2 files changed, 78 insertions(+), 12 deletions(-) diff --git a/src/java.base/share/classes/sun/security/ssl/DHasKEM.java b/src/java.base/share/classes/sun/security/ssl/DHasKEM.java index 763013f280c..ef5c5b82f06 100644 --- a/src/java.base/share/classes/sun/security/ssl/DHasKEM.java +++ b/src/java.base/share/classes/sun/security/ssl/DHasKEM.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * 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,7 +101,18 @@ public class DHasKEM implements KEMSpi { return new KEM.Encapsulated( sub(dh, from, to), pkEm, null); + + } catch (IllegalArgumentException e) { + // ECDH validation failure + // all-zero shared secret + throw e; + } catch (InvalidKeyException e) { + // Invalid peer public key + // Convert InvalidKeyException to an unchecked exception + throw new IllegalArgumentException("Invalid peer public key", + e); } catch (Exception e) { + // Unexpected internal failure throw new ProviderException("internal error", e); } } @@ -126,6 +137,11 @@ public class DHasKEM implements KEMSpi { PublicKey pkE = params.DeserializePublicKey(encapsulation); SecretKey dh = params.DH(algorithm, skR, pkE); return sub(dh, from, to); + + } catch (IllegalArgumentException e) { + // ECDH validation failure + // all-zero shared secret + throw e; } catch (IOException | InvalidKeyException e) { throw new DecapsulateException("Cannot decapsulate", e); } catch (Exception e) { @@ -248,7 +264,24 @@ public class DHasKEM implements KEMSpi { KeyAgreement ka = KeyAgreement.getInstance(kaAlgorithm); ka.init(skE); ka.doPhase(pkR, true); - return ka.generateSecret(alg); + SecretKey secret = ka.generateSecret(alg); + + // RFC 8446 section 7.4.2: checks for all-zero + // X25519/X448 shared secret. + if (kaAlgorithm.equals("X25519") || + kaAlgorithm.equals("X448")) { + byte[] s = secret.getEncoded(); + for (byte b : s) { + if (b != 0) { + return secret; + } + } + // Trigger ILLEGAL_PARAMETER alert + throw new IllegalArgumentException( + "All-zero shared secret"); + } + + return secret; } } } diff --git a/src/java.base/share/classes/sun/security/ssl/KAKeyDerivation.java b/src/java.base/share/classes/sun/security/ssl/KAKeyDerivation.java index 39e82b50435..dea86351cc8 100644 --- a/src/java.base/share/classes/sun/security/ssl/KAKeyDerivation.java +++ b/src/java.base/share/classes/sun/security/ssl/KAKeyDerivation.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ package sun.security.ssl; import sun.security.util.RawKeySpec; +import javax.crypto.DecapsulateException; import javax.crypto.KDF; import javax.crypto.KEM; import javax.crypto.KeyAgreement; @@ -35,6 +36,7 @@ import javax.net.ssl.SSLHandshakeException; import java.io.IOException; import java.security.GeneralSecurityException; +import java.security.InvalidKeyException; import java.security.KeyFactory; import java.security.PrivateKey; import java.security.Provider; @@ -173,6 +175,9 @@ public class KAKeyDerivation implements SSLKeyDerivation { "encapsulation"); } + // All exceptions thrown during KEM encapsulation are mapped + // to TLS fatal alerts: + // illegal_parameter alert or internal_error alert. try { KeyFactory kf = (provider != null) ? KeyFactory.getInstance(algorithmName, provider) : @@ -189,8 +194,18 @@ public class KAKeyDerivation implements SSLKeyDerivation { SecretKey derived = deriveHandshakeSecret(algorithm, sharedSecret); return new KEM.Encapsulated(derived, enc.encapsulation(), null); - } catch (GeneralSecurityException gse) { - throw new SSLHandshakeException("Could not generate secret", gse); + } catch (IllegalArgumentException | InvalidKeyException e) { + // Peer validation failure + // ECDH all-zero shared secret (RFC 8446 section 7.4.2), + // ML-KEM encapsulation key check failure (FIPS-203 section 7.2) + throw context.conContext.fatal(Alert.ILLEGAL_PARAMETER, e); + } catch (GeneralSecurityException e) { + // Cryptographic failure, + // deriveHandshakeSecret failure. + throw context.conContext.fatal(Alert.INTERNAL_ERROR, e); + } catch (RuntimeException e) { + // unexpected provider/runtime failure + throw context.conContext.fatal(Alert.INTERNAL_ERROR, e); } finally { KeyUtil.destroySecretKeys(sharedSecret); } @@ -208,13 +223,30 @@ public class KAKeyDerivation implements SSLKeyDerivation { // Using KEM: called by the client after receiving the KEM // ciphertext (keyshare) from the server in ServerHello. // The client decapsulates it using its private key. - KEM kem = (provider != null) - ? KEM.getInstance(algorithmName, provider) - : KEM.getInstance(algorithmName); - var decapsulator = kem.newDecapsulator(localPrivateKey); - sharedSecret = decapsulator.decapsulate( - keyshare, 0, decapsulator.secretSize(), - "TlsPremasterSecret"); + + // All exceptions thrown during KEM decapsulation are mapped + // to TLS fatal alerts: + // illegal_parameter alert or internal_error alert. + try { + KEM kem = (provider != null) + ? KEM.getInstance(algorithmName, provider) + : KEM.getInstance(algorithmName); + var decapsulator = kem.newDecapsulator(localPrivateKey); + sharedSecret = decapsulator.decapsulate( + keyshare, 0, decapsulator.secretSize(), + "TlsPremasterSecret"); + } catch (IllegalArgumentException | InvalidKeyException | + DecapsulateException e) { + // Peer validation failure + // ECDH all-zero shared secret (RFC 8446 section 7.4.2) + throw context.conContext.fatal(Alert.ILLEGAL_PARAMETER, e); + } catch (GeneralSecurityException e) { + // cryptographic failure + throw context.conContext.fatal(Alert.INTERNAL_ERROR, e); + } catch (RuntimeException e) { + // unexpected provider/runtime failure + throw context.conContext.fatal(Alert.INTERNAL_ERROR, e); + } } else { // Using traditional DH-style Key Agreement KeyAgreement ka = KeyAgreement.getInstance(algorithmName); @@ -225,6 +257,7 @@ public class KAKeyDerivation implements SSLKeyDerivation { return deriveHandshakeSecret(type, sharedSecret); } catch (GeneralSecurityException gse) { + // deriveHandshakeSecret() failure throw new SSLHandshakeException("Could not generate secret", gse); } finally { KeyUtil.destroySecretKeys(sharedSecret); From 02972a5856a60f27fe6b914b38d3398bf6d2f9c7 Mon Sep 17 00:00:00 2001 From: Hai-May Chao Date: Wed, 25 Mar 2026 15:52:04 +0000 Subject: [PATCH 034/359] 8379549: sun/security/ssl/SSLSocketImpl/SSLSocketSSLEngineCloseInbound.java failed with SocketException: Connection reset by peer Reviewed-by: wetmore, syan, dcubed --- .../SSLSocketSSLEngineCloseInbound.java | 48 ++++++++++++++----- 1 file changed, 37 insertions(+), 11 deletions(-) diff --git a/test/jdk/sun/security/ssl/SSLSocketImpl/SSLSocketSSLEngineCloseInbound.java b/test/jdk/sun/security/ssl/SSLSocketImpl/SSLSocketSSLEngineCloseInbound.java index e084bdd3367..dc0610ce8c8 100644 --- a/test/jdk/sun/security/ssl/SSLSocketImpl/SSLSocketSSLEngineCloseInbound.java +++ b/test/jdk/sun/security/ssl/SSLSocketImpl/SSLSocketSSLEngineCloseInbound.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,7 @@ /* * @test * @bug 8273553 8253368 + * @library /test/lib * @summary sun.security.ssl.SSLEngineImpl.closeInbound also has similar error * of JDK-8253368 * @run main/othervm SSLSocketSSLEngineCloseInbound TLSv1.3 @@ -79,12 +80,30 @@ * read() ... ChangeCipherSpec * read() ... Finished */ -import javax.net.ssl.*; + +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLEngineResult; import javax.net.ssl.SSLEngineResult.*; -import java.io.*; -import java.net.*; -import java.security.*; -import java.nio.*; +import javax.net.ssl.SSLException; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.TrustManagerFactory; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.nio.ByteBuffer; +import java.security.KeyStore; +import java.security.Security; +import java.util.concurrent.CountDownLatch; + +import jdk.test.lib.Utils; public class SSLSocketSSLEngineCloseInbound { @@ -124,6 +143,8 @@ public class SSLSocketSSLEngineCloseInbound { private ByteBuffer cTOs; // "reliable" transport client->server private ByteBuffer sTOc; // "reliable" transport server->client + private final CountDownLatch serverReadyLatch = new CountDownLatch(1); + /* * The following is to set up the keystores/trust material. */ @@ -224,7 +245,7 @@ public class SSLSocketSSLEngineCloseInbound { // server-side socket that will read try (Socket socket = serverSocket.accept()) { - socket.setSoTimeout(500); + socket.setSoTimeout((int)Utils.adjustTimeout(500)); InputStream is = socket.getInputStream(); OutputStream os = socket.getOutputStream(); @@ -289,6 +310,8 @@ public class SSLSocketSSLEngineCloseInbound { throw new Exception("Server session is not valid"); } + // Server signals client it has finished writing + serverReadyLatch.countDown(); return; } @@ -315,6 +338,8 @@ public class SSLSocketSSLEngineCloseInbound { } } } finally { + // Release the latch if an exception is thrown. + serverReadyLatch.countDown(); if (serverException != null) { if (clientException != null) { serverException.initCause(clientException); @@ -342,7 +367,8 @@ public class SSLSocketSSLEngineCloseInbound { public void run() { // client-side socket try (SSLSocket sslSocket = (SSLSocket)sslc.getSocketFactory(). - createSocket("localhost", port)) { + createSocket(InetAddress.getLoopbackAddress(), + port)) { clientSocket = sslSocket; OutputStream os = sslSocket.getOutputStream(); @@ -365,9 +391,9 @@ public class SSLSocketSSLEngineCloseInbound { throw new Exception("Client's session is not valid"); } - // Give server a chance to read before we shutdown via - // the try-with-resources block. - Thread.sleep(2000); + // Client waits for server to finish sending data + // before shutdown. + serverReadyLatch.await(); } catch (Exception e) { clientException = e; } From 331c7540175ce1e7f992a49102eaa6ff5b24c42b Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Wed, 25 Mar 2026 16:32:44 +0000 Subject: [PATCH 035/359] 8380523: Refactor TLAB slow allocation naming Reviewed-by: stefank, jsikstro --- .../gc/shared/threadLocalAllocBuffer.cpp | 176 +++++++++--------- .../gc/shared/threadLocalAllocBuffer.hpp | 44 ++--- .../shared/threadLocalAllocBuffer.inline.hpp | 2 +- src/hotspot/share/jvmci/vmStructs_jvmci.cpp | 4 +- src/hotspot/share/runtime/vmStructs.cpp | 7 +- 5 files changed, 116 insertions(+), 117 deletions(-) diff --git a/src/hotspot/share/gc/shared/threadLocalAllocBuffer.cpp b/src/hotspot/share/gc/shared/threadLocalAllocBuffer.cpp index 9d995234736..f9b8694eb04 100644 --- a/src/hotspot/share/gc/shared/threadLocalAllocBuffer.cpp +++ b/src/hotspot/share/gc/shared/threadLocalAllocBuffer.cpp @@ -37,7 +37,7 @@ #include "utilities/copy.hpp" size_t ThreadLocalAllocBuffer::_max_size = 0; -unsigned int ThreadLocalAllocBuffer::_target_refills = 0; +unsigned int ThreadLocalAllocBuffer::_target_num_refills = 0; ThreadLocalAllocBuffer::ThreadLocalAllocBuffer() : _start(nullptr), @@ -48,10 +48,10 @@ ThreadLocalAllocBuffer::ThreadLocalAllocBuffer() : _desired_size(0), _refill_waste_limit(0), _allocated_before_last_gc(0), - _number_of_refills(0), + _num_refills(0), _refill_waste(0), _gc_waste(0), - _slow_allocations(0), + _num_slow_allocations(0), _allocated_size(0), _allocation_fraction(TLABAllocationWeight) { @@ -81,7 +81,7 @@ void ThreadLocalAllocBuffer::accumulate_and_reset_statistics(ThreadLocalAllocSta print_stats("gc"); - if (_number_of_refills > 0) { + if (_num_refills > 0) { // Update allocation history if a reasonable amount of eden was allocated. bool update_allocation_history = used > 0.5 * capacity; @@ -98,16 +98,16 @@ void ThreadLocalAllocBuffer::accumulate_and_reset_statistics(ThreadLocalAllocSta _allocation_fraction.sample(alloc_frac); } - stats->update_fast_allocations(_number_of_refills, + stats->update_fast_allocations(_num_refills, _allocated_size, _gc_waste, _refill_waste); } else { - assert(_number_of_refills == 0 && _refill_waste == 0 && _gc_waste == 0, + assert(_num_refills == 0 && _refill_waste == 0 && _gc_waste == 0, "tlab stats == 0"); } - stats->update_slow_allocations(_slow_allocations); + stats->update_num_slow_allocations(_num_slow_allocations); reset_statistics(); } @@ -147,7 +147,7 @@ void ThreadLocalAllocBuffer::resize() { assert(ResizeTLAB, "Should not call this otherwise"); size_t alloc = (size_t)(_allocation_fraction.average() * (Universe::heap()->tlab_capacity() / HeapWordSize)); - size_t new_size = alloc / _target_refills; + size_t new_size = alloc / _target_num_refills; new_size = clamp(new_size, min_size(), max_size()); @@ -156,24 +156,24 @@ void ThreadLocalAllocBuffer::resize() { log_trace(gc, tlab)("TLAB new size: thread: " PTR_FORMAT " [id: %2d]" " refills %d alloc: %8.6f desired_size: %zu -> %zu", p2i(thread()), thread()->osthread()->thread_id(), - _target_refills, _allocation_fraction.average(), desired_size(), aligned_new_size); + _target_num_refills, _allocation_fraction.average(), desired_size(), aligned_new_size); set_desired_size(aligned_new_size); set_refill_waste_limit(initial_refill_waste_limit()); } void ThreadLocalAllocBuffer::reset_statistics() { - _number_of_refills = 0; - _refill_waste = 0; - _gc_waste = 0; - _slow_allocations = 0; - _allocated_size = 0; + _num_refills = 0; + _refill_waste = 0; + _gc_waste = 0; + _num_slow_allocations = 0; + _allocated_size = 0; } void ThreadLocalAllocBuffer::fill(HeapWord* start, HeapWord* top, size_t new_size) { - _number_of_refills++; + _num_refills++; _allocated_size += new_size; print_stats("fill"); assert(top <= start + new_size - alignment_reserve(), "size too small"); @@ -205,7 +205,7 @@ void ThreadLocalAllocBuffer::initialize() { size_t capacity = Universe::heap()->tlab_capacity() / HeapWordSize; if (capacity > 0) { // Keep alloc_frac as float and not double to avoid the double to float conversion - float alloc_frac = desired_size() * target_refills() / (float)capacity; + float alloc_frac = desired_size() * target_num_refills() / (float)capacity; _allocation_fraction.sample(alloc_frac); } @@ -219,10 +219,10 @@ void ThreadLocalAllocBuffer::startup_initialization() { // Assuming each thread's active tlab is, on average, // 1/2 full at a GC - _target_refills = 100 / (2 * TLABWasteTargetPercent); - // We need to set initial target refills to 2 to avoid a GC which causes VM + _target_num_refills = 100 / (2 * TLABWasteTargetPercent); + // We need to set the initial target number of refills to 2 to avoid a GC which causes VM // abort during VM initialization. - _target_refills = MAX2(_target_refills, 2U); + _target_num_refills = MAX2(_target_num_refills, 2U); // During jvm startup, the main thread is initialized // before the heap is initialized. So reinitialize it now. @@ -240,10 +240,10 @@ size_t ThreadLocalAllocBuffer::initial_desired_size() { init_sz = TLABSize / HeapWordSize; } else { // Initial size is a function of the average number of allocating threads. - unsigned int nof_threads = ThreadLocalAllocStats::allocating_threads_avg(); + unsigned int num_threads = ThreadLocalAllocStats::num_allocating_threads_avg(); init_sz = (Universe::heap()->tlab_capacity() / HeapWordSize) / - (nof_threads * target_refills()); + (num_threads * target_num_refills()); init_sz = align_object_size(init_sz); } // We can't use clamp() between min_size() and max_size() here because some @@ -271,10 +271,10 @@ void ThreadLocalAllocBuffer::print_stats(const char* tag) { " slow: %dB", tag, p2i(thrd), thrd->osthread()->thread_id(), _desired_size / (K / HeapWordSize), - _slow_allocations, _refill_waste_limit * HeapWordSize, + _num_slow_allocations, _refill_waste_limit * HeapWordSize, _allocation_fraction.average(), _allocation_fraction.average() * tlab_used / K, - _number_of_refills, waste_percent, + _num_refills, waste_percent, _gc_waste * HeapWordSize, _refill_waste * HeapWordSize); } @@ -299,17 +299,17 @@ HeapWord* ThreadLocalAllocBuffer::hard_end() { return _allocation_end + alignment_reserve(); } -PerfVariable* ThreadLocalAllocStats::_perf_allocating_threads; -PerfVariable* ThreadLocalAllocStats::_perf_total_refills; -PerfVariable* ThreadLocalAllocStats::_perf_max_refills; +PerfVariable* ThreadLocalAllocStats::_perf_num_allocating_threads; +PerfVariable* ThreadLocalAllocStats::_perf_total_num_refills; +PerfVariable* ThreadLocalAllocStats::_perf_max_num_refills; PerfVariable* ThreadLocalAllocStats::_perf_total_allocated_size; PerfVariable* ThreadLocalAllocStats::_perf_total_gc_waste; PerfVariable* ThreadLocalAllocStats::_perf_max_gc_waste; PerfVariable* ThreadLocalAllocStats::_perf_total_refill_waste; PerfVariable* ThreadLocalAllocStats::_perf_max_refill_waste; -PerfVariable* ThreadLocalAllocStats::_perf_total_slow_allocations; -PerfVariable* ThreadLocalAllocStats::_perf_max_slow_allocations; -AdaptiveWeightedAverage ThreadLocalAllocStats::_allocating_threads_avg(0); +PerfVariable* ThreadLocalAllocStats::_perf_total_num_slow_allocations; +PerfVariable* ThreadLocalAllocStats::_perf_max_num_slow_allocations; +AdaptiveWeightedAverage ThreadLocalAllocStats::_num_allocating_threads_avg(0); static PerfVariable* create_perf_variable(const char* name, PerfData::Units unit, TRAPS) { ResourceMark rm; @@ -317,47 +317,47 @@ static PerfVariable* create_perf_variable(const char* name, PerfData::Units unit } void ThreadLocalAllocStats::initialize() { - _allocating_threads_avg = AdaptiveWeightedAverage(TLABAllocationWeight); - _allocating_threads_avg.sample(1); // One allocating thread at startup + _num_allocating_threads_avg = AdaptiveWeightedAverage(TLABAllocationWeight); + _num_allocating_threads_avg.sample(1); // One allocating thread at startup if (UsePerfData) { EXCEPTION_MARK; - _perf_allocating_threads = create_perf_variable("allocThreads", PerfData::U_None, CHECK); - _perf_total_refills = create_perf_variable("fills", PerfData::U_None, CHECK); - _perf_max_refills = create_perf_variable("maxFills", PerfData::U_None, CHECK); - _perf_total_allocated_size = create_perf_variable("alloc", PerfData::U_Bytes, CHECK); - _perf_total_gc_waste = create_perf_variable("gcWaste", PerfData::U_Bytes, CHECK); - _perf_max_gc_waste = create_perf_variable("maxGcWaste", PerfData::U_Bytes, CHECK); - _perf_total_refill_waste = create_perf_variable("refillWaste", PerfData::U_Bytes, CHECK); - _perf_max_refill_waste = create_perf_variable("maxRefillWaste", PerfData::U_Bytes, CHECK); - _perf_total_slow_allocations = create_perf_variable("slowAlloc", PerfData::U_None, CHECK); - _perf_max_slow_allocations = create_perf_variable("maxSlowAlloc", PerfData::U_None, CHECK); + _perf_num_allocating_threads = create_perf_variable("allocThreads", PerfData::U_None, CHECK); + _perf_total_num_refills = create_perf_variable("fills", PerfData::U_None, CHECK); + _perf_max_num_refills = create_perf_variable("maxFills", PerfData::U_None, CHECK); + _perf_total_allocated_size = create_perf_variable("alloc", PerfData::U_Bytes, CHECK); + _perf_total_gc_waste = create_perf_variable("gcWaste", PerfData::U_Bytes, CHECK); + _perf_max_gc_waste = create_perf_variable("maxGcWaste", PerfData::U_Bytes, CHECK); + _perf_total_refill_waste = create_perf_variable("refillWaste", PerfData::U_Bytes, CHECK); + _perf_max_refill_waste = create_perf_variable("maxRefillWaste", PerfData::U_Bytes, CHECK); + _perf_total_num_slow_allocations = create_perf_variable("slowAlloc", PerfData::U_None, CHECK); + _perf_max_num_slow_allocations = create_perf_variable("maxSlowAlloc", PerfData::U_None, CHECK); } } ThreadLocalAllocStats::ThreadLocalAllocStats() : - _allocating_threads(0), - _total_refills(0), - _max_refills(0), + _num_allocating_threads(0), + _total_num_refills(0), + _max_num_refills(0), _total_allocated_size(0), _total_gc_waste(0), _max_gc_waste(0), _total_refill_waste(0), _max_refill_waste(0), - _total_slow_allocations(0), - _max_slow_allocations(0) {} + _total_num_slow_allocations(0), + _max_num_slow_allocations(0) {} -unsigned int ThreadLocalAllocStats::allocating_threads_avg() { - return MAX2((unsigned int)(_allocating_threads_avg.average() + 0.5), 1U); +unsigned int ThreadLocalAllocStats::num_allocating_threads_avg() { + return MAX2((unsigned int)(_num_allocating_threads_avg.average() + 0.5), 1U); } -void ThreadLocalAllocStats::update_fast_allocations(unsigned int refills, +void ThreadLocalAllocStats::update_fast_allocations(unsigned int num_refills, size_t allocated_size, size_t gc_waste, size_t refill_waste) { - _allocating_threads += 1; - _total_refills += refills; - _max_refills = MAX2(_max_refills, refills); + _num_allocating_threads += 1; + _total_num_refills += num_refills; + _max_num_refills = MAX2(_max_num_refills, num_refills); _total_allocated_size += allocated_size; _total_gc_waste += gc_waste; _max_gc_waste = MAX2(_max_gc_waste, gc_waste); @@ -365,35 +365,35 @@ void ThreadLocalAllocStats::update_fast_allocations(unsigned int refills, _max_refill_waste = MAX2(_max_refill_waste, refill_waste); } -void ThreadLocalAllocStats::update_slow_allocations(unsigned int allocations) { - _total_slow_allocations += allocations; - _max_slow_allocations = MAX2(_max_slow_allocations, allocations); +void ThreadLocalAllocStats::update_num_slow_allocations(unsigned int num_slow_allocations) { + _total_num_slow_allocations += num_slow_allocations; + _max_num_slow_allocations = MAX2(_max_num_slow_allocations, num_slow_allocations); } void ThreadLocalAllocStats::update(const ThreadLocalAllocStats& other) { - _allocating_threads += other._allocating_threads; - _total_refills += other._total_refills; - _max_refills = MAX2(_max_refills, other._max_refills); - _total_allocated_size += other._total_allocated_size; - _total_gc_waste += other._total_gc_waste; - _max_gc_waste = MAX2(_max_gc_waste, other._max_gc_waste); - _total_refill_waste += other._total_refill_waste; - _max_refill_waste = MAX2(_max_refill_waste, other._max_refill_waste); - _total_slow_allocations += other._total_slow_allocations; - _max_slow_allocations = MAX2(_max_slow_allocations, other._max_slow_allocations); + _num_allocating_threads += other._num_allocating_threads; + _total_num_refills += other._total_num_refills; + _max_num_refills = MAX2(_max_num_refills, other._max_num_refills); + _total_allocated_size += other._total_allocated_size; + _total_gc_waste += other._total_gc_waste; + _max_gc_waste = MAX2(_max_gc_waste, other._max_gc_waste); + _total_refill_waste += other._total_refill_waste; + _max_refill_waste = MAX2(_max_refill_waste, other._max_refill_waste); + _total_num_slow_allocations += other._total_num_slow_allocations; + _max_num_slow_allocations = MAX2(_max_num_slow_allocations, other._max_num_slow_allocations); } void ThreadLocalAllocStats::reset() { - _allocating_threads = 0; - _total_refills = 0; - _max_refills = 0; - _total_allocated_size = 0; - _total_gc_waste = 0; - _max_gc_waste = 0; - _total_refill_waste = 0; - _max_refill_waste = 0; - _total_slow_allocations = 0; - _max_slow_allocations = 0; + _num_allocating_threads = 0; + _total_num_refills = 0; + _max_num_refills = 0; + _total_allocated_size = 0; + _total_gc_waste = 0; + _max_gc_waste = 0; + _total_refill_waste = 0; + _max_refill_waste = 0; + _total_num_slow_allocations = 0; + _max_num_slow_allocations = 0; } void ThreadLocalAllocStats::publish() { @@ -401,7 +401,7 @@ void ThreadLocalAllocStats::publish() { return; } - _allocating_threads_avg.sample(_allocating_threads); + _num_allocating_threads_avg.sample(_num_allocating_threads); const size_t waste = _total_gc_waste + _total_refill_waste; const double waste_percent = percent_of(waste, _total_allocated_size); @@ -409,22 +409,22 @@ void ThreadLocalAllocStats::publish() { " slow allocs: %d max %d waste: %4.1f%%" " gc: %zuB max: %zuB" " slow: %zuB max: %zuB", - _allocating_threads, _total_refills, _max_refills, - _total_slow_allocations, _max_slow_allocations, waste_percent, + _num_allocating_threads, _total_num_refills, _max_num_refills, + _total_num_slow_allocations, _max_num_slow_allocations, waste_percent, _total_gc_waste * HeapWordSize, _max_gc_waste * HeapWordSize, _total_refill_waste * HeapWordSize, _max_refill_waste * HeapWordSize); if (UsePerfData) { - _perf_allocating_threads ->set_value(_allocating_threads); - _perf_total_refills ->set_value(_total_refills); - _perf_max_refills ->set_value(_max_refills); - _perf_total_allocated_size ->set_value(_total_allocated_size); - _perf_total_gc_waste ->set_value(_total_gc_waste); - _perf_max_gc_waste ->set_value(_max_gc_waste); - _perf_total_refill_waste ->set_value(_total_refill_waste); - _perf_max_refill_waste ->set_value(_max_refill_waste); - _perf_total_slow_allocations ->set_value(_total_slow_allocations); - _perf_max_slow_allocations ->set_value(_max_slow_allocations); + _perf_num_allocating_threads ->set_value(_num_allocating_threads); + _perf_total_num_refills ->set_value(_total_num_refills); + _perf_max_num_refills ->set_value(_max_num_refills); + _perf_total_allocated_size ->set_value(_total_allocated_size); + _perf_total_gc_waste ->set_value(_total_gc_waste); + _perf_max_gc_waste ->set_value(_max_gc_waste); + _perf_total_refill_waste ->set_value(_total_refill_waste); + _perf_max_refill_waste ->set_value(_max_refill_waste); + _perf_total_num_slow_allocations ->set_value(_total_num_slow_allocations); + _perf_max_num_slow_allocations ->set_value(_max_num_slow_allocations); } } diff --git a/src/hotspot/share/gc/shared/threadLocalAllocBuffer.hpp b/src/hotspot/share/gc/shared/threadLocalAllocBuffer.hpp index 8c99523557e..67bc149013e 100644 --- a/src/hotspot/share/gc/shared/threadLocalAllocBuffer.hpp +++ b/src/hotspot/share/gc/shared/threadLocalAllocBuffer.hpp @@ -56,13 +56,13 @@ private: size_t _refill_waste_limit; // hold onto tlab if free() is larger than this uint64_t _allocated_before_last_gc; // total bytes allocated up until the last gc - static size_t _max_size; // maximum size of any TLAB - static unsigned _target_refills; // expected number of refills between GCs + static size_t _max_size; // maximum size of any TLAB + static unsigned _target_num_refills; // expected number of refills between GCs - unsigned _number_of_refills; + unsigned _num_refills; unsigned _refill_waste; unsigned _gc_waste; - unsigned _slow_allocations; + unsigned _num_slow_allocations; size_t _allocated_size; AdaptiveWeightedAverage _allocation_fraction; // fraction of eden allocated in tlabs @@ -79,7 +79,7 @@ private: size_t initial_refill_waste_limit(); - static int target_refills() { return _target_refills; } + static int target_num_refills() { return _target_num_refills; } size_t initial_desired_size(); size_t remaining(); @@ -98,9 +98,9 @@ private: // statistics - int number_of_refills() const { return _number_of_refills; } - int gc_waste() const { return _gc_waste; } - int slow_allocations() const { return _slow_allocations; } + int num_refills() const { return _num_refills; } + int gc_waste() const { return _gc_waste; } + int num_slow_allocations() const { return _num_slow_allocations; } public: ThreadLocalAllocBuffer(); @@ -179,41 +179,41 @@ public: class ThreadLocalAllocStats : public StackObj { private: - static PerfVariable* _perf_allocating_threads; - static PerfVariable* _perf_total_refills; - static PerfVariable* _perf_max_refills; + static PerfVariable* _perf_num_allocating_threads; + static PerfVariable* _perf_total_num_refills; + static PerfVariable* _perf_max_num_refills; static PerfVariable* _perf_total_allocated_size; static PerfVariable* _perf_total_gc_waste; static PerfVariable* _perf_max_gc_waste; static PerfVariable* _perf_total_refill_waste; static PerfVariable* _perf_max_refill_waste; - static PerfVariable* _perf_total_slow_allocations; - static PerfVariable* _perf_max_slow_allocations; + static PerfVariable* _perf_total_num_slow_allocations; + static PerfVariable* _perf_max_num_slow_allocations; - static AdaptiveWeightedAverage _allocating_threads_avg; + static AdaptiveWeightedAverage _num_allocating_threads_avg; - unsigned int _allocating_threads; - unsigned int _total_refills; - unsigned int _max_refills; + unsigned int _num_allocating_threads; + unsigned int _total_num_refills; + unsigned int _max_num_refills; size_t _total_allocated_size; size_t _total_gc_waste; size_t _max_gc_waste; size_t _total_refill_waste; size_t _max_refill_waste; - unsigned int _total_slow_allocations; - unsigned int _max_slow_allocations; + unsigned int _total_num_slow_allocations; + unsigned int _max_num_slow_allocations; public: static void initialize(); - static unsigned int allocating_threads_avg(); + static unsigned int num_allocating_threads_avg(); ThreadLocalAllocStats(); - void update_fast_allocations(unsigned int refills, + void update_fast_allocations(unsigned int num_refills, size_t allocated_size, size_t gc_waste, size_t refill_waste); - void update_slow_allocations(unsigned int allocations); + void update_num_slow_allocations(unsigned int num_slow_allocations); void update(const ThreadLocalAllocStats& other); void reset(); diff --git a/src/hotspot/share/gc/shared/threadLocalAllocBuffer.inline.hpp b/src/hotspot/share/gc/shared/threadLocalAllocBuffer.inline.hpp index 441686c5c4c..727467f98d0 100644 --- a/src/hotspot/share/gc/shared/threadLocalAllocBuffer.inline.hpp +++ b/src/hotspot/share/gc/shared/threadLocalAllocBuffer.inline.hpp @@ -82,7 +82,7 @@ void ThreadLocalAllocBuffer::record_slow_allocation(size_t obj_size) { set_refill_waste_limit(refill_waste_limit() + refill_waste_limit_increment()); - _slow_allocations++; + _num_slow_allocations++; log_develop_trace(gc, tlab)("TLAB: %s thread: " PTR_FORMAT " [id: %2d]" " obj: %zu" diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index 74314b0ad61..ac532e1bb4c 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -450,8 +450,8 @@ nonstatic_field(ThreadLocalAllocBuffer, _pf_top, HeapWord*) \ nonstatic_field(ThreadLocalAllocBuffer, _desired_size, size_t) \ nonstatic_field(ThreadLocalAllocBuffer, _refill_waste_limit, size_t) \ - nonstatic_field(ThreadLocalAllocBuffer, _number_of_refills, unsigned) \ - nonstatic_field(ThreadLocalAllocBuffer, _slow_allocations, unsigned) \ + nonstatic_field(ThreadLocalAllocBuffer, _num_refills, unsigned) \ + nonstatic_field(ThreadLocalAllocBuffer, _num_slow_allocations, unsigned) \ \ nonstatic_field(SafepointMechanism::ThreadData, _polling_word, volatile uintptr_t) \ nonstatic_field(SafepointMechanism::ThreadData, _polling_page, volatile uintptr_t) \ diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index 93e0ff2f3b6..48f3f078ae8 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -335,11 +335,11 @@ nonstatic_field(ThreadLocalAllocBuffer, _pf_top, HeapWord*) \ nonstatic_field(ThreadLocalAllocBuffer, _desired_size, size_t) \ nonstatic_field(ThreadLocalAllocBuffer, _refill_waste_limit, size_t) \ - static_field(ThreadLocalAllocBuffer, _target_refills, unsigned) \ - nonstatic_field(ThreadLocalAllocBuffer, _number_of_refills, unsigned) \ + static_field(ThreadLocalAllocBuffer, _target_num_refills, unsigned) \ + nonstatic_field(ThreadLocalAllocBuffer, _num_refills, unsigned) \ nonstatic_field(ThreadLocalAllocBuffer, _refill_waste, unsigned) \ nonstatic_field(ThreadLocalAllocBuffer, _gc_waste, unsigned) \ - nonstatic_field(ThreadLocalAllocBuffer, _slow_allocations, unsigned) \ + nonstatic_field(ThreadLocalAllocBuffer, _num_slow_allocations, unsigned) \ nonstatic_field(VirtualSpace, _low_boundary, char*) \ nonstatic_field(VirtualSpace, _high_boundary, char*) \ nonstatic_field(VirtualSpace, _low, char*) \ @@ -2142,4 +2142,3 @@ void vmStructs_init() { VMStructs::init(); } #endif // ASSERT - From 28529282545f6b59596a445409d59398253176f1 Mon Sep 17 00:00:00 2001 From: Ana-Maria Mihalceanu Date: Wed, 25 Mar 2026 17:20:46 +0000 Subject: [PATCH 036/359] 8380663: Update jcmd man page to include AOT.end_recording diagnostic command Reviewed-by: kevinw, kvn --- src/jdk.jcmd/share/man/jcmd.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/jdk.jcmd/share/man/jcmd.md b/src/jdk.jcmd/share/man/jcmd.md index af3886a915c..23dfa67d864 100644 --- a/src/jdk.jcmd/share/man/jcmd.md +++ b/src/jdk.jcmd/share/man/jcmd.md @@ -134,6 +134,16 @@ The following commands are available: - `-all`: (Optional) Show help for all commands (BOOLEAN, false) . +`AOT.end_recording` +: Ends an in-progress AOT training and records the results to the file(s) specified by `-XX:AOTConfiguration` and/or `-XX:AOTCacheOutput`. + + Impact: Low + + **Note:** + + The JVM must be started in AOT training mode using command-line arguments such as `-XX:AOTMode=record` or `-XX:AOTCacheOutput=`. + The results of the AOT training can be an AOT configuration file, an AOT cache file, or both. + `Compiler.CodeHeap_Analytics` \[*function*\] \[*granularity*\] : Print CodeHeap analytics From 88bdbb78b2565e559d6f96cd099770951f17e8cc Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Wed, 25 Mar 2026 18:26:24 +0000 Subject: [PATCH 037/359] 8380472: Clean up test/jdk/jdk/nio/zipfs/PathOps.java shared file system usage Reviewed-by: lancea, jpai --- test/jdk/jdk/nio/zipfs/PathOps.java | 421 +++++++++++++--------------- 1 file changed, 190 insertions(+), 231 deletions(-) diff --git a/test/jdk/jdk/nio/zipfs/PathOps.java b/test/jdk/jdk/nio/zipfs/PathOps.java index a035d425a3d..86b7946eba2 100644 --- a/test/jdk/jdk/nio/zipfs/PathOps.java +++ b/test/jdk/jdk/nio/zipfs/PathOps.java @@ -21,7 +21,6 @@ * questions. */ -import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; @@ -30,20 +29,20 @@ import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.ValueSource; import java.io.IOException; -import java.nio.file.FileSystem; import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.InvalidPathException; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.ProviderMismatchException; +import java.util.Objects; import java.util.stream.Stream; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.fail; +import static org.junit.jupiter.api.Assertions.assertTrue; /* * @test @@ -55,47 +54,48 @@ import static org.junit.jupiter.api.Assertions.fail; */ public class PathOps { - static FileSystem fs; + // create empty JAR file, testing doesn't require any contents + static Path emptyJar; - // This test uses a static file system since some ops tested on - // Path depend on the same underlying `fs` instance @BeforeAll static void setup() throws IOException { - // create empty JAR file, test doesn't require any contents - Path emptyJar = Utils.createJarFile("empty.jar"); - fs = FileSystems.newFileSystem(emptyJar); - } - - @AfterAll - static void cleanup() throws IOException { - fs.close(); + emptyJar = Utils.createJarFile("empty.jar"); } + // Ensure NPEs are thrown for null inputs on Path ops @Test - void nullPointerTest() { - Path path = fs.getPath("foo"); - assertThrows(NullPointerException.class, () -> path.resolve((String) null)); - assertThrows(NullPointerException.class, () -> path.relativize(null)); - assertThrows(NullPointerException.class, () -> path.compareTo(null)); - assertThrows(NullPointerException.class, () -> path.startsWith((Path) null)); - assertThrows(NullPointerException.class, () -> path.endsWith((Path) null)); + void nullPointerTest() throws IOException { + try (var fs = FileSystems.newFileSystem(emptyJar)) { + Path path = fs.getPath("foo"); + assertThrows(NullPointerException.class, () -> path.resolve((String) null)); + assertThrows(NullPointerException.class, () -> path.relativize(null)); + assertThrows(NullPointerException.class, () -> path.compareTo(null)); + assertThrows(NullPointerException.class, () -> path.startsWith((Path) null)); + assertThrows(NullPointerException.class, () -> path.endsWith((Path) null)); + } } + // Ensure correct behavior when paths are provided by mismatched providers @Test - void mismatchedProvidersTest() { - Path path = fs.getPath("foo"); + void mismatchedProvidersTest() throws IOException { Path other = Paths.get("foo"); - assertThrows(ProviderMismatchException.class, () -> path.compareTo(other)); - assertThrows(ProviderMismatchException.class, () -> path.resolve(other)); - assertThrows(ProviderMismatchException.class, () -> path.relativize(other)); - assertFalse(path.startsWith(other), "providerMismatched startsWith() returns true "); - assertFalse(path.endsWith(other), "providerMismatched endsWith() returns true "); + try (var fs = FileSystems.newFileSystem(emptyJar)) { + Path path = fs.getPath("foo"); + assertThrows(ProviderMismatchException.class, () -> path.compareTo(other)); + assertThrows(ProviderMismatchException.class, () -> path.resolve(other)); + assertThrows(ProviderMismatchException.class, () -> path.relativize(other)); + assertFalse(path.startsWith(other), "providerMismatched startsWith() returns true "); + assertFalse(path.endsWith(other), "providerMismatched endsWith() returns true "); + } } + // Ensure correct construction of paths when given sequence of strings @ParameterizedTest @MethodSource - void constructionTest(String first, String[] more, String expected) { - string(getPath(first, more), expected); + void constructionTest(String first, String[] more, String expected) throws IOException { + try (var fs = FileSystems.newFileSystem(emptyJar)) { + string(fs.getPath(first, more), expected); + } } static Stream constructionTest() { @@ -112,22 +112,29 @@ public class PathOps { ); } + // Ensure proper root, parent, and name components @Test - void allComponentsTest() { - var path = getPath("/a/b/c"); - root(path, "/"); - parent(path, "/a/b"); - name(path, "c"); + void allComponentsTest() throws IOException { + try (var fs = FileSystems.newFileSystem(emptyJar)) { + var path = fs.getPath("/a/b/c"); + root(path, "/"); + parent(path, "/a/b"); + name(path, "c"); + } } + // Ensure correct name count for root only and empty name @ParameterizedTest @MethodSource - void nameCountTest(String first, String root, String parent, String name, int nameCount) { - var path = getPath(first); - root(path, root); - parent(path, parent); - name(path, name); - nameCount(path, nameCount); + void nameCountTest(String first, String root, String parent, String name, int nameCount) throws IOException { + try (var fs = FileSystems.newFileSystem(emptyJar)) { + var path = fs.getPath(first); + root(path, root); + parent(path, parent); + name(path, name); + assertNotNull(path); + assertEquals(nameCount, path.getNameCount()); + } } static Stream nameCountTest() { @@ -139,13 +146,16 @@ public class PathOps { ); } + // Ensure correct parent and name behavior for no root and name only @ParameterizedTest @MethodSource - void parentNameTest(String first, String root, String parent, String name) { - var path = getPath(first); - root(path, root); - parent(path, parent); - name(path, name); + void parentNameTest(String first, String root, String parent, String name) throws IOException { + try (var fs = FileSystems.newFileSystem(emptyJar)) { + var path = fs.getPath(first); + root(path, root); + parent(path, parent); + name(path, name); + } } static Stream parentNameTest() { @@ -157,10 +167,16 @@ public class PathOps { ); } + // Ensure correct (positive) `startsWith` behavior @ParameterizedTest @MethodSource - void startsWithTest(String first, String prefix) { - starts(getPath(first), prefix); + void startsWithTest(String first, String prefix) throws IOException { + try (var fs = FileSystems.newFileSystem(emptyJar)) { + var path = fs.getPath(first); + assertNotNull(path); + Path s = fs.getPath(prefix); + assertTrue(path.startsWith(s)); + } } static Stream startsWithTest() { @@ -180,10 +196,16 @@ public class PathOps { ); } + // Ensure correct (negative) `startsWith` behavior @ParameterizedTest @MethodSource - void notStartsWithTest(String first, String prefix) { - notStarts(getPath(first), prefix); + void notStartsWithTest(String first, String prefix) throws IOException { + try (var fs = FileSystems.newFileSystem(emptyJar)) { + var path = fs.getPath(first); + assertNotNull(path); + Path s = fs.getPath(prefix); + assertFalse(path.startsWith(s)); + } } static Stream notStartsWithTest() { @@ -203,10 +225,16 @@ public class PathOps { ); } + // Ensure correct (positive) `endsWith` behavior @ParameterizedTest @MethodSource - void endsWithTest(String first, String suffix) { - ends(getPath(first), suffix); + void endsWithTest(String first, String suffix) throws IOException { + try (var fs = FileSystems.newFileSystem(emptyJar)) { + var path = fs.getPath(first); + assertNotNull(path); + Path s = fs.getPath(suffix); + assertTrue(path.endsWith(s)); + } } static Stream endsWithTest() { @@ -231,10 +259,16 @@ public class PathOps { ); } + // Ensure correct (negative) `endsWith` behavior @ParameterizedTest @MethodSource - void notEndsWithTest(String first, String suffix) { - notEnds(getPath(first), suffix); + void notEndsWithTest(String first, String suffix) throws IOException { + try (var fs = FileSystems.newFileSystem(emptyJar)) { + var path = fs.getPath(first); + assertNotNull(path); + Path s = fs.getPath(suffix); + assertFalse(path.endsWith(s)); + } } static Stream notEndsWithTest() { @@ -248,10 +282,15 @@ public class PathOps { ); } + // Ensure `getName` returns correct String at index @ParameterizedTest @MethodSource - void elementTest(int index, String expected) { - element(getPath("a/b/c"), index, expected); + void elementTest(int index, String expected) throws IOException { + try (var fs = FileSystems.newFileSystem(emptyJar)) { + var path = fs.getPath("a/b/c"); + assertNotNull(path); + assertEquals(expected, path.getName(index).toString()); + } } static Stream elementTest() { @@ -262,22 +301,35 @@ public class PathOps { ); } + // Ensure expected behavior for absolute paths @ParameterizedTest @ValueSource(strings = {"/", "/tmp"} ) - void isAbsoluteTest(String first) { - absolute(getPath(first)); + void isAbsoluteTest(String first) throws IOException { + try (var fs = FileSystems.newFileSystem(emptyJar)) { + var path = fs.getPath(first); + assertNotNull(path); + assertTrue(path.isAbsolute()); + } } + // Ensure expected behavior for non-absolute paths @ParameterizedTest @ValueSource(strings = {"tmp", ""} ) - void notAbsoluteTest(String first) { - notAbsolute(getPath(first)); + void notAbsoluteTest(String first) throws IOException { + try (var fs = FileSystems.newFileSystem(emptyJar)) { + var path = fs.getPath(first); + assertNotNull(path); + assertFalse(path.isAbsolute()); + } } + // Ensure correct append and replacement behavior for `resolve(String)` @ParameterizedTest @MethodSource - void resolveTest(String first, String other, String expected) { - resolve(getPath(first), other, expected); + void resolveTest(String first, String other, String expected) throws IOException { + try (var fs = FileSystems.newFileSystem(emptyJar)) { + resolve(fs.getPath(first), other, expected); + } } static Stream resolveTest() { @@ -298,10 +350,15 @@ public class PathOps { ); } + // Ensure correct append and replacement behavior for `resolve(Path)` @ParameterizedTest @MethodSource - void resolvePathTest(String first, String other, String expected) { - resolvePath(getPath(first), other, expected); + void resolvePathTest(String first, String other, String expected) throws IOException { + try (var fs = FileSystems.newFileSystem(emptyJar)) { + var path = fs.getPath(first); + assertNotNull(path); + assertEquals(expected, path.resolve(fs.getPath(other)).toString()); + } } static Stream resolvePathTest() { @@ -322,10 +379,13 @@ public class PathOps { ); } + // Ensure correct behavior for `resolveSibling` @ParameterizedTest @MethodSource - void resolveSiblingTest(String first, String other, String expected) { - resolveSibling(getPath(first), other, expected); + void resolveSiblingTest(String first, String other, String expected) throws IOException { + try (var fs = FileSystems.newFileSystem(emptyJar)) { + resolveSibling(fs.getPath(first), other, expected); + } } static Stream resolveSiblingTest() { @@ -345,18 +405,28 @@ public class PathOps { ); } + // Checking `resolve` and `resolveSibling` behavior for empty path @Test - void resolveSiblingAndResolveTest() { - var path = getPath(""); - resolveSibling(path, "foo", "foo"); - resolveSibling(path, "/foo", "/foo"); - resolve(path, "", ""); + void resolveSiblingAndResolveTest() throws IOException { + try (var fs = FileSystems.newFileSystem(emptyJar)) { + var path = fs.getPath(""); + resolveSibling(path, "foo", "foo"); + resolveSibling(path, "/foo", "/foo"); + resolve(path, "", ""); + } } + // Ensure correct behavior of `relativize`. i.e. Relative path should be + // produced between two given paths @ParameterizedTest @MethodSource - void relativizeTest(String first, String other, String expected) { - relativize(getPath(first), other, expected); + void relativizeTest(String first, String other, String expected) throws IOException { + try (var fs = FileSystems.newFileSystem(emptyJar)) { + var path = fs.getPath(first); + assertNotNull(path); + Path that = fs.getPath(other); + assertEquals(expected, path.relativize(that).toString()); + } } static Stream relativizeTest() { @@ -380,10 +450,15 @@ public class PathOps { ); } + // Ensure correct behavior of `normalize`. i.e. redundant elements should be removed. @ParameterizedTest @MethodSource - void normalizeTest(String first, String expected) { - normalize(getPath(first), expected); + void normalizeTest(String first, String expected) throws IOException { + try (var fs = FileSystems.newFileSystem(emptyJar)) { + var path = fs.getPath(first); + assertNotNull(path); + assertEquals(expected, path.normalize().toString()); + } } static Stream normalizeTest() { @@ -409,10 +484,13 @@ public class PathOps { ); } + // Check IPE is thrown for invalid path Strings @ParameterizedTest @MethodSource - void invalidTest(String first) { - assertThrows(InvalidPathException.class, () -> getPath(first)); + void invalidTest(String first) throws IOException { + try (var fs = FileSystems.newFileSystem(emptyJar)) { + assertThrows(InvalidPathException.class, () -> fs.getPath(first)); + } } static Stream invalidTest() { @@ -426,184 +504,65 @@ public class PathOps { ); } + // Check that repeated forward slash is normalized correctly @Test - void normalizationTest() { - var path = getPath("//foo//bar"); - string(path, "/foo/bar"); - root(path, "/"); - parent(path, "/foo"); - name(path, "bar"); + void normalizationTest() throws IOException { + try (var fs = FileSystems.newFileSystem(emptyJar)) { + var path = fs.getPath("//foo//bar"); + string(path, "/foo/bar"); + root(path, "/"); + parent(path, "/foo"); + name(path, "bar"); + } } - @Test - void isSameFileTest() { - isSameFile(getPath("/fileDoesNotExist"), "/fileDoesNotExist"); + @Test // Check that identical paths refer to the same file + void isSameFileTest() throws IOException { + try (var fs = FileSystems.newFileSystem(emptyJar)) { + var path = fs.getPath("/fileDoesNotExist"); + assertNotNull(path); + assertTrue(Files.isSameFile(path, fs.getPath("/fileDoesNotExist"))); + } } + // Regression test for 8139956: Ensure `relativize` of equivalent paths + // produces an empty path -> `getNameCount` returns 1 @Test - void getNameCountTest() { - // 8139956 - System.out.println("check getNameCount"); - int nc = fs.getPath("/").relativize(fs.getPath("/")).getNameCount(); - assertEquals(1, nc, "getNameCount of empty path failed"); + void getNameCountTest() throws IOException { + try (var fs = FileSystems.newFileSystem(emptyJar)) { + int nc = fs.getPath("/").relativize(fs.getPath("/")).getNameCount(); + assertEquals(1, nc, "getNameCount of empty path failed"); + } } // Utilities for testing - - static void checkPath(Path path) { - assertNotNull(path, "path is null"); - } - - static void check(Object result, String expected) { - if (result == null) { - if (expected == null) return; - } else { - // compare string representations - if (expected != null && result.toString().equals(expected)) - return; - } - fail(); - } - - static void check(Object result, boolean expected) { - check(result, Boolean.toString(expected)); - } - - static void check(Object result, int expected) { - check(result, Integer.toString(expected)); - } - static void root(Path path, String expected) { - System.out.println("check root"); - checkPath(path); - check(path.getRoot(), expected); + assertNotNull(path); + assertEquals(expected, Objects.toString(path.getRoot(), null)); } static void parent(Path path, String expected) { - System.out.println("check parent"); - checkPath(path); - check(path.getParent(), expected); + assertNotNull(path); + assertEquals(expected, Objects.toString(path.getParent(), null)); } static void name(Path path, String expected) { - System.out.println("check name"); - checkPath(path); - check(path.getFileName(), expected); - } - - static void nameCount(Path path, int expected) { - System.out.println("check nameCount"); - checkPath(path); - check(path.getNameCount(), expected); - } - - static void element(Path path, int index, String expected) { - System.out.format("check element %d\n", index); - checkPath(path); - check(path.getName(index), expected); - } - - static void subpath(Path path, int startIndex, int endIndex, String expected) { - System.out.format("test subpath(%d,%d)\n", startIndex, endIndex); - checkPath(path); - check(path.subpath(startIndex, endIndex), expected); - } - - static void starts(Path path, String prefix) { - System.out.format("test startsWith with %s\n", prefix); - checkPath(path); - Path s = fs.getPath(prefix); - check(path.startsWith(s), true); - } - - static void notStarts(Path path, String prefix) { - System.out.format("test not startsWith with %s\n", prefix); - checkPath(path); - Path s = fs.getPath(prefix); - check(path.startsWith(s), false); - } - - static void ends(Path path, String suffix) { - System.out.format("test endsWith %s\n", suffix); - checkPath(path); - Path s = fs.getPath(suffix); - check(path.endsWith(s), true); - } - - static void notEnds(Path path, String suffix) { - System.out.format("test not endsWith %s\n", suffix); - checkPath(path); - Path s = fs.getPath(suffix); - check(path.endsWith(s), false); - } - - static void absolute(Path path) { - System.out.println("check path is absolute"); - checkPath(path); - check(path.isAbsolute(), true); - } - - static void notAbsolute(Path path) { - System.out.println("check path is not absolute"); - checkPath(path); - check(path.isAbsolute(), false); + assertNotNull(path); + assertEquals(expected, Objects.toString(path.getFileName(), null)); } static void resolve(Path path, String other, String expected) { - System.out.format("test resolve %s\n", other); - checkPath(path); - check(path.resolve(other), expected); - } - - static void resolvePath(Path path, String other, String expected) { - System.out.format("test resolve %s\n", other); - checkPath(path); - check(path.resolve(fs.getPath(other)), expected); + assertNotNull(path); + assertEquals(expected, path.resolve(other).toString()); } static void resolveSibling(Path path, String other, String expected) { - System.out.format("test resolveSibling %s\n", other); - checkPath(path); - check(path.resolveSibling(other), expected); - - } - - static void relativize(Path path, String other, String expected) { - System.out.format("test relativize %s\n", other); - checkPath(path); - Path that = fs.getPath(other); - check(path.relativize(that), expected); - - } - - static void normalize(Path path, String expected) { - System.out.println("check normalized path"); - checkPath(path); - check(path.normalize(), expected); - + assertNotNull(path); + assertEquals(expected, path.resolveSibling(other).toString()); } static void string(Path path, String expected) { - System.out.println("check string representation"); - checkPath(path); - check(path, expected); - } - - static void isSameFile(Path path, String target) { - try { - System.out.println("check two paths are same"); - checkPath(path); - check(Files.isSameFile(path, fs.getPath(target)), true); - } catch (IOException ioe) { - fail(); - } - } - - static Path getPath(String s) { - return fs.getPath(s); - } - - static Path getPath(String first, String... more) { - return fs.getPath(first, more); + assertNotNull(path); + assertEquals(expected, path.toString()); } } From 3588fb79691b3829bab214a4bb1517fd382cccaf Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Wed, 25 Mar 2026 22:07:41 +0000 Subject: [PATCH 038/359] 8380825: AOT tests should run in two step training mode by default Reviewed-by: kvn, vlivanov --- .../aotCache/AOTCacheSupportForCustomLoaders.java | 10 ++++++++-- .../runtime/cds/appcds/aotClassLinking/AddOpens.java | 6 +++--- .../runtime/cds/appcds/aotClassLinking/AddReads.java | 8 +++----- .../aotCode/AOTCodeCPUFeatureIncompatibilityTest.java | 11 +++++++---- test/lib/jdk/test/lib/cds/CDSAppTester.java | 11 ++++++++++- 5 files changed, 31 insertions(+), 15 deletions(-) diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/AOTCacheSupportForCustomLoaders.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/AOTCacheSupportForCustomLoaders.java index 9461957ef2c..1a8313a3058 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/AOTCacheSupportForCustomLoaders.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/AOTCacheSupportForCustomLoaders.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -76,10 +76,12 @@ public class AOTCacheSupportForCustomLoaders { } class AppWithCustomLoaders { + static MyLoader loader; // keep alive so its classes can be cached. + public static void main(String args[]) throws Exception { File custJar = new File("cust.jar"); URL[] urls = new URL[] {custJar.toURI().toURL()}; - MyLoader loader = new MyLoader(urls, AppWithCustomLoaders.class.getClassLoader()); + loader = new MyLoader(urls, AppWithCustomLoaders.class.getClassLoader()); test1(loader); test2(loader); @@ -107,6 +109,7 @@ class AppWithCustomLoaders { } // Test 3: custom loader defines a class from the exact location as a class defined in the boot layer. + static Class test3_c1_keepalive; static void test3(String modulePath) throws Exception { Class c0 = Class.forName("com.test.Foo"); System.out.println(c0); @@ -130,6 +133,9 @@ class AppWithCustomLoaders { System.out.println(c1.getModule().getName()); System.out.println(c1.getClassLoader()); + // Keep c1 alive so it can be cached. + test3_c1_keepalive = c1; + if (!c1.getModule().getName().equals("com.test")) { throw new RuntimeException("Unexpected module: " + c1.getModule()); } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/AddOpens.java b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/AddOpens.java index d3626d30c7e..f7e15f8fae0 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/AddOpens.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/AddOpens.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -157,7 +157,7 @@ public class AddOpens { out.shouldContain(expectedOutput[0]); out.shouldContain(expectedOutput[1]); } else if (runMode == RunMode.ASSEMBLY) { - out.shouldContain("full module graph: enabled"); + out.shouldMatch("(full module graph: enabled)|(Full module graph = enabled)"); } } } @@ -200,7 +200,7 @@ public class AddOpens { out.shouldContain(expectedOutput[0]); out.shouldContain(expectedOutput[1]); } else if (runMode == RunMode.ASSEMBLY) { - out.shouldContain("full module graph: enabled"); + out.shouldMatch("(full module graph: enabled)|(Full module graph = enabled)"); } } } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/AddReads.java b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/AddReads.java index 5c9364aa079..95fc9f0f700 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/AddReads.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/AddReads.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 @@ public class AddReads { "[class,load] com.norequires.Main source: shared objects file"; private static final String sharedClassB = "[class,load] org.astro.World source: shared objects file"; - private static final String fmgEnabled = "full module graph: enabled"; - private static final String fmgDisabled = "full module graph: disabled"; private static final String cannotAccess = "class com.norequires.Main (in module com.norequires) cannot access class org.astro.World (in module org.astro)"; @@ -166,8 +164,8 @@ public class AddReads { out.shouldContain("full module graph: disabled"); out.shouldContain("Mismatched values for property jdk.module.addreads: runtime com.norequires=ALL-UNNAMED dump time com.norequires=org.astro"); } else if (runMode == RunMode.ASSEMBLY) { - out.shouldContain("full module graph: enabled"); - } else { + out.shouldMatch("(full module graph: enabled)|(Full module graph = enabled)"); + } else { out.shouldHaveExitValue(0); } } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeCPUFeatureIncompatibilityTest.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeCPUFeatureIncompatibilityTest.java index 8d1e190d1e3..e9e610330ad 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeCPUFeatureIncompatibilityTest.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeCPUFeatureIncompatibilityTest.java @@ -76,15 +76,18 @@ public class AOTCodeCPUFeatureIncompatibilityTest { @Override public String[] vmArgs(RunMode runMode) { if (runMode == RunMode.PRODUCTION) { - return new String[] {vmOption, "-Xlog:aot+codecache+init=debug"}; + return new String[] {vmOption, "-Xlog:aot+codecache*=debug"}; + } else { + return new String[] {"-Xlog:aot+codecache*=debug"}; } - return new String[] {}; } @Override public void checkExecution(OutputAnalyzer out, RunMode runMode) throws Exception { - if (runMode == RunMode.ASSEMBLY) { + if (runMode == RunMode.ASSEMBLY || runMode == RunMode.PRODUCTION) { out.shouldMatch("CPU features recorded in AOTCodeCache:.*" + featureName + ".*"); - } else if (runMode == RunMode.PRODUCTION) { + } + + if (runMode == RunMode.PRODUCTION) { out.shouldMatch("AOT Code Cache disabled: required cpu features are missing:.*" + featureName + ".*"); out.shouldContain("Unable to use AOT Code Cache"); } diff --git a/test/lib/jdk/test/lib/cds/CDSAppTester.java b/test/lib/jdk/test/lib/cds/CDSAppTester.java index 18356dd8aa9..3eac8a35a37 100644 --- a/test/lib/jdk/test/lib/cds/CDSAppTester.java +++ b/test/lib/jdk/test/lib/cds/CDSAppTester.java @@ -480,11 +480,20 @@ abstract public class CDSAppTester { // See JEP 483 public void runAOTWorkflow(String... args) throws Exception { this.workflow = Workflow.AOT; - boolean oneStepTraining = true; // by default use onestep trainning + + // By default use twostep training -- tests are much easier to write this way, as + // the stdout/stderr of the training run is clearly separated from the assembly phase. + // + // Many older test cases written before JEP 514 were not aware of one step treaining + // and may not check the stdout/stderr correctly. + boolean oneStepTraining = false; if (System.getProperty("CDSAppTester.two.step.training") != null) { oneStepTraining = false; } + if (System.getProperty("CDSAppTester.one.step.training") != null) { + oneStepTraining = true; + } if (args.length > 1) { // Tests such as test/hotspot/jtreg/runtime/cds/appcds/aotCache/SpecialCacheNames.java From a55656d2f938ea7ca11b7022f4bfe63f124183cf Mon Sep 17 00:00:00 2001 From: Dingli Zhang Date: Thu, 26 Mar 2026 01:53:36 +0000 Subject: [PATCH 039/359] 8380789: RISC-V: TestOpaqueConstantBoolNodes.java fails when running without RVV Reviewed-by: fyang --- .../compiler/intrinsics/string/TestOpaqueConstantBoolNodes.java | 1 + 1 file changed, 1 insertion(+) diff --git a/test/hotspot/jtreg/compiler/intrinsics/string/TestOpaqueConstantBoolNodes.java b/test/hotspot/jtreg/compiler/intrinsics/string/TestOpaqueConstantBoolNodes.java index b8db97f7ecb..c32eba5aa77 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/string/TestOpaqueConstantBoolNodes.java +++ b/test/hotspot/jtreg/compiler/intrinsics/string/TestOpaqueConstantBoolNodes.java @@ -26,6 +26,7 @@ * @bug 8374582 * @summary Tests the creation and removal of opaque nodes at range checks points in string intrinsics. * @requires vm.flagless + * @requires os.arch != "riscv64" | vm.cpu.features ~= ".*rvv.*" * @library /test/lib / * @run driver ${test.main.class} */ From ceb109fbd8a382b8c8afa73bdeffc360d352d935 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Thu, 26 Mar 2026 01:59:10 +0000 Subject: [PATCH 040/359] 8380081: jpackage: Incorrect descriptions of win-specific options Reviewed-by: nlisker, almatvee --- .../internal/resources/HelpResources.properties | 14 +++++++++----- src/jdk.jpackage/share/man/jpackage.md | 11 +++++++---- .../jdk/jpackage/internal/cli/help-windows.txt | 14 +++++++++----- 3 files changed, 25 insertions(+), 14 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources.properties b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources.properties index 0b2ca83a7d7..7f570e71330 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources.properties +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources.properties @@ -405,20 +405,24 @@ help.option.win-help-url=\ \ URL where user can obtain further information or technical support help.option.win-menu=\ -\ Request to add a Start menu shortcut for this application +\ Adds a Start menu shortcut for this application, or requests\n\ +\ to do so if --win-shortcut-prompt is specified help.option.win-menu-group=\ \ Start Menu group this application is placed in help.option.win-per-user-install=\ -\ Request to perform an install on a per-user basis +\ Installs the application on a per-user basis.\n\ +\ Without this option installs per-machine help.option.win-shortcut=\ -\ Request to add desktop shortcut for this application +\ Adds a desktop shortcut for this application, or requests\n\ +\ to do so if --win-shortcut-prompt is specified help.option.win-shortcut-prompt=\ -\ Adds a dialog to enable the user to choose if shortcuts\n\ -\ will be created by installer. +\ Adds a dialog if at least one of --win-menu or --win-shortcut\n\ +\ are specified to enable the user to choose if these shortcuts\n\ +\ will be created by the installer help.option.win-update-url=\ \ URL of available application update information diff --git a/src/jdk.jpackage/share/man/jpackage.md b/src/jdk.jpackage/share/man/jpackage.md index 9ba5949866f..156b05307b7 100644 --- a/src/jdk.jpackage/share/man/jpackage.md +++ b/src/jdk.jpackage/share/man/jpackage.md @@ -410,7 +410,8 @@ The `jpackage` tool will take as input a Java application and a Java run-time im `--win-menu` -: Request to add a Start Menu shortcut for this application +: Adds a Start menu shortcut for this application, or requests to do so + if --win-shortcut-prompt is specified `--win-menu-group` *menu-group-name* @@ -418,15 +419,17 @@ The `jpackage` tool will take as input a Java application and a Java run-time im `--win-per-user-install` -: Request to perform an install on a per-user basis +: Installs the application on a per-user basis. Without this option installs per-machine `--win-shortcut` -: Request to create a desktop shortcut for this application +: Adds a desktop shortcut for this application, or requests to do so + if --win-shortcut-prompt is specified `--win-shortcut-prompt` -: Adds a dialog to enable the user to choose if shortcuts will be created by installer +: Adds a dialog if at least one of --win-menu or --win-shortcut are specified + to enable the user to choose if these shortcuts will be created by the installer `--win-update-url` *url* diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/help-windows.txt b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/help-windows.txt index 7a098b847ad..e30a5bb7f9b 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/help-windows.txt +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/help-windows.txt @@ -189,16 +189,20 @@ Platform dependent options for creating the application package: --win-help-url URL where user can obtain further information or technical support --win-menu [] - Request to add a Start menu shortcut for this application + Adds a Start menu shortcut for this application, or requests + to do so if --win-shortcut-prompt is specified --win-menu-group

Start Menu group this application is placed in --win-per-user-install - Request to perform an install on a per-user basis + Installs the application on a per-user basis. + Without this option installs per-machine --win-shortcut [] - Request to add desktop shortcut for this application + Adds a desktop shortcut for this application, or requests + to do so if --win-shortcut-prompt is specified --win-shortcut-prompt - Adds a dialog to enable the user to choose if shortcuts - will be created by installer. + Adds a dialog if at least one of --win-menu or --win-shortcut + are specified to enable the user to choose if these shortcuts + will be created by the installer --win-update-url URL of available application update information --win-upgrade-uuid From 69deec20163561b40abce1faa4e82217afdc8efd Mon Sep 17 00:00:00 2001 From: Yasumasa Suenaga Date: Thu, 26 Mar 2026 02:16:00 +0000 Subject: [PATCH 041/359] 8378985: serviceability/sa/TestJhsdbJstackMixedWithXComp.java failed if sender frame is return barrier of Continuation Reviewed-by: cjplummer, mdoerr, fyang --- src/hotspot/share/runtime/vmStructs.cpp | 2 + .../sun/jvm/hotspot/runtime/Continuation.java | 60 +++++++++++++++++++ .../hotspot/runtime/ContinuationEntry.java | 30 ++++++++-- .../jvm/hotspot/runtime/Continuations.java | 33 ++++++++++ .../sun/jvm/hotspot/runtime/Frame.java | 3 +- .../sun/jvm/hotspot/runtime/JavaThread.java | 4 +- .../sun/jvm/hotspot/runtime/StubRoutines.java | 9 ++- .../aarch64/AARCH64ContinuationEntry.java | 43 +++++++++++++ .../hotspot/runtime/aarch64/AARCH64Frame.java | 33 ++++++---- .../runtime/amd64/AMD64ContinuationEntry.java | 43 +++++++++++++ .../jvm/hotspot/runtime/amd64/AMD64Frame.java | 50 ++++++++++++---- .../runtime/ppc64/PPC64ContinuationEntry.java | 43 +++++++++++++ .../jvm/hotspot/runtime/ppc64/PPC64Frame.java | 37 +++++++----- .../riscv64/RISCV64ContinuationEntry.java | 43 +++++++++++++ .../hotspot/runtime/riscv64/RISCV64Frame.java | 37 +++++++----- 15 files changed, 412 insertions(+), 58 deletions(-) create mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Continuation.java create mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Continuations.java create mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/aarch64/AARCH64ContinuationEntry.java create mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/amd64/AMD64ContinuationEntry.java create mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ppc64/PPC64ContinuationEntry.java create mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/riscv64/RISCV64ContinuationEntry.java diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index 48f3f078ae8..b6294a9a168 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -475,6 +475,7 @@ /***********************************/ \ \ static_field(StubRoutines, _call_stub_return_address, address) \ + static_field(StubRoutines, _cont_returnBarrier, address) \ \ /***************************************/ \ /* PcDesc and other compiled code info */ \ @@ -786,6 +787,7 @@ static_field(Mutex, _mutex_array, Mutex**) \ static_field(Mutex, _num_mutex, int) \ volatile_nonstatic_field(Mutex, _owner, Thread*) \ + nonstatic_field(ContinuationEntry, _parent, ContinuationEntry*) \ static_field(ContinuationEntry, _return_pc, address) //-------------------------------------------------------------------------------- diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Continuation.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Continuation.java new file mode 100644 index 00000000000..72ba053f451 --- /dev/null +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Continuation.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2026, 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.runtime; + +import sun.jvm.hotspot.debugger.Address; + + +public class Continuation { + + public static boolean isReturnBarrierEntry(Address senderPC) { + if (!Continuations.enabled()) { + return false; + } + return VM.getVM().getStubRoutines().contReturnBarrier().equals(senderPC); + } + + public static boolean isSPInContinuation(ContinuationEntry entry, Address sp) { + return entry.getEntrySP().greaterThan(sp); + } + + public static ContinuationEntry getContinuationEntryForSP(JavaThread thread, Address sp) { + ContinuationEntry entry = thread.getContEntry(); + while (entry != null && !isSPInContinuation(entry, sp)) { + entry = entry.getParent(); + } + return entry; + } + + public static Frame continuationBottomSender(JavaThread thread, Frame callee, Address senderSP) { + ContinuationEntry ce = getContinuationEntryForSP(thread, callee.getSP()); + Frame entry = ce.toFrame(); + if (callee.isInterpretedFrame()) { + entry.setSP(senderSP); // sp != unextended_sp + } + return entry; + } + +} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ContinuationEntry.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ContinuationEntry.java index 73152bdee84..7d8a2ba5993 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ContinuationEntry.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ContinuationEntry.java @@ -1,6 +1,6 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2025, NTT DATA. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, 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 @@ -26,12 +26,17 @@ package sun.jvm.hotspot.runtime; import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.runtime.*; +import sun.jvm.hotspot.runtime.aarch64.*; +import sun.jvm.hotspot.runtime.amd64.*; +import sun.jvm.hotspot.runtime.ppc64.*; +import sun.jvm.hotspot.runtime.riscv64.*; import sun.jvm.hotspot.types.*; +import sun.jvm.hotspot.utilities.*; -public class ContinuationEntry extends VMObject { +public abstract class ContinuationEntry extends VMObject { private static long size; + private static AddressField parentField; private static Address returnPC; static { @@ -41,13 +46,28 @@ public class ContinuationEntry extends VMObject { private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { Type type = db.lookupType("ContinuationEntry"); size = type.getSize(); + parentField = type.getAddressField("_parent"); returnPC = type.getAddressField("_return_pc").getValue(); } + public static ContinuationEntry create(Address addr) { + return switch (VM.getVM().getDebugger().getCPU()) { + case "amd64" -> VMObjectFactory.newObject(AMD64ContinuationEntry.class, addr); + case "aarch64" -> VMObjectFactory.newObject(AARCH64ContinuationEntry.class, addr); + case "riscv64" -> VMObjectFactory.newObject(RISCV64ContinuationEntry.class, addr); + case "ppc64" -> VMObjectFactory.newObject(PPC64ContinuationEntry.class, addr); + default -> throw new UnsupportedPlatformException("Continuation is not yet implemented."); + }; + } + public ContinuationEntry(Address addr) { super(addr); } + public ContinuationEntry getParent() { + return create(parentField.getValue(addr)); + } + public Address getEntryPC() { return returnPC; } @@ -60,4 +80,6 @@ public class ContinuationEntry extends VMObject { return this.getAddress().addOffsetTo(size); } + public abstract Frame toFrame(); + } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Continuations.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Continuations.java new file mode 100644 index 00000000000..884f8764ba5 --- /dev/null +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Continuations.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2026, 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.runtime; + +public class Continuations { + + public static boolean enabled() { + return VM.getVM().getCommandLineFlag("VMContinuations").getBool(); + } + +} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Frame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Frame.java index ee9e0ecdafd..978fb39ad1c 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Frame.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Frame.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -138,6 +138,7 @@ public abstract class Frame implements Cloneable { } public abstract Address getSP(); + public abstract void setSP(Address newSP); public abstract Address getID(); public abstract Address getFP(); 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 826b5cecfd5..c18bcf8cd37 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, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -343,7 +343,7 @@ public class JavaThread extends Thread { } public ContinuationEntry getContEntry() { - return VMObjectFactory.newObject(ContinuationEntry.class, contEntryField.getValue(addr)); + return ContinuationEntry.create(contEntryField.getValue(addr)); } /** Gets the Java-side thread object for this JavaThread */ diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/StubRoutines.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/StubRoutines.java index 38a3103ac50..85d8c8cd3b6 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/StubRoutines.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/StubRoutines.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +34,7 @@ import sun.jvm.hotspot.utilities.Observer; public class StubRoutines { private static AddressField callStubReturnAddressField; + private static AddressField contReturnBarrierField; static { VM.registerVMInitializedObserver(new Observer() { @@ -46,6 +47,7 @@ public class StubRoutines { private static synchronized void initialize(TypeDataBase db) { Type type = db.lookupType("StubRoutines"); callStubReturnAddressField = type.getAddressField("_call_stub_return_address"); + contReturnBarrierField = type.getAddressField("_cont_returnBarrier"); } public StubRoutines() { @@ -59,4 +61,9 @@ public class StubRoutines { return (addr.equals(returnPC)); } } + + public Address contReturnBarrier() { + return contReturnBarrierField.getValue(); + } + } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/aarch64/AARCH64ContinuationEntry.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/aarch64/AARCH64ContinuationEntry.java new file mode 100644 index 00000000000..b373167a37c --- /dev/null +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/aarch64/AARCH64ContinuationEntry.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2026, 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.runtime.aarch64; + +import sun.jvm.hotspot.debugger.Address; +import sun.jvm.hotspot.runtime.ContinuationEntry; +import sun.jvm.hotspot.runtime.Frame; + + +public class AARCH64ContinuationEntry extends ContinuationEntry { + + public AARCH64ContinuationEntry(Address addr) { + super(addr); + } + + @Override + public Frame toFrame() { + return new AARCH64Frame(getEntrySP(), getEntrySP(), getEntryFP(), getEntryPC()); + } + +} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/aarch64/AARCH64Frame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/aarch64/AARCH64Frame.java index 7233d508cbc..5e73150c6cf 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/aarch64/AARCH64Frame.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/aarch64/AARCH64Frame.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2015, 2019, Red Hat Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -206,6 +206,11 @@ public class AARCH64Frame extends Frame { public Address getSP() { return raw_sp; } public Address getID() { return raw_sp; } + @Override + public void setSP(Address newSP) { + raw_sp = newSP; + } + // FIXME: not implemented yet public boolean isSignalHandlerFrameDbg() { return false; } public int getSignalNumberDbg() { return 0; } @@ -360,16 +365,6 @@ public class AARCH64Frame extends Frame { map.setLocation(fp, savedFPAddr); } - private Frame senderForContinuationStub(AARCH64RegisterMap map, CodeBlob cb) { - var contEntry = map.getThread().getContEntry(); - - Address senderSP = contEntry.getEntrySP(); - Address senderPC = contEntry.getEntryPC(); - Address senderFP = contEntry.getEntryFP(); - - return new AARCH64Frame(senderSP, senderFP, senderPC); - } - private Frame senderForCompiledFrame(AARCH64RegisterMap map, CodeBlob cb) { if (DEBUG) { System.out.println("senderForCompiledFrame"); @@ -416,6 +411,22 @@ public class AARCH64Frame extends Frame { updateMapWithSavedLink(map, savedFPAddr); } + if (Continuation.isReturnBarrierEntry(senderPC)) { + // We assume WalkContinuation is "WalkContinuation::skip". + // It is same with c'tor arguments of RegisterMap in frame::next_frame(). + // + // HotSpot code in cpu/aarch64/frame_aarch64.inline.hpp: + // + // if (Continuation::is_return_barrier_entry(sender_pc)) { + // if (map->walk_cont()) { // about to walk into an h-stack + // return Continuation::top_frame(*this, map); + // } else { + // return Continuation::continuation_bottom_sender(map->thread(), *this, l_sender_sp); + // } + // } + return Continuation.continuationBottomSender(map.getThread(), this, senderSP); + } + return new AARCH64Frame(senderSP, savedFPAddr.getAddressAt(0), senderPC); } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/amd64/AMD64ContinuationEntry.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/amd64/AMD64ContinuationEntry.java new file mode 100644 index 00000000000..3cbebfce2f4 --- /dev/null +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/amd64/AMD64ContinuationEntry.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2026, 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.runtime.amd64; + +import sun.jvm.hotspot.debugger.Address; +import sun.jvm.hotspot.runtime.ContinuationEntry; +import sun.jvm.hotspot.runtime.Frame; + + +public class AMD64ContinuationEntry extends ContinuationEntry { + + public AMD64ContinuationEntry(Address addr) { + super(addr); + } + + @Override + public Frame toFrame() { + return new AMD64Frame(getEntrySP(), getEntrySP(), getEntryFP(), getEntryPC()); + } + +} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/amd64/AMD64Frame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/amd64/AMD64Frame.java index fa9d50160e1..2b78157e2b2 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/amd64/AMD64Frame.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/amd64/AMD64Frame.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -206,6 +206,11 @@ public class AMD64Frame extends Frame { public Address getSP() { return raw_sp; } public Address getID() { return raw_sp; } + @Override + public void setSP(Address newSP) { + raw_sp = newSP; + } + // FIXME: not implemented yet (should be done for Solaris) public boolean isSignalHandlerFrameDbg() { return false; } public int getSignalNumberDbg() { return 0; } @@ -258,6 +263,23 @@ public class AMD64Frame extends Frame { // update it accordingly map.setIncludeArgumentOops(false); + // HotSpot has following code in frame::sender_raw() at frame_x86.inline.hpp, however + // in_cont() should be false. + // + // if (map->in_cont()) { // already in an h-stack + // return map->stack_chunk()->sender(*this, map); + // } + // + // in_cont() returns true if _chunk() is not null. + // + // frame::next_frame() creates RegisterMap instance with 4 arguments. + // It sets RegisterMap::WalkContinuation::skip to final argument (walk_cont), + // therefore _chunk will not be initialized by the following code in c'tor of RegisterMap. + // + // if (walk_cont == WalkContinuation::include && thread != nullptr && thread->last_continuation() != nullptr) { + // _chunk = stackChunkHandle(Thread::current()->handle_area()->allocate_null_handle(), true /* dummy */); + // } + if (isEntryFrame()) return senderForEntryFrame(map); if (isInterpretedFrame()) return senderForInterpreterFrame(map); @@ -360,16 +382,6 @@ public class AMD64Frame extends Frame { map.setLocation(rbp, savedFPAddr); } - private Frame senderForContinuationStub(AMD64RegisterMap map, CodeBlob cb) { - var contEntry = map.getThread().getContEntry(); - - Address senderSP = contEntry.getEntrySP(); - Address senderPC = contEntry.getEntryPC(); - Address senderFP = contEntry.getEntryFP(); - - return new AMD64Frame(senderSP, senderFP, senderPC); - } - private Frame senderForCompiledFrame(AMD64RegisterMap map, CodeBlob cb) { if (DEBUG) { System.out.println("senderForCompiledFrame"); @@ -408,6 +420,22 @@ public class AMD64Frame extends Frame { updateMapWithSavedLink(map, savedFPAddr); } + if (Continuation.isReturnBarrierEntry(senderPC)) { + // We assume WalkContinuation is "WalkContinuation::skip". + // It is same with c'tor arguments of RegisterMap in frame::next_frame(). + // + // HotSpot code in cpu/x86/frame_x86.inline.hpp: + // + // if (Continuation::is_return_barrier_entry(sender_pc)) { + // if (map->walk_cont()) { // about to walk into an h-stack + // return Continuation::top_frame(*this, map); + // } else { + // return Continuation::continuation_bottom_sender(map->thread(), *this, sender_sp); + // } + // } + return Continuation.continuationBottomSender(map.getThread(), this, senderSP); + } + return new AMD64Frame(senderSP, savedFPAddr.getAddressAt(0), senderPC); } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ppc64/PPC64ContinuationEntry.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ppc64/PPC64ContinuationEntry.java new file mode 100644 index 00000000000..fac71cc9953 --- /dev/null +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ppc64/PPC64ContinuationEntry.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2026, 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.runtime.ppc64; + +import sun.jvm.hotspot.debugger.Address; +import sun.jvm.hotspot.runtime.ContinuationEntry; +import sun.jvm.hotspot.runtime.Frame; + + +public class PPC64ContinuationEntry extends ContinuationEntry { + + public PPC64ContinuationEntry(Address addr) { + super(addr); + } + + @Override + public Frame toFrame() { + return new PPC64Frame(getEntrySP(), getEntrySP(), getEntryFP(), getEntryPC()); + } + +} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ppc64/PPC64Frame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ppc64/PPC64Frame.java index cae034c9613..a663d016011 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ppc64/PPC64Frame.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ppc64/PPC64Frame.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +198,11 @@ public class PPC64Frame extends Frame { public Address getSP() { return raw_sp; } public Address getID() { return raw_sp; } + @Override + public void setSP(Address newSP) { + raw_sp = newSP; + } + // FIXME: not implemented yet (should be done for Solaris/PPC64) public boolean isSignalHandlerFrameDbg() { return false; } public int getSignalNumberDbg() { return 0; } @@ -260,9 +265,7 @@ public class PPC64Frame extends Frame { if (cb != null) { if (cb.isUpcallStub()) { return senderForUpcallStub(map, (UpcallStub)cb); - } else if (cb.isContinuationStub()) { - return senderForContinuationStub(map, cb); - } else { + } else if (cb.getFrameSize() > 0) { return senderForCompiledFrame(map, cb); } } @@ -337,16 +340,6 @@ public class PPC64Frame extends Frame { return new PPC64Frame(sp, unextendedSP, getLink(), getSenderPC()); } - private Frame senderForContinuationStub(PPC64RegisterMap map, CodeBlob cb) { - var contEntry = map.getThread().getContEntry(); - - Address sp = contEntry.getEntrySP(); - Address pc = contEntry.getEntryPC(); - Address fp = contEntry.getEntryFP(); - - return new PPC64Frame(sp, fp, pc); - } - private Frame senderForCompiledFrame(PPC64RegisterMap map, CodeBlob cb) { if (DEBUG) { System.out.println("senderForCompiledFrame"); @@ -379,6 +372,22 @@ public class PPC64Frame extends Frame { } } + if (Continuation.isReturnBarrierEntry(senderPC)) { + // We assume WalkContinuation is "WalkContinuation::skip". + // It is same with c'tor arguments of RegisterMap in frame::next_frame(). + // + // HotSpot code in cpu/ppc/frame_ppc.inline.hpp: + // + // if (Continuation::is_return_barrier_entry(sender_pc)) { + // if (map->walk_cont()) { // about to walk into an h-stack + // return Continuation::top_frame(*this, map); + // } else { + // return Continuation::continuation_bottom_sender(map->thread(), *this, l_sender_sp); + // } + // } + return Continuation.continuationBottomSender(map.getThread(), this, senderSP); + } + return new PPC64Frame(senderSP, getLink(), senderPC); } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/riscv64/RISCV64ContinuationEntry.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/riscv64/RISCV64ContinuationEntry.java new file mode 100644 index 00000000000..ec04498a6c0 --- /dev/null +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/riscv64/RISCV64ContinuationEntry.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2026, 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.runtime.riscv64; + +import sun.jvm.hotspot.debugger.Address; +import sun.jvm.hotspot.runtime.ContinuationEntry; +import sun.jvm.hotspot.runtime.Frame; + + +public class RISCV64ContinuationEntry extends ContinuationEntry { + + public RISCV64ContinuationEntry(Address addr) { + super(addr); + } + + @Override + public Frame toFrame() { + return new RISCV64Frame(getEntrySP(), getEntrySP(), getEntryFP(), getEntryPC()); + } + +} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/riscv64/RISCV64Frame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/riscv64/RISCV64Frame.java index 44c8f4c679c..a35c0735979 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/riscv64/RISCV64Frame.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/riscv64/RISCV64Frame.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2015, 2019, Red Hat Inc. * Copyright (c) 2021, 2023, Huawei Technologies Co., Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -201,6 +201,11 @@ public class RISCV64Frame extends Frame { public Address getSP() { return raw_sp; } public Address getID() { return raw_sp; } + @Override + public void setSP(Address newSP) { + raw_sp = newSP; + } + // FIXME: not implemented yet public boolean isSignalHandlerFrameDbg() { return false; } public int getSignalNumberDbg() { return 0; } @@ -264,9 +269,7 @@ public class RISCV64Frame extends Frame { if (cb != null) { if (cb.isUpcallStub()) { return senderForUpcallStub(map, (UpcallStub)cb); - } else if (cb.isContinuationStub()) { - return senderForContinuationStub(map, cb); - } else { + } else if (cb.getFrameSize() > 0) { return senderForCompiledFrame(map, cb); } } @@ -354,16 +357,6 @@ public class RISCV64Frame extends Frame { map.setLocation(fp, savedFPAddr); } - private Frame senderForContinuationStub(RISCV64RegisterMap map, CodeBlob cb) { - var contEntry = map.getThread().getContEntry(); - - Address senderSP = contEntry.getEntrySP(); - Address senderPC = contEntry.getEntryPC(); - Address senderFP = contEntry.getEntryFP(); - - return new RISCV64Frame(senderSP, senderFP, senderPC); - } - private Frame senderForCompiledFrame(RISCV64RegisterMap map, CodeBlob cb) { if (DEBUG) { System.out.println("senderForCompiledFrame"); @@ -406,6 +399,22 @@ public class RISCV64Frame extends Frame { updateMapWithSavedLink(map, savedFPAddr); } + if (Continuation.isReturnBarrierEntry(senderPC)) { + // We assume WalkContinuation is "WalkContinuation::skip". + // It is same with c'tor arguments of RegisterMap in frame::next_frame(). + // + // HotSpot code in cpu/riscv/frame_riscv.inline.hpp: + // + // if (Continuation::is_return_barrier_entry(sender_pc)) { + // if (map->walk_cont()) { // about to walk into an h-stack + // return Continuation::top_frame(*this, map); + // } else { + // return Continuation::continuation_bottom_sender(map->thread(), *this, l_sender_sp); + // } + // } + return Continuation.continuationBottomSender(map.getThread(), this, senderSP); + } + return new RISCV64Frame(senderSP, savedFPAddr.getAddressAt(0), senderPC); } From 960161db82191b679b92094c8bd661e868dfb424 Mon Sep 17 00:00:00 2001 From: Yasumasa Suenaga Date: Thu, 26 Mar 2026 07:22:04 +0000 Subject: [PATCH 042/359] 8380764: Vector classes should have @ValueBased Reviewed-by: liach --- .../share/classes/jdk/incubator/vector/ByteVector128.java | 6 ++++-- .../share/classes/jdk/incubator/vector/ByteVector256.java | 6 ++++-- .../share/classes/jdk/incubator/vector/ByteVector512.java | 6 ++++-- .../share/classes/jdk/incubator/vector/ByteVector64.java | 6 ++++-- .../share/classes/jdk/incubator/vector/ByteVectorMax.java | 6 ++++-- .../share/classes/jdk/incubator/vector/DoubleVector128.java | 6 ++++-- .../share/classes/jdk/incubator/vector/DoubleVector256.java | 6 ++++-- .../share/classes/jdk/incubator/vector/DoubleVector512.java | 6 ++++-- .../share/classes/jdk/incubator/vector/DoubleVector64.java | 6 ++++-- .../share/classes/jdk/incubator/vector/DoubleVectorMax.java | 6 ++++-- .../share/classes/jdk/incubator/vector/FloatVector128.java | 6 ++++-- .../share/classes/jdk/incubator/vector/FloatVector256.java | 6 ++++-- .../share/classes/jdk/incubator/vector/FloatVector512.java | 6 ++++-- .../share/classes/jdk/incubator/vector/FloatVector64.java | 6 ++++-- .../share/classes/jdk/incubator/vector/FloatVectorMax.java | 6 ++++-- .../share/classes/jdk/incubator/vector/IntVector128.java | 6 ++++-- .../share/classes/jdk/incubator/vector/IntVector256.java | 6 ++++-- .../share/classes/jdk/incubator/vector/IntVector512.java | 6 ++++-- .../share/classes/jdk/incubator/vector/IntVector64.java | 6 ++++-- .../share/classes/jdk/incubator/vector/IntVectorMax.java | 6 ++++-- .../share/classes/jdk/incubator/vector/LongVector128.java | 6 ++++-- .../share/classes/jdk/incubator/vector/LongVector256.java | 6 ++++-- .../share/classes/jdk/incubator/vector/LongVector512.java | 6 ++++-- .../share/classes/jdk/incubator/vector/LongVector64.java | 6 ++++-- .../share/classes/jdk/incubator/vector/LongVectorMax.java | 6 ++++-- .../share/classes/jdk/incubator/vector/ShortVector128.java | 6 ++++-- .../share/classes/jdk/incubator/vector/ShortVector256.java | 6 ++++-- .../share/classes/jdk/incubator/vector/ShortVector512.java | 6 ++++-- .../share/classes/jdk/incubator/vector/ShortVector64.java | 6 ++++-- .../share/classes/jdk/incubator/vector/ShortVectorMax.java | 6 ++++-- .../classes/jdk/incubator/vector/X-VectorBits.java.template | 6 ++++-- 31 files changed, 124 insertions(+), 62 deletions(-) diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector128.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector128.java index c38e8d0f8a0..360afedbbbb 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector128.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector128.java @@ -31,6 +31,7 @@ import java.util.Arrays; import java.util.Objects; import java.util.function.IntUnaryOperator; +import jdk.internal.ValueBased; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.vector.VectorSupport; @@ -41,6 +42,7 @@ import static jdk.incubator.vector.VectorOperators.*; // -- This file was mechanically generated: Do not edit! -- // @SuppressWarnings("cast") // warning: redundant cast +@ValueBased final class ByteVector128 extends ByteVector { static final ByteSpecies VSPECIES = (ByteSpecies) ByteVector.SPECIES_128; @@ -598,7 +600,7 @@ final class ByteVector128 extends ByteVector { } // Mask - + @ValueBased static final class ByteMask128 extends AbstractMask { static final int VLENGTH = VSPECIES.laneCount(); // used by the JVM @@ -831,7 +833,7 @@ final class ByteVector128 extends ByteVector { } // Shuffle - + @ValueBased static final class ByteShuffle128 extends AbstractShuffle { static final int VLENGTH = VSPECIES.laneCount(); // used by the JVM diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector256.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector256.java index 0eec0c56e37..ca0c59dd49e 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector256.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector256.java @@ -31,6 +31,7 @@ import java.util.Arrays; import java.util.Objects; import java.util.function.IntUnaryOperator; +import jdk.internal.ValueBased; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.vector.VectorSupport; @@ -41,6 +42,7 @@ import static jdk.incubator.vector.VectorOperators.*; // -- This file was mechanically generated: Do not edit! -- // @SuppressWarnings("cast") // warning: redundant cast +@ValueBased final class ByteVector256 extends ByteVector { static final ByteSpecies VSPECIES = (ByteSpecies) ByteVector.SPECIES_256; @@ -630,7 +632,7 @@ final class ByteVector256 extends ByteVector { } // Mask - + @ValueBased static final class ByteMask256 extends AbstractMask { static final int VLENGTH = VSPECIES.laneCount(); // used by the JVM @@ -863,7 +865,7 @@ final class ByteVector256 extends ByteVector { } // Shuffle - + @ValueBased static final class ByteShuffle256 extends AbstractShuffle { static final int VLENGTH = VSPECIES.laneCount(); // used by the JVM diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector512.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector512.java index 138319b60d4..1a0c69153bc 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector512.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector512.java @@ -31,6 +31,7 @@ import java.util.Arrays; import java.util.Objects; import java.util.function.IntUnaryOperator; +import jdk.internal.ValueBased; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.vector.VectorSupport; @@ -41,6 +42,7 @@ import static jdk.incubator.vector.VectorOperators.*; // -- This file was mechanically generated: Do not edit! -- // @SuppressWarnings("cast") // warning: redundant cast +@ValueBased final class ByteVector512 extends ByteVector { static final ByteSpecies VSPECIES = (ByteSpecies) ByteVector.SPECIES_512; @@ -694,7 +696,7 @@ final class ByteVector512 extends ByteVector { } // Mask - + @ValueBased static final class ByteMask512 extends AbstractMask { static final int VLENGTH = VSPECIES.laneCount(); // used by the JVM @@ -927,7 +929,7 @@ final class ByteVector512 extends ByteVector { } // Shuffle - + @ValueBased static final class ByteShuffle512 extends AbstractShuffle { static final int VLENGTH = VSPECIES.laneCount(); // used by the JVM diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector64.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector64.java index d7c7c78534b..50561eca0f8 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector64.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector64.java @@ -31,6 +31,7 @@ import java.util.Arrays; import java.util.Objects; import java.util.function.IntUnaryOperator; +import jdk.internal.ValueBased; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.vector.VectorSupport; @@ -41,6 +42,7 @@ import static jdk.incubator.vector.VectorOperators.*; // -- This file was mechanically generated: Do not edit! -- // @SuppressWarnings("cast") // warning: redundant cast +@ValueBased final class ByteVector64 extends ByteVector { static final ByteSpecies VSPECIES = (ByteSpecies) ByteVector.SPECIES_64; @@ -582,7 +584,7 @@ final class ByteVector64 extends ByteVector { } // Mask - + @ValueBased static final class ByteMask64 extends AbstractMask { static final int VLENGTH = VSPECIES.laneCount(); // used by the JVM @@ -815,7 +817,7 @@ final class ByteVector64 extends ByteVector { } // Shuffle - + @ValueBased static final class ByteShuffle64 extends AbstractShuffle { static final int VLENGTH = VSPECIES.laneCount(); // used by the JVM diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVectorMax.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVectorMax.java index 636aa83893a..ee931bbc077 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVectorMax.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVectorMax.java @@ -31,6 +31,7 @@ import java.util.Arrays; import java.util.Objects; import java.util.function.IntUnaryOperator; +import jdk.internal.ValueBased; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.vector.VectorSupport; @@ -41,6 +42,7 @@ import static jdk.incubator.vector.VectorOperators.*; // -- This file was mechanically generated: Do not edit! -- // @SuppressWarnings("cast") // warning: redundant cast +@ValueBased final class ByteVectorMax extends ByteVector { static final ByteSpecies VSPECIES = (ByteSpecies) ByteVector.SPECIES_MAX; @@ -568,7 +570,7 @@ final class ByteVectorMax extends ByteVector { } // Mask - + @ValueBased static final class ByteMaskMax extends AbstractMask { static final int VLENGTH = VSPECIES.laneCount(); // used by the JVM @@ -801,7 +803,7 @@ final class ByteVectorMax extends ByteVector { } // Shuffle - + @ValueBased static final class ByteShuffleMax extends AbstractShuffle { static final int VLENGTH = VSPECIES.laneCount(); // used by the JVM diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector128.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector128.java index 1140d377e9b..43c7e3f0c46 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector128.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector128.java @@ -31,6 +31,7 @@ import java.util.Arrays; import java.util.Objects; import java.util.function.IntUnaryOperator; +import jdk.internal.ValueBased; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.vector.VectorSupport; @@ -41,6 +42,7 @@ import static jdk.incubator.vector.VectorOperators.*; // -- This file was mechanically generated: Do not edit! -- // @SuppressWarnings("cast") // warning: redundant cast +@ValueBased final class DoubleVector128 extends DoubleVector { static final DoubleSpecies VSPECIES = (DoubleSpecies) DoubleVector.SPECIES_128; @@ -559,7 +561,7 @@ final class DoubleVector128 extends DoubleVector { } // Mask - + @ValueBased static final class DoubleMask128 extends AbstractMask { static final int VLENGTH = VSPECIES.laneCount(); // used by the JVM @@ -792,7 +794,7 @@ final class DoubleVector128 extends DoubleVector { } // Shuffle - + @ValueBased static final class DoubleShuffle128 extends AbstractShuffle { static final int VLENGTH = VSPECIES.laneCount(); // used by the JVM diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector256.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector256.java index 59b7913cfcb..5f176854dbd 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector256.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector256.java @@ -31,6 +31,7 @@ import java.util.Arrays; import java.util.Objects; import java.util.function.IntUnaryOperator; +import jdk.internal.ValueBased; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.vector.VectorSupport; @@ -41,6 +42,7 @@ import static jdk.incubator.vector.VectorOperators.*; // -- This file was mechanically generated: Do not edit! -- // @SuppressWarnings("cast") // warning: redundant cast +@ValueBased final class DoubleVector256 extends DoubleVector { static final DoubleSpecies VSPECIES = (DoubleSpecies) DoubleVector.SPECIES_256; @@ -563,7 +565,7 @@ final class DoubleVector256 extends DoubleVector { } // Mask - + @ValueBased static final class DoubleMask256 extends AbstractMask { static final int VLENGTH = VSPECIES.laneCount(); // used by the JVM @@ -796,7 +798,7 @@ final class DoubleVector256 extends DoubleVector { } // Shuffle - + @ValueBased static final class DoubleShuffle256 extends AbstractShuffle { static final int VLENGTH = VSPECIES.laneCount(); // used by the JVM diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector512.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector512.java index 8ed21953394..0696f48163d 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector512.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector512.java @@ -31,6 +31,7 @@ import java.util.Arrays; import java.util.Objects; import java.util.function.IntUnaryOperator; +import jdk.internal.ValueBased; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.vector.VectorSupport; @@ -41,6 +42,7 @@ import static jdk.incubator.vector.VectorOperators.*; // -- This file was mechanically generated: Do not edit! -- // @SuppressWarnings("cast") // warning: redundant cast +@ValueBased final class DoubleVector512 extends DoubleVector { static final DoubleSpecies VSPECIES = (DoubleSpecies) DoubleVector.SPECIES_512; @@ -571,7 +573,7 @@ final class DoubleVector512 extends DoubleVector { } // Mask - + @ValueBased static final class DoubleMask512 extends AbstractMask { static final int VLENGTH = VSPECIES.laneCount(); // used by the JVM @@ -804,7 +806,7 @@ final class DoubleVector512 extends DoubleVector { } // Shuffle - + @ValueBased static final class DoubleShuffle512 extends AbstractShuffle { static final int VLENGTH = VSPECIES.laneCount(); // used by the JVM diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector64.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector64.java index 7e1a8cf768d..5b74c2c4619 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector64.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector64.java @@ -31,6 +31,7 @@ import java.util.Arrays; import java.util.Objects; import java.util.function.IntUnaryOperator; +import jdk.internal.ValueBased; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.vector.VectorSupport; @@ -41,6 +42,7 @@ import static jdk.incubator.vector.VectorOperators.*; // -- This file was mechanically generated: Do not edit! -- // @SuppressWarnings("cast") // warning: redundant cast +@ValueBased final class DoubleVector64 extends DoubleVector { static final DoubleSpecies VSPECIES = (DoubleSpecies) DoubleVector.SPECIES_64; @@ -557,7 +559,7 @@ final class DoubleVector64 extends DoubleVector { } // Mask - + @ValueBased static final class DoubleMask64 extends AbstractMask { static final int VLENGTH = VSPECIES.laneCount(); // used by the JVM @@ -790,7 +792,7 @@ final class DoubleVector64 extends DoubleVector { } // Shuffle - + @ValueBased static final class DoubleShuffle64 extends AbstractShuffle { static final int VLENGTH = VSPECIES.laneCount(); // used by the JVM diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVectorMax.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVectorMax.java index 46c090e066e..07d227d641a 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVectorMax.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVectorMax.java @@ -31,6 +31,7 @@ import java.util.Arrays; import java.util.Objects; import java.util.function.IntUnaryOperator; +import jdk.internal.ValueBased; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.vector.VectorSupport; @@ -41,6 +42,7 @@ import static jdk.incubator.vector.VectorOperators.*; // -- This file was mechanically generated: Do not edit! -- // @SuppressWarnings("cast") // warning: redundant cast +@ValueBased final class DoubleVectorMax extends DoubleVector { static final DoubleSpecies VSPECIES = (DoubleSpecies) DoubleVector.SPECIES_MAX; @@ -556,7 +558,7 @@ final class DoubleVectorMax extends DoubleVector { } // Mask - + @ValueBased static final class DoubleMaskMax extends AbstractMask { static final int VLENGTH = VSPECIES.laneCount(); // used by the JVM @@ -789,7 +791,7 @@ final class DoubleVectorMax extends DoubleVector { } // Shuffle - + @ValueBased static final class DoubleShuffleMax extends AbstractShuffle { static final int VLENGTH = VSPECIES.laneCount(); // used by the JVM diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector128.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector128.java index 1e3867e84fc..17c1fdba4fc 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector128.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector128.java @@ -31,6 +31,7 @@ import java.util.Arrays; import java.util.Objects; import java.util.function.IntUnaryOperator; +import jdk.internal.ValueBased; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.vector.VectorSupport; @@ -41,6 +42,7 @@ import static jdk.incubator.vector.VectorOperators.*; // -- This file was mechanically generated: Do not edit! -- // @SuppressWarnings("cast") // warning: redundant cast +@ValueBased final class FloatVector128 extends FloatVector { static final FloatSpecies VSPECIES = (FloatSpecies) FloatVector.SPECIES_128; @@ -563,7 +565,7 @@ final class FloatVector128 extends FloatVector { } // Mask - + @ValueBased static final class FloatMask128 extends AbstractMask { static final int VLENGTH = VSPECIES.laneCount(); // used by the JVM @@ -796,7 +798,7 @@ final class FloatVector128 extends FloatVector { } // Shuffle - + @ValueBased static final class FloatShuffle128 extends AbstractShuffle { static final int VLENGTH = VSPECIES.laneCount(); // used by the JVM diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector256.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector256.java index f267025972d..7badb71415e 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector256.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector256.java @@ -31,6 +31,7 @@ import java.util.Arrays; import java.util.Objects; import java.util.function.IntUnaryOperator; +import jdk.internal.ValueBased; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.vector.VectorSupport; @@ -41,6 +42,7 @@ import static jdk.incubator.vector.VectorOperators.*; // -- This file was mechanically generated: Do not edit! -- // @SuppressWarnings("cast") // warning: redundant cast +@ValueBased final class FloatVector256 extends FloatVector { static final FloatSpecies VSPECIES = (FloatSpecies) FloatVector.SPECIES_256; @@ -571,7 +573,7 @@ final class FloatVector256 extends FloatVector { } // Mask - + @ValueBased static final class FloatMask256 extends AbstractMask { static final int VLENGTH = VSPECIES.laneCount(); // used by the JVM @@ -804,7 +806,7 @@ final class FloatVector256 extends FloatVector { } // Shuffle - + @ValueBased static final class FloatShuffle256 extends AbstractShuffle { static final int VLENGTH = VSPECIES.laneCount(); // used by the JVM diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector512.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector512.java index 439e26f0d89..7c0786b7fcd 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector512.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector512.java @@ -31,6 +31,7 @@ import java.util.Arrays; import java.util.Objects; import java.util.function.IntUnaryOperator; +import jdk.internal.ValueBased; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.vector.VectorSupport; @@ -41,6 +42,7 @@ import static jdk.incubator.vector.VectorOperators.*; // -- This file was mechanically generated: Do not edit! -- // @SuppressWarnings("cast") // warning: redundant cast +@ValueBased final class FloatVector512 extends FloatVector { static final FloatSpecies VSPECIES = (FloatSpecies) FloatVector.SPECIES_512; @@ -587,7 +589,7 @@ final class FloatVector512 extends FloatVector { } // Mask - + @ValueBased static final class FloatMask512 extends AbstractMask { static final int VLENGTH = VSPECIES.laneCount(); // used by the JVM @@ -820,7 +822,7 @@ final class FloatVector512 extends FloatVector { } // Shuffle - + @ValueBased static final class FloatShuffle512 extends AbstractShuffle { static final int VLENGTH = VSPECIES.laneCount(); // used by the JVM diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector64.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector64.java index 9e81a52d27b..fc4877e5ae8 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector64.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector64.java @@ -31,6 +31,7 @@ import java.util.Arrays; import java.util.Objects; import java.util.function.IntUnaryOperator; +import jdk.internal.ValueBased; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.vector.VectorSupport; @@ -41,6 +42,7 @@ import static jdk.incubator.vector.VectorOperators.*; // -- This file was mechanically generated: Do not edit! -- // @SuppressWarnings("cast") // warning: redundant cast +@ValueBased final class FloatVector64 extends FloatVector { static final FloatSpecies VSPECIES = (FloatSpecies) FloatVector.SPECIES_64; @@ -559,7 +561,7 @@ final class FloatVector64 extends FloatVector { } // Mask - + @ValueBased static final class FloatMask64 extends AbstractMask { static final int VLENGTH = VSPECIES.laneCount(); // used by the JVM @@ -792,7 +794,7 @@ final class FloatVector64 extends FloatVector { } // Shuffle - + @ValueBased static final class FloatShuffle64 extends AbstractShuffle { static final int VLENGTH = VSPECIES.laneCount(); // used by the JVM diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVectorMax.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVectorMax.java index 4813f153544..5cfafecdb58 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVectorMax.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVectorMax.java @@ -31,6 +31,7 @@ import java.util.Arrays; import java.util.Objects; import java.util.function.IntUnaryOperator; +import jdk.internal.ValueBased; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.vector.VectorSupport; @@ -41,6 +42,7 @@ import static jdk.incubator.vector.VectorOperators.*; // -- This file was mechanically generated: Do not edit! -- // @SuppressWarnings("cast") // warning: redundant cast +@ValueBased final class FloatVectorMax extends FloatVector { static final FloatSpecies VSPECIES = (FloatSpecies) FloatVector.SPECIES_MAX; @@ -556,7 +558,7 @@ final class FloatVectorMax extends FloatVector { } // Mask - + @ValueBased static final class FloatMaskMax extends AbstractMask { static final int VLENGTH = VSPECIES.laneCount(); // used by the JVM @@ -789,7 +791,7 @@ final class FloatVectorMax extends FloatVector { } // Shuffle - + @ValueBased static final class FloatShuffleMax extends AbstractShuffle { static final int VLENGTH = VSPECIES.laneCount(); // used by the JVM diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector128.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector128.java index cc8f31a4bc2..04b10386127 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector128.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector128.java @@ -31,6 +31,7 @@ import java.util.Arrays; import java.util.Objects; import java.util.function.IntUnaryOperator; +import jdk.internal.ValueBased; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.vector.VectorSupport; @@ -41,6 +42,7 @@ import static jdk.incubator.vector.VectorOperators.*; // -- This file was mechanically generated: Do not edit! -- // @SuppressWarnings("cast") // warning: redundant cast +@ValueBased final class IntVector128 extends IntVector { static final IntSpecies VSPECIES = (IntSpecies) IntVector.SPECIES_128; @@ -574,7 +576,7 @@ final class IntVector128 extends IntVector { } // Mask - + @ValueBased static final class IntMask128 extends AbstractMask { static final int VLENGTH = VSPECIES.laneCount(); // used by the JVM @@ -807,7 +809,7 @@ final class IntVector128 extends IntVector { } // Shuffle - + @ValueBased static final class IntShuffle128 extends AbstractShuffle { static final int VLENGTH = VSPECIES.laneCount(); // used by the JVM diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector256.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector256.java index 0630cd958f2..20d9df1cd60 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector256.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector256.java @@ -31,6 +31,7 @@ import java.util.Arrays; import java.util.Objects; import java.util.function.IntUnaryOperator; +import jdk.internal.ValueBased; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.vector.VectorSupport; @@ -41,6 +42,7 @@ import static jdk.incubator.vector.VectorOperators.*; // -- This file was mechanically generated: Do not edit! -- // @SuppressWarnings("cast") // warning: redundant cast +@ValueBased final class IntVector256 extends IntVector { static final IntSpecies VSPECIES = (IntSpecies) IntVector.SPECIES_256; @@ -582,7 +584,7 @@ final class IntVector256 extends IntVector { } // Mask - + @ValueBased static final class IntMask256 extends AbstractMask { static final int VLENGTH = VSPECIES.laneCount(); // used by the JVM @@ -815,7 +817,7 @@ final class IntVector256 extends IntVector { } // Shuffle - + @ValueBased static final class IntShuffle256 extends AbstractShuffle { static final int VLENGTH = VSPECIES.laneCount(); // used by the JVM diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector512.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector512.java index 92eb5a0f2d2..4f3a16e2777 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector512.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector512.java @@ -31,6 +31,7 @@ import java.util.Arrays; import java.util.Objects; import java.util.function.IntUnaryOperator; +import jdk.internal.ValueBased; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.vector.VectorSupport; @@ -41,6 +42,7 @@ import static jdk.incubator.vector.VectorOperators.*; // -- This file was mechanically generated: Do not edit! -- // @SuppressWarnings("cast") // warning: redundant cast +@ValueBased final class IntVector512 extends IntVector { static final IntSpecies VSPECIES = (IntSpecies) IntVector.SPECIES_512; @@ -598,7 +600,7 @@ final class IntVector512 extends IntVector { } // Mask - + @ValueBased static final class IntMask512 extends AbstractMask { static final int VLENGTH = VSPECIES.laneCount(); // used by the JVM @@ -831,7 +833,7 @@ final class IntVector512 extends IntVector { } // Shuffle - + @ValueBased static final class IntShuffle512 extends AbstractShuffle { static final int VLENGTH = VSPECIES.laneCount(); // used by the JVM diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector64.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector64.java index c3f92285034..dd51669943b 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector64.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector64.java @@ -31,6 +31,7 @@ import java.util.Arrays; import java.util.Objects; import java.util.function.IntUnaryOperator; +import jdk.internal.ValueBased; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.vector.VectorSupport; @@ -41,6 +42,7 @@ import static jdk.incubator.vector.VectorOperators.*; // -- This file was mechanically generated: Do not edit! -- // @SuppressWarnings("cast") // warning: redundant cast +@ValueBased final class IntVector64 extends IntVector { static final IntSpecies VSPECIES = (IntSpecies) IntVector.SPECIES_64; @@ -570,7 +572,7 @@ final class IntVector64 extends IntVector { } // Mask - + @ValueBased static final class IntMask64 extends AbstractMask { static final int VLENGTH = VSPECIES.laneCount(); // used by the JVM @@ -803,7 +805,7 @@ final class IntVector64 extends IntVector { } // Shuffle - + @ValueBased static final class IntShuffle64 extends AbstractShuffle { static final int VLENGTH = VSPECIES.laneCount(); // used by the JVM diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVectorMax.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVectorMax.java index 8d3c251536c..0b785b01aec 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVectorMax.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVectorMax.java @@ -31,6 +31,7 @@ import java.util.Arrays; import java.util.Objects; import java.util.function.IntUnaryOperator; +import jdk.internal.ValueBased; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.vector.VectorSupport; @@ -41,6 +42,7 @@ import static jdk.incubator.vector.VectorOperators.*; // -- This file was mechanically generated: Do not edit! -- // @SuppressWarnings("cast") // warning: redundant cast +@ValueBased final class IntVectorMax extends IntVector { static final IntSpecies VSPECIES = (IntSpecies) IntVector.SPECIES_MAX; @@ -568,7 +570,7 @@ final class IntVectorMax extends IntVector { } // Mask - + @ValueBased static final class IntMaskMax extends AbstractMask { static final int VLENGTH = VSPECIES.laneCount(); // used by the JVM @@ -812,7 +814,7 @@ final class IntVectorMax extends IntVector { } // Shuffle - + @ValueBased static final class IntShuffleMax extends AbstractShuffle { static final int VLENGTH = VSPECIES.laneCount(); // used by the JVM diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector128.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector128.java index f8dad12ff89..594c82ca1fc 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector128.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector128.java @@ -31,6 +31,7 @@ import java.util.Arrays; import java.util.Objects; import java.util.function.IntUnaryOperator; +import jdk.internal.ValueBased; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.vector.VectorSupport; @@ -41,6 +42,7 @@ import static jdk.incubator.vector.VectorOperators.*; // -- This file was mechanically generated: Do not edit! -- // @SuppressWarnings("cast") // warning: redundant cast +@ValueBased final class LongVector128 extends LongVector { static final LongSpecies VSPECIES = (LongSpecies) LongVector.SPECIES_128; @@ -560,7 +562,7 @@ final class LongVector128 extends LongVector { } // Mask - + @ValueBased static final class LongMask128 extends AbstractMask { static final int VLENGTH = VSPECIES.laneCount(); // used by the JVM @@ -793,7 +795,7 @@ final class LongVector128 extends LongVector { } // Shuffle - + @ValueBased static final class LongShuffle128 extends AbstractShuffle { static final int VLENGTH = VSPECIES.laneCount(); // used by the JVM diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector256.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector256.java index 144e2c1c64d..c3d1ff4c276 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector256.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector256.java @@ -31,6 +31,7 @@ import java.util.Arrays; import java.util.Objects; import java.util.function.IntUnaryOperator; +import jdk.internal.ValueBased; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.vector.VectorSupport; @@ -41,6 +42,7 @@ import static jdk.incubator.vector.VectorOperators.*; // -- This file was mechanically generated: Do not edit! -- // @SuppressWarnings("cast") // warning: redundant cast +@ValueBased final class LongVector256 extends LongVector { static final LongSpecies VSPECIES = (LongSpecies) LongVector.SPECIES_256; @@ -564,7 +566,7 @@ final class LongVector256 extends LongVector { } // Mask - + @ValueBased static final class LongMask256 extends AbstractMask { static final int VLENGTH = VSPECIES.laneCount(); // used by the JVM @@ -797,7 +799,7 @@ final class LongVector256 extends LongVector { } // Shuffle - + @ValueBased static final class LongShuffle256 extends AbstractShuffle { static final int VLENGTH = VSPECIES.laneCount(); // used by the JVM diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector512.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector512.java index b49d0c7c147..b8c95967a99 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector512.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector512.java @@ -31,6 +31,7 @@ import java.util.Arrays; import java.util.Objects; import java.util.function.IntUnaryOperator; +import jdk.internal.ValueBased; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.vector.VectorSupport; @@ -41,6 +42,7 @@ import static jdk.incubator.vector.VectorOperators.*; // -- This file was mechanically generated: Do not edit! -- // @SuppressWarnings("cast") // warning: redundant cast +@ValueBased final class LongVector512 extends LongVector { static final LongSpecies VSPECIES = (LongSpecies) LongVector.SPECIES_512; @@ -572,7 +574,7 @@ final class LongVector512 extends LongVector { } // Mask - + @ValueBased static final class LongMask512 extends AbstractMask { static final int VLENGTH = VSPECIES.laneCount(); // used by the JVM @@ -805,7 +807,7 @@ final class LongVector512 extends LongVector { } // Shuffle - + @ValueBased static final class LongShuffle512 extends AbstractShuffle { static final int VLENGTH = VSPECIES.laneCount(); // used by the JVM diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector64.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector64.java index 5e8451695bc..3c9b525f6d0 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector64.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector64.java @@ -31,6 +31,7 @@ import java.util.Arrays; import java.util.Objects; import java.util.function.IntUnaryOperator; +import jdk.internal.ValueBased; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.vector.VectorSupport; @@ -41,6 +42,7 @@ import static jdk.incubator.vector.VectorOperators.*; // -- This file was mechanically generated: Do not edit! -- // @SuppressWarnings("cast") // warning: redundant cast +@ValueBased final class LongVector64 extends LongVector { static final LongSpecies VSPECIES = (LongSpecies) LongVector.SPECIES_64; @@ -558,7 +560,7 @@ final class LongVector64 extends LongVector { } // Mask - + @ValueBased static final class LongMask64 extends AbstractMask { static final int VLENGTH = VSPECIES.laneCount(); // used by the JVM @@ -791,7 +793,7 @@ final class LongVector64 extends LongVector { } // Shuffle - + @ValueBased static final class LongShuffle64 extends AbstractShuffle { static final int VLENGTH = VSPECIES.laneCount(); // used by the JVM diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVectorMax.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVectorMax.java index 3469da8f2f4..4752959f884 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVectorMax.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVectorMax.java @@ -31,6 +31,7 @@ import java.util.Arrays; import java.util.Objects; import java.util.function.IntUnaryOperator; +import jdk.internal.ValueBased; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.vector.VectorSupport; @@ -41,6 +42,7 @@ import static jdk.incubator.vector.VectorOperators.*; // -- This file was mechanically generated: Do not edit! -- // @SuppressWarnings("cast") // warning: redundant cast +@ValueBased final class LongVectorMax extends LongVector { static final LongSpecies VSPECIES = (LongSpecies) LongVector.SPECIES_MAX; @@ -558,7 +560,7 @@ final class LongVectorMax extends LongVector { } // Mask - + @ValueBased static final class LongMaskMax extends AbstractMask { static final int VLENGTH = VSPECIES.laneCount(); // used by the JVM @@ -791,7 +793,7 @@ final class LongVectorMax extends LongVector { } // Shuffle - + @ValueBased static final class LongShuffleMax extends AbstractShuffle { static final int VLENGTH = VSPECIES.laneCount(); // used by the JVM diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector128.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector128.java index e989cdbdbea..89ec97c6be0 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector128.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector128.java @@ -31,6 +31,7 @@ import java.util.Arrays; import java.util.Objects; import java.util.function.IntUnaryOperator; +import jdk.internal.ValueBased; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.vector.VectorSupport; @@ -41,6 +42,7 @@ import static jdk.incubator.vector.VectorOperators.*; // -- This file was mechanically generated: Do not edit! -- // @SuppressWarnings("cast") // warning: redundant cast +@ValueBased final class ShortVector128 extends ShortVector { static final ShortSpecies VSPECIES = (ShortSpecies) ShortVector.SPECIES_128; @@ -582,7 +584,7 @@ final class ShortVector128 extends ShortVector { } // Mask - + @ValueBased static final class ShortMask128 extends AbstractMask { static final int VLENGTH = VSPECIES.laneCount(); // used by the JVM @@ -815,7 +817,7 @@ final class ShortVector128 extends ShortVector { } // Shuffle - + @ValueBased static final class ShortShuffle128 extends AbstractShuffle { static final int VLENGTH = VSPECIES.laneCount(); // used by the JVM diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector256.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector256.java index c74188e22f5..0f5751c27d8 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector256.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector256.java @@ -31,6 +31,7 @@ import java.util.Arrays; import java.util.Objects; import java.util.function.IntUnaryOperator; +import jdk.internal.ValueBased; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.vector.VectorSupport; @@ -41,6 +42,7 @@ import static jdk.incubator.vector.VectorOperators.*; // -- This file was mechanically generated: Do not edit! -- // @SuppressWarnings("cast") // warning: redundant cast +@ValueBased final class ShortVector256 extends ShortVector { static final ShortSpecies VSPECIES = (ShortSpecies) ShortVector.SPECIES_256; @@ -598,7 +600,7 @@ final class ShortVector256 extends ShortVector { } // Mask - + @ValueBased static final class ShortMask256 extends AbstractMask { static final int VLENGTH = VSPECIES.laneCount(); // used by the JVM @@ -831,7 +833,7 @@ final class ShortVector256 extends ShortVector { } // Shuffle - + @ValueBased static final class ShortShuffle256 extends AbstractShuffle { static final int VLENGTH = VSPECIES.laneCount(); // used by the JVM diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector512.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector512.java index 46b5d652200..3d38dfd88fd 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector512.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector512.java @@ -31,6 +31,7 @@ import java.util.Arrays; import java.util.Objects; import java.util.function.IntUnaryOperator; +import jdk.internal.ValueBased; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.vector.VectorSupport; @@ -41,6 +42,7 @@ import static jdk.incubator.vector.VectorOperators.*; // -- This file was mechanically generated: Do not edit! -- // @SuppressWarnings("cast") // warning: redundant cast +@ValueBased final class ShortVector512 extends ShortVector { static final ShortSpecies VSPECIES = (ShortSpecies) ShortVector.SPECIES_512; @@ -630,7 +632,7 @@ final class ShortVector512 extends ShortVector { } // Mask - + @ValueBased static final class ShortMask512 extends AbstractMask { static final int VLENGTH = VSPECIES.laneCount(); // used by the JVM @@ -863,7 +865,7 @@ final class ShortVector512 extends ShortVector { } // Shuffle - + @ValueBased static final class ShortShuffle512 extends AbstractShuffle { static final int VLENGTH = VSPECIES.laneCount(); // used by the JVM diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector64.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector64.java index 66ff3efe522..b319d98f784 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector64.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector64.java @@ -31,6 +31,7 @@ import java.util.Arrays; import java.util.Objects; import java.util.function.IntUnaryOperator; +import jdk.internal.ValueBased; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.vector.VectorSupport; @@ -41,6 +42,7 @@ import static jdk.incubator.vector.VectorOperators.*; // -- This file was mechanically generated: Do not edit! -- // @SuppressWarnings("cast") // warning: redundant cast +@ValueBased final class ShortVector64 extends ShortVector { static final ShortSpecies VSPECIES = (ShortSpecies) ShortVector.SPECIES_64; @@ -574,7 +576,7 @@ final class ShortVector64 extends ShortVector { } // Mask - + @ValueBased static final class ShortMask64 extends AbstractMask { static final int VLENGTH = VSPECIES.laneCount(); // used by the JVM @@ -807,7 +809,7 @@ final class ShortVector64 extends ShortVector { } // Shuffle - + @ValueBased static final class ShortShuffle64 extends AbstractShuffle { static final int VLENGTH = VSPECIES.laneCount(); // used by the JVM diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVectorMax.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVectorMax.java index b9a9b85126b..69b298857c9 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVectorMax.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVectorMax.java @@ -31,6 +31,7 @@ import java.util.Arrays; import java.util.Objects; import java.util.function.IntUnaryOperator; +import jdk.internal.ValueBased; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.vector.VectorSupport; @@ -41,6 +42,7 @@ import static jdk.incubator.vector.VectorOperators.*; // -- This file was mechanically generated: Do not edit! -- // @SuppressWarnings("cast") // warning: redundant cast +@ValueBased final class ShortVectorMax extends ShortVector { static final ShortSpecies VSPECIES = (ShortSpecies) ShortVector.SPECIES_MAX; @@ -568,7 +570,7 @@ final class ShortVectorMax extends ShortVector { } // Mask - + @ValueBased static final class ShortMaskMax extends AbstractMask { static final int VLENGTH = VSPECIES.laneCount(); // used by the JVM @@ -801,7 +803,7 @@ final class ShortVectorMax extends ShortVector { } // Shuffle - + @ValueBased static final class ShortShuffleMax extends AbstractShuffle { static final int VLENGTH = VSPECIES.laneCount(); // used by the JVM diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-VectorBits.java.template b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-VectorBits.java.template index bbf02f9c6cd..35041a0b70f 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-VectorBits.java.template +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-VectorBits.java.template @@ -31,6 +31,7 @@ import java.util.Arrays; import java.util.Objects; import java.util.function.IntUnaryOperator; +import jdk.internal.ValueBased; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.vector.VectorSupport; @@ -41,6 +42,7 @@ import static jdk.incubator.vector.VectorOperators.*; #warn This file is preprocessed before being compiled @SuppressWarnings("cast") // warning: redundant cast +@ValueBased final class $vectortype$ extends $abstractvectortype$ { static final $Type$Species VSPECIES = ($Type$Species) $Type$Vector.SPECIES_$BITS$; @@ -855,7 +857,7 @@ final class $vectortype$ extends $abstractvectortype$ { #end[FP] // Mask - + @ValueBased static final class $masktype$ extends AbstractMask<$Boxtype$> { static final int VLENGTH = VSPECIES.laneCount(); // used by the JVM @@ -1103,7 +1105,7 @@ final class $vectortype$ extends $abstractvectortype$ { } // Shuffle - + @ValueBased static final class $shuffletype$ extends AbstractShuffle<$Boxtype$> { static final int VLENGTH = VSPECIES.laneCount(); // used by the JVM From c64f7357a536a7577432964ea8ce723c5373a184 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Thu, 26 Mar 2026 08:19:31 +0000 Subject: [PATCH 043/359] 8379516: Adjust JVM debug helper exports Reviewed-by: kbarrett, lucy, clanger --- src/hotspot/share/utilities/debug.cpp | 104 +++++++++++++++++--------- 1 file changed, 69 insertions(+), 35 deletions(-) diff --git a/src/hotspot/share/utilities/debug.cpp b/src/hotspot/share/utilities/debug.cpp index e8533e29460..23e8281f000 100644 --- a/src/hotspot/share/utilities/debug.cpp +++ b/src/hotspot/share/utilities/debug.cpp @@ -342,20 +342,20 @@ class Command : public StackObj { int Command::level = 0; -extern "C" DEBUGEXPORT void blob(CodeBlob* cb) { +extern "C" NOINLINE void blob(CodeBlob* cb) { Command c("blob"); cb->print(); } -extern "C" DEBUGEXPORT void dump_vtable(address p) { +extern "C" NOINLINE void dump_vtable(address p) { Command c("dump_vtable"); Klass* k = (Klass*)p; k->vtable().print(); } -extern "C" DEBUGEXPORT void nm(intptr_t p) { +extern "C" NOINLINE void nm(intptr_t p) { // Actually we look through all CodeBlobs (the nm name has been kept for backwards compatibility) Command c("nm"); CodeBlob* cb = CodeCache::find_blob((address)p); @@ -367,7 +367,7 @@ extern "C" DEBUGEXPORT void nm(intptr_t p) { } -extern "C" DEBUGEXPORT void disnm(intptr_t p) { +extern "C" NOINLINE void disnm(intptr_t p) { Command c("disnm"); CodeBlob* cb = CodeCache::find_blob((address) p); if (cb != nullptr) { @@ -382,7 +382,7 @@ extern "C" DEBUGEXPORT void disnm(intptr_t p) { } -extern "C" DEBUGEXPORT void printnm(intptr_t p) { +extern "C" NOINLINE void printnm(intptr_t p) { char buffer[256]; os::snprintf_checked(buffer, sizeof(buffer), "printnm: " INTPTR_FORMAT, p); Command c(buffer); @@ -396,14 +396,14 @@ extern "C" DEBUGEXPORT void printnm(intptr_t p) { } -extern "C" DEBUGEXPORT void universe() { +extern "C" NOINLINE void universe() { Command c("universe"); if (!c.onThread()) return; Universe::print_on(tty); } -extern "C" DEBUGEXPORT void verify() { +extern "C" NOINLINE void verify() { // try to run a verify on the entire system // note: this may not be safe if we're not at a safepoint; for debugging, // this manipulates the safepoint settings to avoid assertion failures @@ -421,7 +421,7 @@ extern "C" DEBUGEXPORT void verify() { } -extern "C" DEBUGEXPORT void pp(void* p) { +extern "C" NOINLINE void pp(void* p) { Command c("pp"); if (!c.onThread()) return; FlagSetting fl(DisplayVMOutput, true); @@ -445,7 +445,7 @@ extern "C" DEBUGEXPORT void pp(void* p) { } -extern "C" DEBUGEXPORT void ps() { // print stack +extern "C" NOINLINE void ps() { // print stack // Prints the stack of the current Java thread Command c("ps"); if (!c.onThread()) return; @@ -477,7 +477,7 @@ extern "C" DEBUGEXPORT void ps() { // print stack } } -extern "C" DEBUGEXPORT void pfl() { +extern "C" NOINLINE void pfl() { // print frame layout Command c("pfl"); if (!c.onThread()) return; @@ -494,7 +494,7 @@ extern "C" DEBUGEXPORT void pfl() { } } -extern "C" DEBUGEXPORT void psf() { // print stack frames +extern "C" NOINLINE void psf() { // print stack frames Command c("psf"); if (!c.onThread()) return; JavaThread* p = JavaThread::active(); @@ -511,21 +511,21 @@ extern "C" DEBUGEXPORT void psf() { // print stack frames } -extern "C" DEBUGEXPORT void threads() { +extern "C" NOINLINE void threads() { Command c("threads"); if (!c.onThread()) return; Threads::print(false, true); } -extern "C" DEBUGEXPORT void psd() { +extern "C" NOINLINE void psd() { Command c("psd"); if (!c.onThread()) return; SystemDictionary::print(); } -extern "C" DEBUGEXPORT void pss() { // print all stacks +extern "C" NOINLINE void pss() { // print all stacks Command c("pss"); if (!c.onThread()) return; Threads::print(true, PRODUCT_ONLY(false) NOT_PRODUCT(true)); @@ -533,7 +533,7 @@ extern "C" DEBUGEXPORT void pss() { // print all stacks // #ifndef PRODUCT -extern "C" DEBUGEXPORT void debug() { // to set things up for compiler debugging +extern "C" NOINLINE void debug() { // to set things up for compiler debugging Command c("debug"); NOT_PRODUCT(WizardMode = true;) PrintCompilation = true; @@ -542,7 +542,7 @@ extern "C" DEBUGEXPORT void debug() { // to set things up for comp } -extern "C" DEBUGEXPORT void ndebug() { // undo debug() +extern "C" NOINLINE void ndebug() { // undo debug() Command c("ndebug"); PrintCompilation = false; PrintInlining = PrintAssembly = false; @@ -550,36 +550,36 @@ extern "C" DEBUGEXPORT void ndebug() { // undo debug() } -extern "C" DEBUGEXPORT void flush() { +extern "C" NOINLINE void flush() { Command c("flush"); tty->flush(); } -extern "C" DEBUGEXPORT void events() { +extern "C" NOINLINE void events() { Command c("events"); Events::print(); } -extern "C" DEBUGEXPORT Method* findm(intptr_t pc) { +extern "C" NOINLINE Method* findm(intptr_t pc) { Command c("findm"); nmethod* nm = CodeCache::find_nmethod((address)pc); return (nm == nullptr) ? (Method*)nullptr : nm->method(); } -extern "C" DEBUGEXPORT nmethod* findnm(intptr_t addr) { +extern "C" NOINLINE nmethod* findnm(intptr_t addr) { Command c("findnm"); return CodeCache::find_nmethod((address)addr); } -extern "C" DEBUGEXPORT void find(intptr_t x) { +extern "C" NOINLINE void find(intptr_t x) { Command c("find"); if (!c.onThread()) return; os::print_location(tty, x, false); } -extern "C" DEBUGEXPORT void findpc(intptr_t x) { +extern "C" NOINLINE void findpc(intptr_t x) { Command c("findpc"); if (!c.onThread()) return; os::print_location(tty, x, true); @@ -591,15 +591,14 @@ extern "C" DEBUGEXPORT void findpc(intptr_t x) { // call findclass("java/lang/Object", 0x3) -> find j.l.Object and disasm all of its methods // call findmethod("*ang/Object*", "wait", 0xff) -> detailed disasm of all "wait" methods in j.l.Object // call findmethod("*ang/Object*", "wait:(*J*)V", 0x1) -> list all "wait" methods in j.l.Object that have a long parameter -extern "C" DEBUGEXPORT void findclass(const char* class_name_pattern, int flags) { +extern "C" NOINLINE void findclass(const char* class_name_pattern, int flags) { Command c("findclass"); if (!c.onThread()) return; ClassPrinter::print_flags_help(tty); ClassPrinter::print_classes(class_name_pattern, flags, tty); } -extern "C" DEBUGEXPORT void findmethod(const char* class_name_pattern, - const char* method_pattern, int flags) { +extern "C" NOINLINE void findmethod(const char* class_name_pattern, const char* method_pattern, int flags) { Command c("findmethod"); if (!c.onThread()) return; ClassPrinter::print_flags_help(tty); @@ -607,7 +606,7 @@ extern "C" DEBUGEXPORT void findmethod(const char* class_name_pattern, } // Need method pointer to find bcp -extern "C" DEBUGEXPORT void findbcp(intptr_t method, intptr_t bcp) { +extern "C" NOINLINE void findbcp(intptr_t method, intptr_t bcp) { Command c("findbcp"); Method* mh = (Method*)method; if (!mh->is_native()) { @@ -618,7 +617,7 @@ extern "C" DEBUGEXPORT void findbcp(intptr_t method, intptr_t bcp) { } // check and decode a single u5 value -extern "C" DEBUGEXPORT u4 u5decode(intptr_t addr) { +extern "C" NOINLINE u4 u5decode(intptr_t addr) { Command c("u5decode"); u1* arr = (u1*)addr; size_t off = 0, lim = 5; @@ -635,9 +634,7 @@ extern "C" DEBUGEXPORT u4 u5decode(intptr_t addr) { // there is no limit on the count of items printed; the // printing stops when an null is printed or at limit. // See documentation for UNSIGNED5::Reader::print(count). -extern "C" DEBUGEXPORT intptr_t u5p(intptr_t addr, - intptr_t limit, - int count) { +extern "C" NOINLINE intptr_t u5p(intptr_t addr, intptr_t limit, int count) { Command c("u5p"); u1* arr = (u1*)addr; if (limit && limit < addr) limit = addr; @@ -650,10 +647,10 @@ extern "C" DEBUGEXPORT intptr_t u5p(intptr_t addr, // int versions of all methods to avoid having to type type casts in the debugger -void pp(intptr_t p) { pp((void*)p); } -void pp(oop p) { pp((void*)p); } +NOINLINE void pp(intptr_t p) { pp((void*)p); } +NOINLINE void pp(oop p) { pp((void*)p); } -extern "C" DEBUGEXPORT void help() { +extern "C" NOINLINE void help() { Command c("help"); tty->print_cr("basic"); tty->print_cr(" pp(void* p) - try to make sense of p"); @@ -709,7 +706,7 @@ extern "C" DEBUGEXPORT void help() { } #ifndef PRODUCT -extern "C" DEBUGEXPORT void pns(void* sp, void* fp, void* pc) { // print native stack +extern "C" NOINLINE void pns(void* sp, void* fp, void* pc) { // print native stack Command c("pns"); if (!c.onThread()) return; static char buf[O_BUFLEN]; @@ -728,7 +725,7 @@ extern "C" DEBUGEXPORT void pns(void* sp, void* fp, void* pc) { // print native // WARNING: Only intended for use when debugging. Do not leave calls to // pns2() in committed source (product or debug). // -extern "C" DEBUGEXPORT void pns2() { // print native stack +extern "C" NOINLINE void pns2() { // print native stack Command c("pns2"); if (!c.onThread()) return; static char buf[O_BUFLEN]; @@ -739,6 +736,43 @@ extern "C" DEBUGEXPORT void pns2() { // print native stack } #endif +// just an exported helper; to avoid link time elimination of the referenced functions +extern "C" JNIEXPORT void JVM_debug_helpers_keeper(void* p1, void* p2, void* p3, intptr_t ip, oop oh, address adr) { + blob((CodeBlob*)p1); + dump_vtable(adr); + nm(ip); + disnm(ip); + printnm(ip); + universe(); + verify(); + pp(p1); + ps(); + pfl(); + psf(); + threads(); + psd(); + pss(); + debug(); + ndebug(); + flush(); + events(); + findm(ip); + findnm(ip); + find(ip); + findpc(ip); + findclass("", 0); + findmethod("", "", 0); + findbcp(ip, ip); + u5decode(ip); + u5p(ip, ip, 0); + pp(ip); + pp(oh); + help(); +#ifndef PRODUCT + pns(p1, p2, p3); + pns2(); +#endif +} // Returns true iff the address p is readable and *(intptr_t*)p != errvalue extern "C" bool dbg_is_safe(const void* p, intptr_t errvalue) { From aea8947e9df84bf583ef658c5bf5f61ad87b73fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20=C3=96sterlund?= Date: Thu, 26 Mar 2026 09:29:53 +0000 Subject: [PATCH 044/359] 8378176: Concurrent GC worker threads may suffer from priority inversion Reviewed-by: kbarrett, ayang, tschatzl --- src/hotspot/share/gc/shared/concurrentGCThread.cpp | 3 +-- src/hotspot/share/gc/shared/concurrentGCThread.hpp | 2 +- src/hotspot/share/gc/shared/workerThread.cpp | 2 -- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/hotspot/share/gc/shared/concurrentGCThread.cpp b/src/hotspot/share/gc/shared/concurrentGCThread.cpp index ed6c1b4d283..c7765631cd9 100644 --- a/src/hotspot/share/gc/shared/concurrentGCThread.cpp +++ b/src/hotspot/share/gc/shared/concurrentGCThread.cpp @@ -33,9 +33,8 @@ ConcurrentGCThread::ConcurrentGCThread() : _should_terminate(false), _has_terminated(false) {} -void ConcurrentGCThread::create_and_start(ThreadPriority prio) { +void ConcurrentGCThread::create_and_start() { if (os::create_thread(this, os::gc_thread)) { - os::set_priority(this, prio); os::start_thread(this); } } diff --git a/src/hotspot/share/gc/shared/concurrentGCThread.hpp b/src/hotspot/share/gc/shared/concurrentGCThread.hpp index 0c764546045..5322d676493 100644 --- a/src/hotspot/share/gc/shared/concurrentGCThread.hpp +++ b/src/hotspot/share/gc/shared/concurrentGCThread.hpp @@ -36,7 +36,7 @@ private: Atomic _has_terminated; protected: - void create_and_start(ThreadPriority prio = NearMaxPriority); + void create_and_start(); virtual void run_service() = 0; virtual void stop_service() = 0; diff --git a/src/hotspot/share/gc/shared/workerThread.cpp b/src/hotspot/share/gc/shared/workerThread.cpp index 2f6f003608f..2738c98e5c3 100644 --- a/src/hotspot/share/gc/shared/workerThread.cpp +++ b/src/hotspot/share/gc/shared/workerThread.cpp @@ -210,8 +210,6 @@ WorkerThread::WorkerThread(const char* name_prefix, uint name_suffix, WorkerTask } void WorkerThread::run() { - os::set_priority(this, NearMaxPriority); - while (true) { _dispatcher->worker_run_task(); } From ab659d4ee48b33a4bad21857b02f0a29314f2b43 Mon Sep 17 00:00:00 2001 From: Dusan Balek Date: Thu, 26 Mar 2026 10:19:37 +0000 Subject: [PATCH 045/359] 8371817: javac with annotation processor throws AssertionError: Cannot add metadata to this type: METHOD when dealing with local classes Reviewed-by: mcimadamore --- .../com/sun/tools/javac/jvm/ClassReader.java | 9 +- .../classfile/LocalClassesTest.java | 163 ++++++++++++++++++ 2 files changed, 168 insertions(+), 4 deletions(-) create mode 100644 test/langtools/tools/javac/annotations/typeAnnotations/classfile/LocalClassesTest.java diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java index 017d740dc0a..08ba0442781 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java @@ -1367,9 +1367,7 @@ public class ClassReader { else self.fullname = ClassSymbol.formFullName(self.name, self.owner); - if (m != null) { - ((ClassType)sym.type).setEnclosingType(m.type); - } else if ((self.flags_field & STATIC) == 0) { + if ((self.flags_field & STATIC) == 0 && (m == null || (m.flags_field & STATIC) == 0)) { ((ClassType)sym.type).setEnclosingType(c.type); } else { ((ClassType)sym.type).setEnclosingType(Type.noType); @@ -2687,6 +2685,7 @@ public class ClassReader { // won't pass the "hasOuterInstance" check above, but those that don't have an // enclosing method (i.e. from initializers) will pass that check. boolean local = forceLocal = + currentOwner.owner.kind != TYP || !currentOwner.owner.members().includes(currentOwner, LookupKind.NON_RECURSIVE); if (!currentOwner.name.isEmpty() && !local) type = new MethodType(adjustMethodParams(flags, type.getParameterTypes()), @@ -3038,7 +3037,9 @@ public class ClassReader { * `typevars'. */ protected void enterTypevars(Symbol sym, Type t) { - if (t.getEnclosingType() != null) { + if (sym.owner.kind == MTH) { + enterTypevars(sym.owner, sym.owner.type); + } else if (t.getEnclosingType() != null) { if (!t.getEnclosingType().hasTag(TypeTag.NONE)) { enterTypevars(sym.owner, t.getEnclosingType()); } diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/classfile/LocalClassesTest.java b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/LocalClassesTest.java new file mode 100644 index 00000000000..66b55c8d209 --- /dev/null +++ b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/LocalClassesTest.java @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8371817 + * @summary Check for type annotating types that refer to local classes read + * from classfiles + * @library /tools/lib + * @modules + * jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * @build toolbox.ToolBox toolbox.JavacTask + * @run junit LocalClassesTest + */ + +import com.sun.source.tree.ClassTree; +import com.sun.source.util.TaskEvent; +import com.sun.source.util.TaskListener; +import com.sun.source.util.TreePathScanner; +import com.sun.source.util.Trees; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import javax.annotation.processing.AbstractProcessor; +import javax.annotation.processing.RoundEnvironment; +import javax.annotation.processing.SupportedAnnotationTypes; +import javax.lang.model.SourceVersion; +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.ElementFilter; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInfo; +import toolbox.JavacTask; +import toolbox.ToolBox; + +public class LocalClassesTest { + + ToolBox tb = new ToolBox(); + Path base; + + @Test + void test() throws Exception { + Path classes = base.resolve("classes"); + Files.createDirectories(classes); + + Map local2enclosing = new HashMap<>(); + new JavacTask(tb) + .options("-d", classes.toString()) + .sources(""" + import java.lang.annotation.ElementType; + import java.lang.annotation.Target; + + public class Test { + public static void m1() { + class Local1 { + @Nullable Local1 l; + } + } + public void m2() { + class Local2 { + @Nullable Local2 l; + } + } + } + + @Target({ElementType.TYPE_USE}) + @interface Nullable {} + """) + .callback(task -> { + task.addTaskListener(new TaskListener() { + @Override + public void finished(TaskEvent e) { + if (e.getKind() == TaskEvent.Kind.ANALYZE) { + Trees trees = Trees.instance(task); + new TreePathScanner<>() { + @Override + public Object visitClass(ClassTree node, Object p) { + if (node.getSimpleName().toString().startsWith("Local")) { + Element el = trees.getElement(getCurrentPath()); + TypeMirror type = trees.getTypeMirror(getCurrentPath()); + local2enclosing.put(el.getSimpleName().toString(), ((DeclaredType) type).getEnclosingType().toString()); + } + return super.visitClass(node, p); + } + }.scan(e.getCompilationUnit(), null); + } + } + }); + }) + .run() + .writeAll(); + + Path classes2 = base.resolve("classes2"); + Files.createDirectories(classes2); + + ProcessorImpl p = new ProcessorImpl(); + new JavacTask(tb) + .options("-cp", classes.toString(), "-d", classes2.toString()) + .processors(p) + .classes("Test$1Local1", "Test$1Local2") + .run() + .writeAll(); + + Assertions.assertEquals(local2enclosing.get("Local1"), p.local2enclosing.get("Local1")); + Assertions.assertEquals(local2enclosing.get("Local2"), p.local2enclosing.get("Local2")); + } + + @SupportedAnnotationTypes("*") + private static class ProcessorImpl extends AbstractProcessor { + private Map local2enclosing = new HashMap<>(); + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + for (TypeElement te : ElementFilter.typesIn(roundEnv.getRootElements())) { + if (te.getSimpleName().toString().startsWith("Local")) { + local2enclosing.put(te.getSimpleName().toString(), ((DeclaredType) te.asType()).getEnclosingType().toString()); + } + } + return false; + } + + @Override + public SourceVersion getSupportedSourceVersion() { + return SourceVersion.latestSupported(); + } + } + + @BeforeEach + public void setup(TestInfo info) { + base = Paths.get(".") + .resolve(info.getTestMethod() + .orElseThrow() + .getName()); + } +} From da296cbea1603e8b1de46c9daafced76fce921e6 Mon Sep 17 00:00:00 2001 From: Thomas Stuefe Date: Thu, 26 Mar 2026 11:08:48 +0000 Subject: [PATCH 046/359] 8363996: Obsolete UseCompressedClassPointers Reviewed-by: rkennke, kvn, adinn, dholmes, mdoerr, iklam, fyang --- src/hotspot/cpu/aarch64/aarch64.ad | 12 +- .../cpu/aarch64/c1_LIRAssembler_aarch64.cpp | 27 +- .../cpu/aarch64/c1_LIRGenerator_aarch64.cpp | 10 +- .../cpu/aarch64/c1_MacroAssembler_aarch64.cpp | 12 +- .../cpu/aarch64/macroAssembler_aarch64.cpp | 74 ++---- src/hotspot/cpu/arm/matcher_arm.hpp | 3 +- src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp | 4 +- src/hotspot/cpu/ppc/macroAssembler_ppc.cpp | 65 ++--- src/hotspot/cpu/ppc/matcher_ppc.hpp | 1 - .../riscv/c1_LIRAssembler_arraycopy_riscv.cpp | 11 +- .../cpu/riscv/c1_LIRAssembler_riscv.cpp | 24 +- .../cpu/riscv/c1_LIRGenerator_riscv.cpp | 10 +- .../cpu/riscv/c1_MacroAssembler_riscv.cpp | 12 +- .../cpu/riscv/c2_MacroAssembler_riscv.cpp | 15 +- .../cpu/riscv/macroAssembler_riscv.cpp | 34 +-- src/hotspot/cpu/riscv/riscv.ad | 9 +- src/hotspot/cpu/riscv/stubGenerator_riscv.cpp | 8 +- src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp | 15 +- .../cpu/s390/c1_MacroAssembler_s390.cpp | 8 +- src/hotspot/cpu/s390/macroAssembler_s390.cpp | 176 ++++++------- src/hotspot/cpu/s390/macroAssembler_s390.hpp | 5 +- src/hotspot/cpu/s390/matcher_s390.hpp | 3 +- src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp | 39 +-- src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp | 10 +- src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp | 9 +- src/hotspot/cpu/x86/macroAssembler_x86.cpp | 38 +-- src/hotspot/cpu/x86/macroAssembler_x86.hpp | 3 +- src/hotspot/cpu/x86/matcher_x86.hpp | 3 +- src/hotspot/cpu/x86/x86.ad | 9 +- src/hotspot/share/cds/aotMapLogger.cpp | 1 - src/hotspot/share/cds/aotMappedHeapLoader.hpp | 2 +- src/hotspot/share/cds/aotMappedHeapWriter.cpp | 2 - src/hotspot/share/cds/aotMetaspace.cpp | 222 ++++++++--------- .../share/cds/aotStreamedHeapWriter.cpp | 1 - src/hotspot/share/cds/archiveBuilder.cpp | 7 +- src/hotspot/share/cds/archiveBuilder.hpp | 2 - src/hotspot/share/cds/archiveUtils.cpp | 4 +- src/hotspot/share/cds/cdsConfig.cpp | 4 - src/hotspot/share/cds/filemap.cpp | 24 +- src/hotspot/share/cds/filemap.hpp | 2 - .../classfile/systemDictionaryShared.cpp | 4 +- src/hotspot/share/code/aotCodeCache.cpp | 7 - src/hotspot/share/code/aotCodeCache.hpp | 11 +- src/hotspot/share/code/compiledIC.cpp | 15 +- .../share/gc/shared/c2/barrierSetC2.cpp | 1 - src/hotspot/share/gc/shared/gcTrace.cpp | 9 +- .../share/gc/shenandoah/shenandoahAsserts.cpp | 32 ++- src/hotspot/share/gc/z/c2/zBarrierSetC2.cpp | 4 +- src/hotspot/share/gc/z/zDebug.gdb | 6 +- .../types/traceid/jfrTraceIdKlassQueue.cpp | 4 +- .../share/jvmci/jvmciCompilerToVMInit.cpp | 10 +- src/hotspot/share/jvmci/vmStructs_jvmci.cpp | 4 +- .../share/memory/classLoaderMetaspace.cpp | 6 +- .../share/memory/classLoaderMetaspace.hpp | 17 +- src/hotspot/share/memory/metaspace.cpp | 233 +++++++++--------- src/hotspot/share/memory/metaspace.hpp | 10 +- .../memory/metaspace/metaspaceReporter.cpp | 212 ++++++++-------- .../memory/metaspace/metaspaceStatistics.cpp | 30 ++- .../memory/metaspace/virtualSpaceNode.cpp | 11 +- src/hotspot/share/nmt/memReporter.cpp | 10 +- src/hotspot/share/oops/arrayOop.hpp | 5 +- src/hotspot/share/oops/compressedKlass.cpp | 33 ++- src/hotspot/share/oops/compressedKlass.hpp | 8 - .../share/oops/compressedKlass.inline.hpp | 4 +- src/hotspot/share/oops/instanceKlass.cpp | 6 +- src/hotspot/share/oops/klass.cpp | 12 +- src/hotspot/share/oops/objLayout.cpp | 10 +- src/hotspot/share/oops/objLayout.hpp | 10 +- src/hotspot/share/oops/objLayout.inline.hpp | 4 +- src/hotspot/share/oops/oop.cpp | 5 +- src/hotspot/share/oops/oop.hpp | 9 +- src/hotspot/share/oops/oop.inline.hpp | 33 +-- src/hotspot/share/opto/cfgnode.cpp | 2 +- src/hotspot/share/opto/chaitin.cpp | 4 +- src/hotspot/share/opto/compile.cpp | 8 +- src/hotspot/share/opto/lcm.cpp | 5 +- src/hotspot/share/opto/memnode.cpp | 4 +- src/hotspot/share/opto/narrowptrnode.cpp | 4 +- src/hotspot/share/opto/type.cpp | 2 +- src/hotspot/share/prims/whitebox.cpp | 1 - src/hotspot/share/runtime/arguments.cpp | 19 +- src/hotspot/share/runtime/globals.hpp | 3 - src/hotspot/share/runtime/os.cpp | 5 +- src/hotspot/share/runtime/vmStructs.cpp | 3 +- src/hotspot/share/services/memoryService.cpp | 12 +- src/hotspot/share/utilities/macros.hpp | 14 +- src/hotspot/share/utilities/vmError.cpp | 15 +- .../classes/sun/jvm/hotspot/oops/Array.java | 6 +- .../sun/jvm/hotspot/oops/Instance.java | 6 +- .../classes/sun/jvm/hotspot/oops/Oop.java | 21 +- .../classes/sun/jvm/hotspot/runtime/VM.java | 18 +- .../gtest/metaspace/test_is_metaspace_obj.cpp | 6 +- .../gtest/metaspace/test_metaspaceUtils.cpp | 61 ++--- test/hotspot/gtest/oops/test_arrayOop.cpp | 20 +- .../gtest/oops/test_compressedKlass.cpp | 30 --- test/hotspot/gtest/oops/test_objArrayOop.cpp | 40 ++- .../arraycopy/TestObjectArrayClone.java | 6 +- .../c1/TestArrayCopyToFromObject.java | 5 +- .../c2/TestReduceAllocationAndLoadKlass.java | 63 ----- .../AllocationMergesTests.java | 22 +- .../compilerToVM/GetResolvedJavaTypeTest.java | 3 +- .../jdk/vm/ci/code/test/DataPatchTest.java | 4 +- .../vm/ci/code/test/TestHotSpotVMConfig.java | 3 +- .../types/TestCheckCastPPBecomesTOP.java | 3 - .../jtreg/compiler/unsafe/OpaqueAccesses.java | 18 +- .../arguments/TestCompressedClassFlags.java | 53 ---- .../gc/g1/TestSharedArchiveWithPreTouch.java | 6 +- .../gc/metaspace/TestMetaspaceMemoryPool.java | 15 +- .../metaspace/TestMetaspacePerfCounters.java | 37 +-- .../TestPerfCountersAndMemoryPools.java | 7 +- .../gc/metaspace/TestSizeTransitions.java | 48 ++-- test/hotspot/jtreg/gtest/ArrayTests.java | 27 +- .../jtreg/gtest/CompressedKlassGtest.java | 10 +- test/hotspot/jtreg/gtest/MetaspaceGtests.java | 11 +- test/hotspot/jtreg/gtest/ObjArrayTests.java | 54 ++-- .../CDSCompressedKPtrs.java | 66 ----- .../CompressedClassPointers.java | 22 +- .../CompressedClassSpaceSize.java | 9 +- .../CompressedKlassPointerAndOops.java | 6 +- .../TestVMConfigInHsErrFile.java | 15 +- .../runtime/FieldLayout/BaseOffsets.java | 42 +--- .../runtime/FieldLayout/FieldDensityTest.java | 5 +- .../FieldLayout/TestOopMapSizeMinimal.java | 53 ++-- .../Metaspace/MaxMetaspaceSizeTest.java | 3 +- .../runtime/Metaspace/PrintMetaspaceDcmd.java | 60 +---- .../cds/appcds/CommandLineFlagCombo.java | 4 +- .../appcds/CommandLineFlagComboNegative.java | 8 +- .../cds/appcds/FillerObjectLoadTest.java | 53 ---- .../appcds/TestCombinedCompressedFlags.java | 87 +------ .../runtime/cds/appcds/TestZGCWithCDS.java | 62 +---- .../cds/appcds/aotCache/OldClassSupport2.java | 7 +- .../cacheObject/DifferentHeapSizes.java | 4 +- .../dynamicArchive/CDSStreamTestDriver.java | 4 +- .../DynamicArchiveTestBase.java | 7 +- .../sharedStrings/IncompatibleOptions.java | 16 +- .../dcmd/vm/ClassLoaderStatsTest.java | 15 +- .../ir_framework/tests/TestIRMatching.java | 19 -- .../GetObjectSizeIntrinsicsTest.java | 5 +- .../TestObjectAllocationInNewTLABEvent.java | 9 +- .../TestObjectAllocationOutsideTLABEvent.java | 9 +- ...ObjectAllocationSampleEventThrottling.java | 9 +- .../TestHeapSummaryEventDefNewSerial.java | 12 +- .../objectcount/ObjectCountEventVerifier.java | 4 +- ...CountAfterGCEventWithG1ConcurrentMark.java | 4 +- ...CountAfterGCEventWithG1FullCollection.java | 4 +- ...bjectCountAfterGCEventWithParallelOld.java | 4 +- ...TestObjectCountAfterGCEventWithSerial.java | 4 +- .../gc/objectcount/TestObjectCountEvent.java | 4 +- test/jtreg-ext/requires/VMProps.java | 11 +- 149 files changed, 952 insertions(+), 2093 deletions(-) delete mode 100644 test/hotspot/jtreg/compiler/c2/TestReduceAllocationAndLoadKlass.java delete mode 100644 test/hotspot/jtreg/gc/arguments/TestCompressedClassFlags.java delete mode 100644 test/hotspot/jtreg/runtime/CDSCompressedKPtrs/CDSCompressedKPtrs.java delete mode 100644 test/hotspot/jtreg/runtime/cds/appcds/FillerObjectLoadTest.java diff --git a/src/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad index b79030f07e7..05b2514a456 100644 --- a/src/hotspot/cpu/aarch64/aarch64.ad +++ b/src/hotspot/cpu/aarch64/aarch64.ad @@ -2233,15 +2233,9 @@ uint BoxLockNode::size(PhaseRegAlloc *ra_) const { void MachUEPNode::format(PhaseRegAlloc* ra_, outputStream* st) const { st->print_cr("# MachUEPNode"); - if (UseCompressedClassPointers) { - st->print_cr("\tldrw rscratch1, [j_rarg0 + oopDesc::klass_offset_in_bytes()]\t# compressed klass"); - st->print_cr("\tldrw r10, [rscratch2 + CompiledICData::speculated_klass_offset()]\t# compressed klass"); - st->print_cr("\tcmpw rscratch1, r10"); - } else { - st->print_cr("\tldr rscratch1, [j_rarg0 + oopDesc::klass_offset_in_bytes()]\t# compressed klass"); - st->print_cr("\tldr r10, [rscratch2 + CompiledICData::speculated_klass_offset()]\t# compressed klass"); - st->print_cr("\tcmp rscratch1, r10"); - } + st->print_cr("\tldrw rscratch1, [j_rarg0 + oopDesc::klass_offset_in_bytes()]\t# compressed klass"); + st->print_cr("\tldrw r10, [rscratch2 + CompiledICData::speculated_klass_offset()]\t# compressed klass"); + st->print_cr("\tcmpw rscratch1, r10"); st->print_cr("\tbne, SharedRuntime::_ic_miss_stub"); } #endif diff --git a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp index 30048a2079d..e7d8c2d3648 100644 --- a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -59,22 +59,6 @@ const Register SHIFT_count = r0; // where count for shift operations must be #define __ _masm-> -static void select_different_registers(Register preserve, - Register extra, - Register &tmp1, - Register &tmp2) { - if (tmp1 == preserve) { - assert_different_registers(tmp1, tmp2, extra); - tmp1 = extra; - } else if (tmp2 == preserve) { - assert_different_registers(tmp1, tmp2, extra); - tmp2 = extra; - } - assert_different_registers(preserve, tmp1, tmp2); -} - - - static void select_different_registers(Register preserve, Register extra, Register &tmp1, @@ -1269,12 +1253,9 @@ void LIR_Assembler::emit_typecheck_helper(LIR_OpTypeCheck *op, Label* success, L } else if (obj == klass_RInfo) { klass_RInfo = dst; } - if (k->is_loaded() && !UseCompressedClassPointers) { - select_different_registers(obj, dst, k_RInfo, klass_RInfo); - } else { - Rtmp1 = op->tmp3()->as_register(); - select_different_registers(obj, dst, k_RInfo, klass_RInfo, Rtmp1); - } + + Rtmp1 = op->tmp3()->as_register(); + select_different_registers(obj, dst, k_RInfo, klass_RInfo, Rtmp1); assert_different_registers(obj, k_RInfo, klass_RInfo); diff --git a/src/hotspot/cpu/aarch64/c1_LIRGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_LIRGenerator_aarch64.cpp index ad26d494b2d..f10c5197d91 100644 --- a/src/hotspot/cpu/aarch64/c1_LIRGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_LIRGenerator_aarch64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2026, 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. * @@ -1287,9 +1287,7 @@ void LIRGenerator::do_CheckCast(CheckCast* x) { } LIR_Opr reg = rlock_result(x); LIR_Opr tmp3 = LIR_OprFact::illegalOpr; - if (!x->klass()->is_loaded() || UseCompressedClassPointers) { - tmp3 = new_register(objectType); - } + tmp3 = new_register(objectType); __ checkcast(reg, obj.result(), x->klass(), new_register(objectType), new_register(objectType), tmp3, x->direct_compare(), info_for_exception, patching_info, stub, @@ -1308,9 +1306,7 @@ void LIRGenerator::do_InstanceOf(InstanceOf* x) { } obj.load_item(); LIR_Opr tmp3 = LIR_OprFact::illegalOpr; - if (!x->klass()->is_loaded() || UseCompressedClassPointers) { - tmp3 = new_register(objectType); - } + tmp3 = new_register(objectType); __ instanceof(reg, obj.result(), x->klass(), new_register(objectType), new_register(objectType), tmp3, x->direct_compare(), patching_info, x->profiled_method(), x->profiled_bci()); diff --git a/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp index e934632715c..89a9422ea48 100644 --- a/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2021, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -105,12 +105,8 @@ void C1_MacroAssembler::initialize_header(Register obj, Register klass, Register } else { mov(t1, checked_cast(markWord::prototype().value())); str(t1, Address(obj, oopDesc::mark_offset_in_bytes())); - if (UseCompressedClassPointers) { // Take care not to kill klass - encode_klass_not_null(t1, klass); - strw(t1, Address(obj, oopDesc::klass_offset_in_bytes())); - } else { - str(klass, Address(obj, oopDesc::klass_offset_in_bytes())); - } + encode_klass_not_null(t1, klass); // Take care not to kill klass + strw(t1, Address(obj, oopDesc::klass_offset_in_bytes())); } if (len->is_valid()) { @@ -121,7 +117,7 @@ void C1_MacroAssembler::initialize_header(Register obj, Register klass, Register // Clear gap/first 4 bytes following the length field. strw(zr, Address(obj, base_offset)); } - } else if (UseCompressedClassPointers && !UseCompactObjectHeaders) { + } else if (!UseCompactObjectHeaders) { store_klass_gap(obj, zr); } } diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp index 3e3e95be07e..732d94180ae 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp @@ -762,7 +762,7 @@ void MacroAssembler::call_VM_base(Register oop_result, assert(java_thread == rthread, "unexpected register"); #ifdef ASSERT // TraceBytecodes does not use r12 but saves it over the call, so don't verify - // if ((UseCompressedOops || UseCompressedClassPointers) && !TraceBytecodes) verify_heapbase("call_VM_base: heap base corrupted?"); + // if (!TraceBytecodes) verify_heapbase("call_VM_base: heap base corrupted?"); #endif // ASSERT assert(java_thread != oop_result , "cannot use the same register for java_thread & oop_result"); @@ -1002,14 +1002,10 @@ int MacroAssembler::ic_check(int end_alignment) { load_narrow_klass_compact(tmp1, receiver); ldrw(tmp2, Address(data, CompiledICData::speculated_klass_offset())); cmpw(tmp1, tmp2); - } else if (UseCompressedClassPointers) { + } else { ldrw(tmp1, Address(receiver, oopDesc::klass_offset_in_bytes())); ldrw(tmp2, Address(data, CompiledICData::speculated_klass_offset())); cmpw(tmp1, tmp2); - } else { - ldr(tmp1, Address(receiver, oopDesc::klass_offset_in_bytes())); - ldr(tmp2, Address(data, CompiledICData::speculated_klass_offset())); - cmp(tmp1, tmp2); } Label dont; @@ -3278,7 +3274,6 @@ int MacroAssembler::pop_p(unsigned int bitset, Register stack) { #ifdef ASSERT void MacroAssembler::verify_heapbase(const char* msg) { #if 0 - assert (UseCompressedOops || UseCompressedClassPointers, "should be compressed"); assert (Universe::heap() != nullptr, "java heap should be initialized"); if (!UseCompressedOops || Universe::ptr_base() == nullptr) { // rheapbase is allocated as general register @@ -5067,13 +5062,10 @@ void MacroAssembler::load_narrow_klass_compact(Register dst, Register src) { void MacroAssembler::load_klass(Register dst, Register src) { if (UseCompactObjectHeaders) { load_narrow_klass_compact(dst, src); - decode_klass_not_null(dst); - } else if (UseCompressedClassPointers) { - ldrw(dst, Address(src, oopDesc::klass_offset_in_bytes())); - decode_klass_not_null(dst); } else { - ldr(dst, Address(src, oopDesc::klass_offset_in_bytes())); + ldrw(dst, Address(src, oopDesc::klass_offset_in_bytes())); } + decode_klass_not_null(dst); } void MacroAssembler::restore_cpu_control_state_after_jni(Register tmp1, Register tmp2) { @@ -5125,25 +5117,21 @@ void MacroAssembler::load_mirror(Register dst, Register method, Register tmp1, R void MacroAssembler::cmp_klass(Register obj, Register klass, Register tmp) { assert_different_registers(obj, klass, tmp); - if (UseCompressedClassPointers) { - if (UseCompactObjectHeaders) { - load_narrow_klass_compact(tmp, obj); - } else { - ldrw(tmp, Address(obj, oopDesc::klass_offset_in_bytes())); - } - if (CompressedKlassPointers::base() == nullptr) { - cmp(klass, tmp, LSL, CompressedKlassPointers::shift()); - return; - } else if (((uint64_t)CompressedKlassPointers::base() & 0xffffffff) == 0 - && CompressedKlassPointers::shift() == 0) { - // Only the bottom 32 bits matter - cmpw(klass, tmp); - return; - } - decode_klass_not_null(tmp); + if (UseCompactObjectHeaders) { + load_narrow_klass_compact(tmp, obj); } else { - ldr(tmp, Address(obj, oopDesc::klass_offset_in_bytes())); + ldrw(tmp, Address(obj, oopDesc::klass_offset_in_bytes())); } + if (CompressedKlassPointers::base() == nullptr) { + cmp(klass, tmp, LSL, CompressedKlassPointers::shift()); + return; + } else if (((uint64_t)CompressedKlassPointers::base() & 0xffffffff) == 0 + && CompressedKlassPointers::shift() == 0) { + // Only the bottom 32 bits matter + cmpw(klass, tmp); + return; + } + decode_klass_not_null(tmp); cmp(klass, tmp); } @@ -5151,36 +5139,25 @@ void MacroAssembler::cmp_klasses_from_objects(Register obj1, Register obj2, Regi if (UseCompactObjectHeaders) { load_narrow_klass_compact(tmp1, obj1); load_narrow_klass_compact(tmp2, obj2); - cmpw(tmp1, tmp2); - } else if (UseCompressedClassPointers) { + } else { ldrw(tmp1, Address(obj1, oopDesc::klass_offset_in_bytes())); ldrw(tmp2, Address(obj2, oopDesc::klass_offset_in_bytes())); - cmpw(tmp1, tmp2); - } else { - ldr(tmp1, Address(obj1, oopDesc::klass_offset_in_bytes())); - ldr(tmp2, Address(obj2, oopDesc::klass_offset_in_bytes())); - cmp(tmp1, tmp2); } + cmpw(tmp1, tmp2); } void MacroAssembler::store_klass(Register dst, Register src) { // FIXME: Should this be a store release? concurrent gcs assumes // klass length is valid if klass field is not null. assert(!UseCompactObjectHeaders, "not with compact headers"); - if (UseCompressedClassPointers) { - encode_klass_not_null(src); - strw(src, Address(dst, oopDesc::klass_offset_in_bytes())); - } else { - str(src, Address(dst, oopDesc::klass_offset_in_bytes())); - } + encode_klass_not_null(src); + strw(src, Address(dst, oopDesc::klass_offset_in_bytes())); } void MacroAssembler::store_klass_gap(Register dst, Register src) { assert(!UseCompactObjectHeaders, "not with compact headers"); - if (UseCompressedClassPointers) { - // Store to klass gap in destination - strw(src, Address(dst, oopDesc::klass_gap_offset_in_bytes())); - } + // Store to klass gap in destination + strw(src, Address(dst, oopDesc::klass_gap_offset_in_bytes())); } // Algorithm must match CompressedOops::encode. @@ -5326,8 +5303,6 @@ MacroAssembler::KlassDecodeMode MacroAssembler::klass_decode_mode() { } MacroAssembler::KlassDecodeMode MacroAssembler::klass_decode_mode(address base, int shift, const size_t range) { - assert(UseCompressedClassPointers, "not using compressed class pointers"); - // KlassDecodeMode shouldn't be set already. assert(_klass_decode_mode == KlassDecodeNone, "set once"); @@ -5457,8 +5432,6 @@ void MacroAssembler::decode_klass_not_null_for_aot(Register dst, Register src) { } void MacroAssembler::decode_klass_not_null(Register dst, Register src) { - assert (UseCompressedClassPointers, "should only be used for compressed headers"); - if (AOTCodeCache::is_on_for_dump()) { decode_klass_not_null_for_aot(dst, src); return; @@ -5525,7 +5498,6 @@ void MacroAssembler::set_narrow_oop(Register dst, jobject obj) { } void MacroAssembler::set_narrow_klass(Register dst, Klass* k) { - assert (UseCompressedClassPointers, "should only be used for compressed headers"); assert (oop_recorder() != nullptr, "this assembler needs an OopRecorder"); int index = oop_recorder()->find_index(k); diff --git a/src/hotspot/cpu/arm/matcher_arm.hpp b/src/hotspot/cpu/arm/matcher_arm.hpp index 6c818e1f20d..7978a5b7090 100644 --- a/src/hotspot/cpu/arm/matcher_arm.hpp +++ b/src/hotspot/cpu/arm/matcher_arm.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * 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,7 +75,6 @@ static bool narrow_klass_use_complex_address() { NOT_LP64(ShouldNotCallThis()); - assert(UseCompressedClassPointers, "only for compressed klass code"); return false; } diff --git a/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp index 798451446e5..4d7af0e4a71 100644 --- a/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2025 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -144,7 +144,7 @@ void C1_MacroAssembler::initialize_header(Register obj, Register klass, Register if (len->is_valid()) { stw(len, arrayOopDesc::length_offset_in_bytes(), obj); - } else if (UseCompressedClassPointers && !UseCompactObjectHeaders) { + } else if (!UseCompactObjectHeaders) { // Otherwise length is in the class gap. store_klass_gap(obj); } diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp index 14e90ddf185..5fbcce94029 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp @@ -3201,23 +3201,17 @@ Register MacroAssembler::encode_klass_not_null(Register dst, Register src) { void MacroAssembler::store_klass(Register dst_oop, Register klass, Register ck) { assert(!UseCompactObjectHeaders, "not with compact headers"); - if (UseCompressedClassPointers) { - Register compressedKlass = encode_klass_not_null(ck, klass); - stw(compressedKlass, oopDesc::klass_offset_in_bytes(), dst_oop); - } else { - std(klass, oopDesc::klass_offset_in_bytes(), dst_oop); - } + Register compressedKlass = encode_klass_not_null(ck, klass); + stw(compressedKlass, oopDesc::klass_offset_in_bytes(), dst_oop); } void MacroAssembler::store_klass_gap(Register dst_oop, Register val) { assert(!UseCompactObjectHeaders, "not with compact headers"); - if (UseCompressedClassPointers) { - if (val == noreg) { - val = R0; - li(val, 0); - } - stw(val, oopDesc::klass_gap_offset_in_bytes(), dst_oop); + if (val == noreg) { + val = R0; + li(val, 0); } + stw(val, oopDesc::klass_gap_offset_in_bytes(), dst_oop); } int MacroAssembler::instr_size_for_decode_klass_not_null() { @@ -3226,17 +3220,13 @@ int MacroAssembler::instr_size_for_decode_klass_not_null() { // Not yet computed? if (computed_size == -1) { - if (!UseCompressedClassPointers) { - computed_size = 0; - } else { - // Determine by scratch emit. - ResourceMark rm; - int code_size = 8 * BytesPerInstWord; - CodeBuffer cb("decode_klass_not_null scratch buffer", code_size, 0); - MacroAssembler* a = new MacroAssembler(&cb); - a->decode_klass_not_null(R11_scratch1); - computed_size = a->offset(); - } + // Determine by scratch emit. + ResourceMark rm; + int code_size = 8 * BytesPerInstWord; + CodeBuffer cb("decode_klass_not_null scratch buffer", code_size, 0); + MacroAssembler* a = new MacroAssembler(&cb); + a->decode_klass_not_null(R11_scratch1); + computed_size = a->offset(); } return computed_size; @@ -3259,18 +3249,14 @@ void MacroAssembler::decode_klass_not_null(Register dst, Register src) { void MacroAssembler::load_klass_no_decode(Register dst, Register src) { if (UseCompactObjectHeaders) { load_narrow_klass_compact(dst, src); - } else if (UseCompressedClassPointers) { - lwz(dst, oopDesc::klass_offset_in_bytes(), src); } else { - ld(dst, oopDesc::klass_offset_in_bytes(), src); + lwz(dst, oopDesc::klass_offset_in_bytes(), src); } } void MacroAssembler::load_klass(Register dst, Register src) { load_klass_no_decode(dst, src); - if (UseCompressedClassPointers) { // also true for UseCompactObjectHeaders - decode_klass_not_null(dst); - } + decode_klass_not_null(dst); } // Loads the obj's Klass* into dst. @@ -3286,18 +3272,13 @@ void MacroAssembler::load_narrow_klass_compact(Register dst, Register src) { void MacroAssembler::cmp_klass(ConditionRegister dst, Register obj, Register klass, Register tmp, Register tmp2) { assert_different_registers(obj, klass, tmp); - if (UseCompressedClassPointers) { - if (UseCompactObjectHeaders) { - load_narrow_klass_compact(tmp, obj); - } else { - lwz(tmp, oopDesc::klass_offset_in_bytes(), obj); - } - Register encoded_klass = encode_klass_not_null(tmp2, klass); - cmpw(dst, tmp, encoded_klass); + if (UseCompactObjectHeaders) { + load_narrow_klass_compact(tmp, obj); } else { - ld(tmp, oopDesc::klass_offset_in_bytes(), obj); - cmpd(dst, tmp, klass); + lwz(tmp, oopDesc::klass_offset_in_bytes(), obj); } + Register encoded_klass = encode_klass_not_null(tmp2, klass); + cmpw(dst, tmp, encoded_klass); } void MacroAssembler::cmp_klasses_from_objects(ConditionRegister dst, Register obj1, Register obj2, Register tmp1, Register tmp2) { @@ -3305,14 +3286,10 @@ void MacroAssembler::cmp_klasses_from_objects(ConditionRegister dst, Register ob load_narrow_klass_compact(tmp1, obj1); load_narrow_klass_compact(tmp2, obj2); cmpw(dst, tmp1, tmp2); - } else if (UseCompressedClassPointers) { + } else { lwz(tmp1, oopDesc::klass_offset_in_bytes(), obj1); lwz(tmp2, oopDesc::klass_offset_in_bytes(), obj2); cmpw(dst, tmp1, tmp2); - } else { - ld(tmp1, oopDesc::klass_offset_in_bytes(), obj1); - ld(tmp2, oopDesc::klass_offset_in_bytes(), obj2); - cmpd(dst, tmp1, tmp2); } } diff --git a/src/hotspot/cpu/ppc/matcher_ppc.hpp b/src/hotspot/cpu/ppc/matcher_ppc.hpp index 2ddbec3e48c..cbe882648b8 100644 --- a/src/hotspot/cpu/ppc/matcher_ppc.hpp +++ b/src/hotspot/cpu/ppc/matcher_ppc.hpp @@ -87,7 +87,6 @@ static bool narrow_klass_use_complex_address() { NOT_LP64(ShouldNotCallThis()); - assert(UseCompressedClassPointers, "only for compressed klass code"); // TODO: PPC port if (MatchDecodeNodes) return true; return false; } diff --git a/src/hotspot/cpu/riscv/c1_LIRAssembler_arraycopy_riscv.cpp b/src/hotspot/cpu/riscv/c1_LIRAssembler_arraycopy_riscv.cpp index 819d6c05654..58eb1a55553 100644 --- a/src/hotspot/cpu/riscv/c1_LIRAssembler_arraycopy_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_LIRAssembler_arraycopy_riscv.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -196,12 +196,9 @@ void LIR_Assembler::arraycopy_type_check(Register src, Register src_pos, Registe if (UseCompactObjectHeaders) { __ load_narrow_klass_compact(tmp, src); __ load_narrow_klass_compact(t0, dst); - } else if (UseCompressedClassPointers) { + } else { __ lwu(tmp, Address(src, oopDesc::klass_offset_in_bytes())); __ lwu(t0, Address(dst, oopDesc::klass_offset_in_bytes())); - } else { - __ ld(tmp, Address(src, oopDesc::klass_offset_in_bytes())); - __ ld(t0, Address(dst, oopDesc::klass_offset_in_bytes())); } __ bne(tmp, t0, *stub->entry(), /* is_far */ true); } else { @@ -257,9 +254,7 @@ void LIR_Assembler::arraycopy_assert(Register src, Register dst, Register tmp, c // but not necessarily exactly of type default_type. Label known_ok, halt; __ mov_metadata(tmp, default_type->constant_encoding()); - if (UseCompressedClassPointers) { - __ encode_klass_not_null(tmp); - } + __ encode_klass_not_null(tmp); if (basic_type != T_OBJECT) { __ cmp_klass_compressed(dst, tmp, t0, halt, false); diff --git a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp index 63e2fd015d7..29e5d86d0cc 100644 --- a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved. * Copyright (c) 2020, 2023, Huawei Technologies Co., Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -55,20 +55,6 @@ const Register SHIFT_count = x10; // where count for shift operations must be #define __ _masm-> -static void select_different_registers(Register preserve, - Register extra, - Register &tmp1, - Register &tmp2) { - if (tmp1 == preserve) { - assert_different_registers(tmp1, tmp2, extra); - tmp1 = extra; - } else if (tmp2 == preserve) { - assert_different_registers(tmp1, tmp2, extra); - tmp2 = extra; - } - assert_different_registers(preserve, tmp1, tmp2); -} - static void select_different_registers(Register preserve, Register extra, Register &tmp1, @@ -1155,12 +1141,8 @@ void LIR_Assembler::emit_typecheck_helper(LIR_OpTypeCheck *op, Label* success, L } else if (obj == klass_RInfo) { klass_RInfo = dst; } - if (k->is_loaded() && !UseCompressedClassPointers) { - select_different_registers(obj, dst, k_RInfo, klass_RInfo); - } else { - Rtmp1 = op->tmp3()->as_register(); - select_different_registers(obj, dst, k_RInfo, klass_RInfo, Rtmp1); - } + Rtmp1 = op->tmp3()->as_register(); + select_different_registers(obj, dst, k_RInfo, klass_RInfo, Rtmp1); assert_different_registers(obj, k_RInfo, klass_RInfo); diff --git a/src/hotspot/cpu/riscv/c1_LIRGenerator_riscv.cpp b/src/hotspot/cpu/riscv/c1_LIRGenerator_riscv.cpp index 88565d9136f..f290708a231 100644 --- a/src/hotspot/cpu/riscv/c1_LIRGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_LIRGenerator_riscv.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, Red Hat Inc. 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. @@ -1073,9 +1073,7 @@ void LIRGenerator::do_CheckCast(CheckCast* x) { } LIR_Opr reg = rlock_result(x); LIR_Opr tmp3 = LIR_OprFact::illegalOpr; - if (!x->klass()->is_loaded() || UseCompressedClassPointers) { - tmp3 = new_register(objectType); - } + tmp3 = new_register(objectType); __ checkcast(reg, obj.result(), x->klass(), new_register(objectType), new_register(objectType), tmp3, x->direct_compare(), info_for_exception, patching_info, stub, @@ -1094,9 +1092,7 @@ void LIRGenerator::do_InstanceOf(InstanceOf* x) { } obj.load_item(); LIR_Opr tmp3 = LIR_OprFact::illegalOpr; - if (!x->klass()->is_loaded() || UseCompressedClassPointers) { - tmp3 = new_register(objectType); - } + tmp3 = new_register(objectType); __ instanceof(reg, obj.result(), x->klass(), new_register(objectType), new_register(objectType), tmp3, x->direct_compare(), patching_info, x->profiled_method(), x->profiled_bci()); diff --git a/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.cpp index aeb077ba0a0..abcc070b253 100644 --- a/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, Red Hat Inc. 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. @@ -92,12 +92,8 @@ void C1_MacroAssembler::initialize_header(Register obj, Register klass, Register // This assumes that all prototype bits fitr in an int32_t mv(tmp1, checked_cast(markWord::prototype().value())); sd(tmp1, Address(obj, oopDesc::mark_offset_in_bytes())); - if (UseCompressedClassPointers) { // Take care not to kill klass - encode_klass_not_null(tmp1, klass, tmp2); - sw(tmp1, Address(obj, oopDesc::klass_offset_in_bytes())); - } else { - sd(klass, Address(obj, oopDesc::klass_offset_in_bytes())); - } + encode_klass_not_null(tmp1, klass, tmp2); + sw(tmp1, Address(obj, oopDesc::klass_offset_in_bytes())); } if (len->is_valid()) { @@ -108,7 +104,7 @@ void C1_MacroAssembler::initialize_header(Register obj, Register klass, Register // Clear gap/first 4 bytes following the length field. sw(zr, Address(obj, base_offset)); } - } else if (UseCompressedClassPointers && !UseCompactObjectHeaders) { + } else if (!UseCompactObjectHeaders) { store_klass_gap(obj, zr); } } diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp index 72a90ddde1f..0d06fd469de 100644 --- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp @@ -1175,8 +1175,7 @@ void C2_MacroAssembler::string_compare_long_same_encoding(Register result, Regis Label TAIL_CHECK, TAIL, NEXT_WORD, DIFFERENCE; const int base_offset = arrayOopDesc::base_offset_in_bytes(T_BYTE); - assert((base_offset % (UseCompactObjectHeaders ? 4 : - (UseCompressedClassPointers ? 8 : 4))) == 0, "Must be"); + assert((base_offset % (UseCompactObjectHeaders ? 4 : 8)) == 0, "Must be"); const int minCharsInWord = isLL ? wordSize : wordSize / 2; @@ -1269,8 +1268,7 @@ void C2_MacroAssembler::string_compare_long_different_encoding(Register result, Label TAIL, NEXT_WORD, DIFFERENCE; const int base_offset = arrayOopDesc::base_offset_in_bytes(T_BYTE); - assert((base_offset % (UseCompactObjectHeaders ? 4 : - (UseCompressedClassPointers ? 8 : 4))) == 0, "Must be"); + assert((base_offset % (UseCompactObjectHeaders ? 4 : 8)) == 0, "Must be"); Register strL = isLU ? str1 : str2; Register strU = isLU ? str2 : str1; @@ -1485,8 +1483,7 @@ void C2_MacroAssembler::arrays_equals(Register a1, Register a2, int length_offset = arrayOopDesc::length_offset_in_bytes(); int base_offset = arrayOopDesc::base_offset_in_bytes(elem_size == 2 ? T_CHAR : T_BYTE); - assert((base_offset % (UseCompactObjectHeaders ? 4 : - (UseCompressedClassPointers ? 8 : 4))) == 0, "Must be"); + assert((base_offset % (UseCompactObjectHeaders ? 4 : 8)) == 0, "Must be"); Register cnt1 = tmp3; Register cnt2 = tmp1; // cnt2 only used in array length compare @@ -1611,8 +1608,7 @@ void C2_MacroAssembler::string_equals(Register a1, Register a2, int base_offset = arrayOopDesc::base_offset_in_bytes(T_BYTE); - assert((base_offset % (UseCompactObjectHeaders ? 4 : - (UseCompressedClassPointers ? 8 : 4))) == 0, "Must be"); + assert((base_offset % (UseCompactObjectHeaders ? 4 : 8)) == 0, "Must be"); BLOCK_COMMENT("string_equals {"); @@ -2699,8 +2695,7 @@ void C2_MacroAssembler::arrays_equals_v(Register a1, Register a2, Register resul int length_offset = arrayOopDesc::length_offset_in_bytes(); int base_offset = arrayOopDesc::base_offset_in_bytes(elem_size == 2 ? T_CHAR : T_BYTE); - assert((base_offset % (UseCompactObjectHeaders ? 4 : - (UseCompressedClassPointers ? 8 : 4))) == 0, "Must be"); + assert((base_offset % (UseCompactObjectHeaders ? 4 : 8)) == 0, "Must be"); BLOCK_COMMENT("arrays_equals_v {"); diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index 4f5e7afc166..b0305fa2977 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved. * Copyright (c) 2020, 2024, Huawei Technologies Co., Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -3514,10 +3514,8 @@ void MacroAssembler::orptr(Address adr, RegisterOrConstant src, Register tmp1, R void MacroAssembler::cmp_klass_compressed(Register oop, Register trial_klass, Register tmp, Label &L, bool equal) { if (UseCompactObjectHeaders) { load_narrow_klass_compact(tmp, oop); - } else if (UseCompressedClassPointers) { - lwu(tmp, Address(oop, oopDesc::klass_offset_in_bytes())); } else { - ld(tmp, Address(oop, oopDesc::klass_offset_in_bytes())); + lwu(tmp, Address(oop, oopDesc::klass_offset_in_bytes())); } if (equal) { beq(trial_klass, tmp, L); @@ -3741,11 +3739,9 @@ void MacroAssembler::load_klass(Register dst, Register src, Register tmp) { if (UseCompactObjectHeaders) { load_narrow_klass_compact(dst, src); decode_klass_not_null(dst, tmp); - } else if (UseCompressedClassPointers) { + } else { lwu(dst, Address(src, oopDesc::klass_offset_in_bytes())); decode_klass_not_null(dst, tmp); - } else { - ld(dst, Address(src, oopDesc::klass_offset_in_bytes())); } } @@ -3753,20 +3749,15 @@ void MacroAssembler::store_klass(Register dst, Register src, Register tmp) { // FIXME: Should this be a store release? concurrent gcs assumes // klass length is valid if klass field is not null. assert(!UseCompactObjectHeaders, "not with compact headers"); - if (UseCompressedClassPointers) { - encode_klass_not_null(src, tmp); - sw(src, Address(dst, oopDesc::klass_offset_in_bytes())); - } else { - sd(src, Address(dst, oopDesc::klass_offset_in_bytes())); - } + encode_klass_not_null(src, tmp); + sw(src, Address(dst, oopDesc::klass_offset_in_bytes())); + } void MacroAssembler::store_klass_gap(Register dst, Register src) { assert(!UseCompactObjectHeaders, "not with compact headers"); - if (UseCompressedClassPointers) { - // Store to klass gap in destination - sw(src, Address(dst, oopDesc::klass_gap_offset_in_bytes())); - } + // Store to klass gap in destination + sw(src, Address(dst, oopDesc::klass_gap_offset_in_bytes())); } void MacroAssembler::decode_klass_not_null(Register r, Register tmp) { @@ -3775,7 +3766,6 @@ void MacroAssembler::decode_klass_not_null(Register r, Register tmp) { } void MacroAssembler::decode_klass_not_null(Register dst, Register src, Register tmp) { - assert(UseCompressedClassPointers, "should only be used for compressed headers"); assert_different_registers(dst, tmp); assert_different_registers(src, tmp); @@ -3806,8 +3796,6 @@ void MacroAssembler::encode_klass_not_null(Register r, Register tmp) { } void MacroAssembler::encode_klass_not_null(Register dst, Register src, Register tmp) { - assert(UseCompressedClassPointers, "should only be used for compressed headers"); - if (CompressedKlassPointers::base() == nullptr) { if (CompressedKlassPointers::shift() != 0) { srli(dst, src, CompressedKlassPointers::shift()); @@ -5337,7 +5325,6 @@ void MacroAssembler::set_narrow_oop(Register dst, jobject obj) { } void MacroAssembler::set_narrow_klass(Register dst, Klass* k) { - assert (UseCompressedClassPointers, "should only be used for compressed headers"); assert (oop_recorder() != nullptr, "this assembler needs an OopRecorder"); int index = oop_recorder()->find_index(k); @@ -5417,12 +5404,9 @@ int MacroAssembler::ic_check(int end_alignment) { if (UseCompactObjectHeaders) { load_narrow_klass_compact(tmp1, receiver); lwu(tmp2, Address(data, CompiledICData::speculated_klass_offset())); - } else if (UseCompressedClassPointers) { + } else { lwu(tmp1, Address(receiver, oopDesc::klass_offset_in_bytes())); lwu(tmp2, Address(data, CompiledICData::speculated_klass_offset())); - } else { - ld(tmp1, Address(receiver, oopDesc::klass_offset_in_bytes())); - ld(tmp2, Address(data, CompiledICData::speculated_klass_offset())); } Label ic_hit; diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad index 54c0d9c0955..e236d03e6d2 100644 --- a/src/hotspot/cpu/riscv/riscv.ad +++ b/src/hotspot/cpu/riscv/riscv.ad @@ -1801,13 +1801,8 @@ void MachUEPNode::format(PhaseRegAlloc* ra_, outputStream* st) const { assert_cond(st != nullptr); st->print_cr("# MachUEPNode"); - if (UseCompressedClassPointers) { - st->print_cr("\tlwu t1, [j_rarg0 + oopDesc::klass_offset_in_bytes()]\t# compressed klass"); - st->print_cr("\tlwu t2, [t0 + CompiledICData::speculated_klass_offset()]\t# compressed klass"); - } else { - st->print_cr("\tld t1, [j_rarg0 + oopDesc::klass_offset_in_bytes()]\t# compressed klass"); - st->print_cr("\tld t2, [t0 + CompiledICData::speculated_klass_offset()]\t# compressed klass"); - } + st->print_cr("\tlwu t1, [j_rarg0 + oopDesc::klass_offset_in_bytes()]\t# compressed klass"); + st->print_cr("\tlwu t2, [t0 + CompiledICData::speculated_klass_offset()]\t# compressed klass"); st->print_cr("\tbeq t1, t2, ic_hit"); st->print_cr("\tj, SharedRuntime::_ic_miss_stub\t # Inline cache check"); st->print_cr("\tic_hit:"); diff --git a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp index 127ac9f6951..964c6d98e9c 100644 --- a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2025, Red Hat Inc. All rights reserved. * Copyright (c) 2020, 2025, Huawei Technologies Co., Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -3070,8 +3070,7 @@ class StubGenerator: public StubCodeGenerator { const Register tmp = x30, tmpLval = x12; int base_offset = arrayOopDesc::base_offset_in_bytes(T_BYTE); - assert((base_offset % (UseCompactObjectHeaders ? 4 : - (UseCompressedClassPointers ? 8 : 4))) == 0, "Must be"); + assert((base_offset % (UseCompactObjectHeaders ? 4 : 8)) == 0, "Must be"); #ifdef ASSERT if (AvoidUnalignedAccesses) { @@ -3128,8 +3127,7 @@ class StubGenerator: public StubCodeGenerator { tmp1 = x28, tmp2 = x29, tmp3 = x30, tmp4 = x12; int base_offset = arrayOopDesc::base_offset_in_bytes(T_BYTE); - assert((base_offset % (UseCompactObjectHeaders ? 4 : - (UseCompressedClassPointers ? 8 : 4))) == 0, "Must be"); + assert((base_offset % (UseCompactObjectHeaders ? 4 : 8)) == 0, "Must be"); Register strU = isLU ? str2 : str1, strL = isLU ? str1 : str2, diff --git a/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp b/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp index 93d6051aa76..e1d8d062c23 100644 --- a/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2016, 2024 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -2251,9 +2251,7 @@ void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) { // but not necessarily exactly of type default_type. NearLabel known_ok, halt; metadata2reg(default_type->constant_encoding(), tmp); - if (UseCompressedClassPointers) { - __ encode_klass_not_null(tmp); - } + __ encode_klass_not_null(tmp); if (basic_type != T_OBJECT) { __ cmp_klass(tmp, dst, Z_R1_scratch); @@ -2540,13 +2538,8 @@ void LIR_Assembler::emit_typecheck_helper(LIR_OpTypeCheck *op, Label* success, L // Get object class. // Not a safepoint as obj null check happens earlier. if (op->fast_check()) { - if (UseCompressedClassPointers) { - __ load_klass(klass_RInfo, obj); - __ compareU64_and_branch(k_RInfo, klass_RInfo, Assembler::bcondNotEqual, *failure_target); - } else { - __ z_cg(k_RInfo, Address(obj, oopDesc::klass_offset_in_bytes())); - __ branch_optimized(Assembler::bcondNotEqual, *failure_target); - } + __ load_klass(klass_RInfo, obj); + __ compareU64_and_branch(k_RInfo, klass_RInfo, Assembler::bcondNotEqual, *failure_target); // Successful cast, fall through to profile or jump. } else { bool need_slow_path = !k->is_loaded() || diff --git a/src/hotspot/cpu/s390/c1_MacroAssembler_s390.cpp b/src/hotspot/cpu/s390/c1_MacroAssembler_s390.cpp index 993c1a1b552..813143938f9 100644 --- a/src/hotspot/cpu/s390/c1_MacroAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/c1_MacroAssembler_s390.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2016, 2024 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -107,10 +107,10 @@ void C1_MacroAssembler::initialize_header(Register obj, Register klass, Register } if (len->is_valid()) { - // Length will be in the klass gap, if one exists. + // Length will be in the klass gap. z_st(len, Address(obj, arrayOopDesc::length_offset_in_bytes())); - } else if (UseCompressedClassPointers && !UseCompactObjectHeaders) { - store_klass_gap(Rzero, obj); // Zero klass gap for compressed oops. + } else if (!UseCompactObjectHeaders) { + store_klass_gap(Rzero, obj); // Zero klass gap. } } diff --git a/src/hotspot/cpu/s390/macroAssembler_s390.cpp b/src/hotspot/cpu/s390/macroAssembler_s390.cpp index 6e132f895bd..de3608e74ba 100644 --- a/src/hotspot/cpu/s390/macroAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/macroAssembler_s390.cpp @@ -1237,7 +1237,6 @@ void MacroAssembler::load_narrow_oop(Register t, narrowOop a) { // Load narrow klass constant, compression required. void MacroAssembler::load_narrow_klass(Register t, Klass* k) { - assert(UseCompressedClassPointers, "must be on to call this method"); narrowKlass encoded_k = CompressedKlassPointers::encode(k); load_const_32to64(t, encoded_k, false /*sign_extend*/); } @@ -1255,7 +1254,6 @@ void MacroAssembler::compare_immediate_narrow_oop(Register oop1, narrowOop oop2) // Compare narrow oop in reg with narrow oop constant, no decompression. void MacroAssembler::compare_immediate_narrow_klass(Register klass1, Klass* klass2) { - assert(UseCompressedClassPointers, "must be on to call this method"); narrowKlass encoded_k = CompressedKlassPointers::encode(klass2); Assembler::z_clfi(klass1, encoded_k); @@ -1348,8 +1346,6 @@ int MacroAssembler::patch_load_narrow_oop(address pos, oop o) { // Patching the immediate value of CPU version dependent load_narrow_klass sequence. // The passed ptr must NOT be in compressed format! int MacroAssembler::patch_load_narrow_klass(address pos, Klass* k) { - assert(UseCompressedClassPointers, "Can only patch compressed klass pointers"); - narrowKlass nk = CompressedKlassPointers::encode(k); return patch_load_const_32to64(pos, nk); } @@ -1364,8 +1360,6 @@ int MacroAssembler::patch_compare_immediate_narrow_oop(address pos, oop o) { // Patching the immediate value of CPU version dependent compare_immediate_narrow_klass sequence. // The passed ptr must NOT be in compressed format! int MacroAssembler::patch_compare_immediate_narrow_klass(address pos, Klass* k) { - assert(UseCompressedClassPointers, "Can only patch compressed klass pointers"); - narrowKlass nk = CompressedKlassPointers::encode(k); return patch_compare_immediate_32(pos, nk); } @@ -2235,10 +2229,8 @@ int MacroAssembler::ic_check(int end_alignment) { if (UseCompactObjectHeaders) { load_narrow_klass_compact(R1_scratch, R2_receiver); - } else if (UseCompressedClassPointers) { - z_llgf(R1_scratch, Address(R2_receiver, oopDesc::klass_offset_in_bytes())); } else { - z_lg(R1_scratch, Address(R2_receiver, oopDesc::klass_offset_in_bytes())); + z_llgf(R1_scratch, Address(R2_receiver, oopDesc::klass_offset_in_bytes())); } z_cg(R1_scratch, Address(R9_data, in_bytes(CompiledICData::speculated_klass_offset()))); z_bre(success); @@ -3916,7 +3908,6 @@ void MacroAssembler::encode_klass_not_null(Register dst, Register src) { address base = CompressedKlassPointers::base(); int shift = CompressedKlassPointers::shift(); bool need_zero_extend = base != nullptr; - assert(UseCompressedClassPointers, "only for compressed klass ptrs"); BLOCK_COMMENT("cKlass encoder {"); @@ -4013,7 +4004,6 @@ int MacroAssembler::instr_size_for_decode_klass_not_null() { address base = CompressedKlassPointers::base(); int shift_size = CompressedKlassPointers::shift() == 0 ? 0 : 6; /* sllg */ int addbase_size = 0; - assert(UseCompressedClassPointers, "only for compressed klass ptrs"); if (base != nullptr) { unsigned int base_h = ((unsigned long)base)>>32; @@ -4043,7 +4033,6 @@ void MacroAssembler::decode_klass_not_null(Register dst) { address base = CompressedKlassPointers::base(); int shift = CompressedKlassPointers::shift(); int beg_off = offset(); - assert(UseCompressedClassPointers, "only for compressed klass ptrs"); BLOCK_COMMENT("cKlass decoder (const size) {"); @@ -4085,7 +4074,6 @@ void MacroAssembler::decode_klass_not_null(Register dst) { void MacroAssembler::decode_klass_not_null(Register dst, Register src) { address base = CompressedKlassPointers::base(); int shift = CompressedKlassPointers::shift(); - assert(UseCompressedClassPointers, "only for compressed klass ptrs"); BLOCK_COMMENT("cKlass decoder {"); @@ -4125,13 +4113,9 @@ void MacroAssembler::decode_klass_not_null(Register dst, Register src) { } void MacroAssembler::load_klass(Register klass, Address mem) { - if (UseCompressedClassPointers) { - z_llgf(klass, mem); - // Attention: no null check here! - decode_klass_not_null(klass); - } else { - z_lg(klass, mem); - } + z_llgf(klass, mem); + // Attention: no null check here! + decode_klass_not_null(klass); } // Loads the obj's Klass* into dst. @@ -4154,10 +4138,8 @@ void MacroAssembler::cmp_klass(Register klass, Register obj, Register tmp) { assert_different_registers(klass, obj, tmp); load_narrow_klass_compact(tmp, obj); z_cr(klass, tmp); - } else if (UseCompressedClassPointers) { - z_c(klass, Address(obj, oopDesc::klass_offset_in_bytes())); } else { - z_cg(klass, Address(obj, oopDesc::klass_offset_in_bytes())); + z_c(klass, Address(obj, oopDesc::klass_offset_in_bytes())); } BLOCK_COMMENT("} cmp_klass"); } @@ -4170,12 +4152,9 @@ void MacroAssembler::cmp_klasses_from_objects(Register obj1, Register obj2, Regi load_narrow_klass_compact(tmp1, obj1); load_narrow_klass_compact(tmp2, obj2); z_cr(tmp1, tmp2); - } else if (UseCompressedClassPointers) { + } else { z_l(tmp1, Address(obj1, oopDesc::klass_offset_in_bytes())); z_c(tmp1, Address(obj2, oopDesc::klass_offset_in_bytes())); - } else { - z_lg(tmp1, Address(obj1, oopDesc::klass_offset_in_bytes())); - z_cg(tmp1, Address(obj2, oopDesc::klass_offset_in_bytes())); } BLOCK_COMMENT("} cmp_klasses_from_objects"); } @@ -4184,36 +4163,28 @@ void MacroAssembler::load_klass(Register klass, Register src_oop) { if (UseCompactObjectHeaders) { load_narrow_klass_compact(klass, src_oop); decode_klass_not_null(klass); - } else if (UseCompressedClassPointers) { + } else { z_llgf(klass, oopDesc::klass_offset_in_bytes(), src_oop); decode_klass_not_null(klass); - } else { - z_lg(klass, oopDesc::klass_offset_in_bytes(), src_oop); } } void MacroAssembler::store_klass(Register klass, Register dst_oop, Register ck) { assert(!UseCompactObjectHeaders, "Don't use with compact headers"); - if (UseCompressedClassPointers) { - assert_different_registers(dst_oop, klass, Z_R0); - if (ck == noreg) ck = klass; - encode_klass_not_null(ck, klass); - z_st(ck, Address(dst_oop, oopDesc::klass_offset_in_bytes())); - } else { - z_stg(klass, Address(dst_oop, oopDesc::klass_offset_in_bytes())); - } + assert_different_registers(dst_oop, klass, Z_R0); + if (ck == noreg) ck = klass; + encode_klass_not_null(ck, klass); + z_st(ck, Address(dst_oop, oopDesc::klass_offset_in_bytes())); } void MacroAssembler::store_klass_gap(Register s, Register d) { assert(!UseCompactObjectHeaders, "Don't use with compact headers"); - if (UseCompressedClassPointers) { - assert(s != d, "not enough registers"); - // Support s = noreg. - if (s != noreg) { - z_st(s, Address(d, oopDesc::klass_gap_offset_in_bytes())); - } else { - z_mvhi(Address(d, oopDesc::klass_gap_offset_in_bytes()), 0); - } + assert(s != d, "not enough registers"); + // Support s = noreg. + if (s != noreg) { + z_st(s, Address(d, oopDesc::klass_gap_offset_in_bytes())); + } else { + z_mvhi(Address(d, oopDesc::klass_gap_offset_in_bytes()), 0); } } @@ -4227,67 +4198,64 @@ void MacroAssembler::compare_klass_ptr(Register Rop1, int64_t disp, Register Rba BLOCK_COMMENT("compare klass ptr {"); - if (UseCompressedClassPointers) { - const int shift = CompressedKlassPointers::shift(); - address base = CompressedKlassPointers::base(); + const int shift = CompressedKlassPointers::shift(); + address base = CompressedKlassPointers::base(); - if (UseCompactObjectHeaders) { - assert(shift >= 3, "cKlass encoder detected bad shift"); - } else { - assert((shift == 0) || (shift == 3), "cKlass encoder detected bad shift"); - } - assert_different_registers(Rop1, Z_R0); - assert_different_registers(Rop1, Rbase, Z_R1); - - // First encode register oop and then compare with cOop in memory. - // This sequence saves an unnecessary cOop load and decode. - if (base == nullptr) { - if (shift == 0) { - z_cl(Rop1, disp, Rbase); // Unscaled - } else { - z_srlg(Z_R0, Rop1, shift); // ZeroBased - z_cl(Z_R0, disp, Rbase); - } - } else { // HeapBased -#ifdef ASSERT - bool used_R0 = true; - bool used_R1 = true; -#endif - Register current = Rop1; - Label done; - - if (maybenull) { // null pointer must be preserved! - z_ltgr(Z_R0, current); - z_bre(done); - current = Z_R0; - } - - unsigned int base_h = ((unsigned long)base)>>32; - unsigned int base_l = (unsigned int)((unsigned long)base); - if ((base_h != 0) && (base_l == 0) && VM_Version::has_HighWordInstr()) { - lgr_if_needed(Z_R0, current); - z_aih(Z_R0, -((int)base_h)); // Base has no set bits in lower half. - } else if ((base_h == 0) && (base_l != 0)) { - lgr_if_needed(Z_R0, current); - z_agfi(Z_R0, -(int)base_l); - } else { - int pow2_offset = get_oop_base_complement(Z_R1, ((uint64_t)(intptr_t)base)); - add2reg_with_index(Z_R0, pow2_offset, Z_R1, Rop1); // Subtract base by adding complement. - } - - if (shift != 0) { - z_srlg(Z_R0, Z_R0, shift); - } - bind(done); - z_cl(Z_R0, disp, Rbase); -#ifdef ASSERT - if (used_R0) preset_reg(Z_R0, 0xb05bUL, 2); - if (used_R1) preset_reg(Z_R1, 0xb06bUL, 2); -#endif - } + if (UseCompactObjectHeaders) { + assert(shift >= 3, "cKlass encoder detected bad shift"); } else { - z_clg(Rop1, disp, Z_R0, Rbase); + assert((shift == 0) || (shift == 3), "cKlass encoder detected bad shift"); } + assert_different_registers(Rop1, Z_R0); + assert_different_registers(Rop1, Rbase, Z_R1); + + // First encode register oop and then compare with cOop in memory. + // This sequence saves an unnecessary cOop load and decode. + if (base == nullptr) { + if (shift == 0) { + z_cl(Rop1, disp, Rbase); // Unscaled + } else { + z_srlg(Z_R0, Rop1, shift); // ZeroBased + z_cl(Z_R0, disp, Rbase); + } + } else { // HeapBased +#ifdef ASSERT + bool used_R0 = true; + bool used_R1 = true; +#endif + Register current = Rop1; + Label done; + + if (maybenull) { // null pointer must be preserved! + z_ltgr(Z_R0, current); + z_bre(done); + current = Z_R0; + } + + unsigned int base_h = ((unsigned long)base)>>32; + unsigned int base_l = (unsigned int)((unsigned long)base); + if ((base_h != 0) && (base_l == 0) && VM_Version::has_HighWordInstr()) { + lgr_if_needed(Z_R0, current); + z_aih(Z_R0, -((int)base_h)); // Base has no set bits in lower half. + } else if ((base_h == 0) && (base_l != 0)) { + lgr_if_needed(Z_R0, current); + z_agfi(Z_R0, -(int)base_l); + } else { + int pow2_offset = get_oop_base_complement(Z_R1, ((uint64_t)(intptr_t)base)); + add2reg_with_index(Z_R0, pow2_offset, Z_R1, Rop1); // Subtract base by adding complement. + } + + if (shift != 0) { + z_srlg(Z_R0, Z_R0, shift); + } + bind(done); + z_cl(Z_R0, disp, Rbase); +#ifdef ASSERT + if (used_R0) preset_reg(Z_R0, 0xb05bUL, 2); + if (used_R1) preset_reg(Z_R1, 0xb06bUL, 2); +#endif + } + BLOCK_COMMENT("} compare klass ptr"); } diff --git a/src/hotspot/cpu/s390/macroAssembler_s390.hpp b/src/hotspot/cpu/s390/macroAssembler_s390.hpp index da24ae80d45..32e484d4790 100644 --- a/src/hotspot/cpu/s390/macroAssembler_s390.hpp +++ b/src/hotspot/cpu/s390/macroAssembler_s390.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2016, 2024 SAP SE. All rights reserved. * Copyright (c) 2024 IBM Corporation. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -842,8 +842,7 @@ class MacroAssembler: public Assembler { void store_klass(Register klass, Register dst_oop, Register ck = noreg); // Klass will get compressed if ck not provided. void store_klass_gap(Register s, Register dst_oop); void load_narrow_klass_compact(Register dst, Register src); - // Compares the Klass pointer of an object to a given Klass (which might be narrow, - // depending on UseCompressedClassPointers). + // Compares the narrow Klass pointer of an object to a given narrow Klass void cmp_klass(Register klass, Register obj, Register tmp); // Compares the Klass pointer of two objects obj1 and obj2. Result is in the condition flags. // Uses tmp1 and tmp2 as temporary registers. diff --git a/src/hotspot/cpu/s390/matcher_s390.hpp b/src/hotspot/cpu/s390/matcher_s390.hpp index 99461e33e3c..b04a6566d41 100644 --- a/src/hotspot/cpu/s390/matcher_s390.hpp +++ b/src/hotspot/cpu/s390/matcher_s390.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2017, 2024 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -82,7 +82,6 @@ static bool narrow_klass_use_complex_address() { NOT_LP64(ShouldNotCallThis()); - assert(UseCompressedClassPointers, "only for compressed klass code"); // TODO HS25: z port if (MatchDecodeNodes) return true; return false; } diff --git a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp index d9be0fdcc8d..5397a230642 100644 --- a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * 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,23 +77,6 @@ const Register SHIFT_count = rcx; // where count for shift operations must be #define __ _masm-> - -static void select_different_registers(Register preserve, - Register extra, - Register &tmp1, - Register &tmp2) { - if (tmp1 == preserve) { - assert_different_registers(tmp1, tmp2, extra); - tmp1 = extra; - } else if (tmp2 == preserve) { - assert_different_registers(tmp1, tmp2, extra); - tmp2 = extra; - } - assert_different_registers(preserve, tmp1, tmp2); -} - - - static void select_different_registers(Register preserve, Register extra, Register &tmp1, @@ -1309,12 +1292,8 @@ void LIR_Assembler::emit_typecheck_helper(LIR_OpTypeCheck *op, Label* success, L } else if (obj == klass_RInfo) { klass_RInfo = dst; } - if (k->is_loaded() && !UseCompressedClassPointers) { - select_different_registers(obj, dst, k_RInfo, klass_RInfo); - } else { - Rtmp1 = op->tmp3()->as_register(); - select_different_registers(obj, dst, k_RInfo, klass_RInfo, Rtmp1); - } + Rtmp1 = op->tmp3()->as_register(); + select_different_registers(obj, dst, k_RInfo, klass_RInfo, Rtmp1); assert_different_registers(obj, k_RInfo, klass_RInfo); @@ -1348,12 +1327,8 @@ void LIR_Assembler::emit_typecheck_helper(LIR_OpTypeCheck *op, Label* success, L if (op->fast_check()) { // get object class // not a safepoint as obj null check happens earlier - if (UseCompressedClassPointers) { - __ load_klass(Rtmp1, obj, tmp_load_klass); - __ cmpptr(k_RInfo, Rtmp1); - } else { - __ cmpptr(k_RInfo, Address(obj, oopDesc::klass_offset_in_bytes())); - } + __ load_klass(Rtmp1, obj, tmp_load_klass); + __ cmpptr(k_RInfo, Rtmp1); __ jcc(Assembler::notEqual, *failure_target); // successful cast, fall through to profile or jump } else { @@ -2651,9 +2626,7 @@ void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) { // but not necessarily exactly of type default_type. Label known_ok, halt; __ mov_metadata(tmp, default_type->constant_encoding()); - if (UseCompressedClassPointers) { - __ encode_klass_not_null(tmp, rscratch1); - } + __ encode_klass_not_null(tmp, rscratch1); if (basic_type != T_OBJECT) { __ cmp_klass(tmp, dst, tmp2); diff --git a/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp b/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp index 5459e8df229..f448e4ee17f 100644 --- a/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp +++ b/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1291,9 +1291,7 @@ void LIRGenerator::do_CheckCast(CheckCast* x) { } LIR_Opr reg = rlock_result(x); LIR_Opr tmp3 = LIR_OprFact::illegalOpr; - if (!x->klass()->is_loaded() || UseCompressedClassPointers) { - tmp3 = new_register(objectType); - } + tmp3 = new_register(objectType); __ checkcast(reg, obj.result(), x->klass(), new_register(objectType), new_register(objectType), tmp3, x->direct_compare(), info_for_exception, patching_info, stub, @@ -1313,9 +1311,7 @@ void LIRGenerator::do_InstanceOf(InstanceOf* x) { } obj.load_item(); LIR_Opr tmp3 = LIR_OprFact::illegalOpr; - if (!x->klass()->is_loaded() || UseCompressedClassPointers) { - tmp3 = new_register(objectType); - } + tmp3 = new_register(objectType); __ instanceof(reg, obj.result(), x->klass(), new_register(objectType), new_register(objectType), tmp3, x->direct_compare(), patching_info, x->profiled_method(), x->profiled_bci()); diff --git a/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp b/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp index 88e2e6c8ba9..7adaea48ff1 100644 --- a/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2026, Oracle and/or its affiliates. All rights reserved. * 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,14 +85,11 @@ void C1_MacroAssembler::initialize_header(Register obj, Register klass, Register if (UseCompactObjectHeaders) { movptr(t1, Address(klass, Klass::prototype_header_offset())); movptr(Address(obj, oopDesc::mark_offset_in_bytes()), t1); - } else if (UseCompressedClassPointers) { // Take care not to kill klass + } else { // Take care not to kill klass movptr(Address(obj, oopDesc::mark_offset_in_bytes()), checked_cast(markWord::prototype().value())); movptr(t1, klass); encode_klass_not_null(t1, rscratch1); movl(Address(obj, oopDesc::klass_offset_in_bytes()), t1); - } else { - movptr(Address(obj, oopDesc::mark_offset_in_bytes()), checked_cast(markWord::prototype().value())); - movptr(Address(obj, oopDesc::klass_offset_in_bytes()), klass); } if (len->is_valid()) { @@ -104,7 +101,7 @@ void C1_MacroAssembler::initialize_header(Register obj, Register klass, Register xorl(t1, t1); movl(Address(obj, base_offset), t1); } - } else if (UseCompressedClassPointers && !UseCompactObjectHeaders) { + } else if (!UseCompactObjectHeaders) { xorptr(t1, t1); store_klass_gap(obj, t1); } diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp index 1d77be26bd9..a0f08145d55 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp @@ -985,12 +985,9 @@ int MacroAssembler::ic_check(int end_alignment) { if (UseCompactObjectHeaders) { load_narrow_klass_compact(temp, receiver); cmpl(temp, Address(data, CompiledICData::speculated_klass_offset())); - } else if (UseCompressedClassPointers) { + } else { movl(temp, Address(receiver, oopDesc::klass_offset_in_bytes())); cmpl(temp, Address(data, CompiledICData::speculated_klass_offset())); - } else { - movptr(temp, Address(receiver, oopDesc::klass_offset_in_bytes())); - cmpptr(temp, Address(data, CompiledICData::speculated_klass_offset())); } // if inline cache check fails, then jump to runtime routine @@ -5384,11 +5381,9 @@ void MacroAssembler::load_klass(Register dst, Register src, Register tmp) { if (UseCompactObjectHeaders) { load_narrow_klass_compact(dst, src); decode_klass_not_null(dst, tmp); - } else if (UseCompressedClassPointers) { + } else { movl(dst, Address(src, oopDesc::klass_offset_in_bytes())); decode_klass_not_null(dst, tmp); - } else { - movptr(dst, Address(src, oopDesc::klass_offset_in_bytes())); } } @@ -5396,12 +5391,8 @@ void MacroAssembler::store_klass(Register dst, Register src, Register tmp) { assert(!UseCompactObjectHeaders, "not with compact headers"); assert_different_registers(src, tmp); assert_different_registers(dst, tmp); - if (UseCompressedClassPointers) { - encode_klass_not_null(src, tmp); - movl(Address(dst, oopDesc::klass_offset_in_bytes()), src); - } else { - movptr(Address(dst, oopDesc::klass_offset_in_bytes()), src); - } + encode_klass_not_null(src, tmp); + movl(Address(dst, oopDesc::klass_offset_in_bytes()), src); } void MacroAssembler::cmp_klass(Register klass, Register obj, Register tmp) { @@ -5410,10 +5401,8 @@ void MacroAssembler::cmp_klass(Register klass, Register obj, Register tmp) { assert_different_registers(klass, obj, tmp); load_narrow_klass_compact(tmp, obj); cmpl(klass, tmp); - } else if (UseCompressedClassPointers) { - cmpl(klass, Address(obj, oopDesc::klass_offset_in_bytes())); } else { - cmpptr(klass, Address(obj, oopDesc::klass_offset_in_bytes())); + cmpl(klass, Address(obj, oopDesc::klass_offset_in_bytes())); } } @@ -5424,12 +5413,9 @@ void MacroAssembler::cmp_klasses_from_objects(Register obj1, Register obj2, Regi load_narrow_klass_compact(tmp1, obj1); load_narrow_klass_compact(tmp2, obj2); cmpl(tmp1, tmp2); - } else if (UseCompressedClassPointers) { + } else { movl(tmp1, Address(obj1, oopDesc::klass_offset_in_bytes())); cmpl(tmp1, Address(obj2, oopDesc::klass_offset_in_bytes())); - } else { - movptr(tmp1, Address(obj1, oopDesc::klass_offset_in_bytes())); - cmpptr(tmp1, Address(obj2, oopDesc::klass_offset_in_bytes())); } } @@ -5478,10 +5464,8 @@ void MacroAssembler::store_heap_oop_null(Address dst) { void MacroAssembler::store_klass_gap(Register dst, Register src) { assert(!UseCompactObjectHeaders, "Don't use with compact headers"); - if (UseCompressedClassPointers) { - // Store to klass gap in destination - movl(Address(dst, oopDesc::klass_gap_offset_in_bytes()), src); - } + // Store to klass gap in destination + movl(Address(dst, oopDesc::klass_gap_offset_in_bytes()), src); } #ifdef ASSERT @@ -5671,7 +5655,6 @@ void MacroAssembler::decode_klass_not_null(Register r, Register tmp) { BLOCK_COMMENT("decode_klass_not_null {"); assert_different_registers(r, tmp); // Note: it will change flags - assert(UseCompressedClassPointers, "should only be used for compressed headers"); // Cannot assert, unverified entry point counts instructions (see .ad file) // vtableStubs also counts instructions in pd_code_size_limit. // Also do not verify_oop as this is called by verify_oop. @@ -5693,7 +5676,6 @@ void MacroAssembler::decode_and_move_klass_not_null(Register dst, Register src) BLOCK_COMMENT("decode_and_move_klass_not_null {"); assert_different_registers(src, dst); // Note: it will change flags - assert (UseCompressedClassPointers, "should only be used for compressed headers"); // Cannot assert, unverified entry point counts instructions (see .ad file) // vtableStubs also counts instructions in pd_code_size_limit. // Also do not verify_oop as this is called by verify_oop. @@ -5750,7 +5732,6 @@ void MacroAssembler::set_narrow_oop(Address dst, jobject obj) { } void MacroAssembler::set_narrow_klass(Register dst, Klass* k) { - assert (UseCompressedClassPointers, "should only be used for compressed headers"); assert (oop_recorder() != nullptr, "this assembler needs an OopRecorder"); int klass_index = oop_recorder()->find_index(k); RelocationHolder rspec = metadata_Relocation::spec(klass_index); @@ -5758,7 +5739,6 @@ void MacroAssembler::set_narrow_klass(Register dst, Klass* k) { } void MacroAssembler::set_narrow_klass(Address dst, Klass* k) { - assert (UseCompressedClassPointers, "should only be used for compressed headers"); assert (oop_recorder() != nullptr, "this assembler needs an OopRecorder"); int klass_index = oop_recorder()->find_index(k); RelocationHolder rspec = metadata_Relocation::spec(klass_index); @@ -5784,7 +5764,6 @@ void MacroAssembler::cmp_narrow_oop(Address dst, jobject obj) { } void MacroAssembler::cmp_narrow_klass(Register dst, Klass* k) { - assert (UseCompressedClassPointers, "should only be used for compressed headers"); assert (oop_recorder() != nullptr, "this assembler needs an OopRecorder"); int klass_index = oop_recorder()->find_index(k); RelocationHolder rspec = metadata_Relocation::spec(klass_index); @@ -5792,7 +5771,6 @@ void MacroAssembler::cmp_narrow_klass(Register dst, Klass* k) { } void MacroAssembler::cmp_narrow_klass(Address dst, Klass* k) { - assert (UseCompressedClassPointers, "should only be used for compressed headers"); assert (oop_recorder() != nullptr, "this assembler needs an OopRecorder"); int klass_index = oop_recorder()->find_index(k); RelocationHolder rspec = metadata_Relocation::spec(klass_index); diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.hpp b/src/hotspot/cpu/x86/macroAssembler_x86.hpp index 8469deaa8be..3bdd1e4477a 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.hpp @@ -351,8 +351,7 @@ class MacroAssembler: public Assembler { void load_klass(Register dst, Register src, Register tmp); void store_klass(Register dst, Register src, Register tmp); - // Compares the Klass pointer of an object to a given Klass (which might be narrow, - // depending on UseCompressedClassPointers). + // Compares the narrow Klass pointer of an object to a given narrow Klass. void cmp_klass(Register klass, Register obj, Register tmp); // Compares the Klass pointer of two objects obj1 and obj2. Result is in the condition flags. diff --git a/src/hotspot/cpu/x86/matcher_x86.hpp b/src/hotspot/cpu/x86/matcher_x86.hpp index f7973a8564e..62a5d2827bc 100644 --- a/src/hotspot/cpu/x86/matcher_x86.hpp +++ b/src/hotspot/cpu/x86/matcher_x86.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * 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,7 +75,6 @@ } static bool narrow_klass_use_complex_address() { - assert(UseCompressedClassPointers, "only for compressed klass code"); return (CompressedKlassPointers::shift() <= 3); } diff --git a/src/hotspot/cpu/x86/x86.ad b/src/hotspot/cpu/x86/x86.ad index 2fd4e5516fc..f31d64f3d7e 100644 --- a/src/hotspot/cpu/x86/x86.ad +++ b/src/hotspot/cpu/x86/x86.ad @@ -2605,13 +2605,8 @@ uint BoxLockNode::size(PhaseRegAlloc *ra_) const #ifndef PRODUCT void MachUEPNode::format(PhaseRegAlloc* ra_, outputStream* st) const { - if (UseCompressedClassPointers) { - st->print_cr("movl rscratch1, [j_rarg0 + oopDesc::klass_offset_in_bytes()]\t# compressed klass"); - st->print_cr("\tcmpl rscratch1, [rax + CompiledICData::speculated_klass_offset()]\t # Inline cache check"); - } else { - st->print_cr("movq rscratch1, [j_rarg0 + oopDesc::klass_offset_in_bytes()]\t# compressed klass"); - st->print_cr("\tcmpq rscratch1, [rax + CompiledICData::speculated_klass_offset()]\t # Inline cache check"); - } + st->print_cr("movl rscratch1, [j_rarg0 + oopDesc::klass_offset_in_bytes()]\t# compressed klass"); + st->print_cr("\tcmpl rscratch1, [rax + CompiledICData::speculated_klass_offset()]\t # Inline cache check"); st->print_cr("\tjne SharedRuntime::_ic_miss_stub"); } #endif diff --git a/src/hotspot/share/cds/aotMapLogger.cpp b/src/hotspot/share/cds/aotMapLogger.cpp index 98336ff9b1f..9f338826fd6 100644 --- a/src/hotspot/share/cds/aotMapLogger.cpp +++ b/src/hotspot/share/cds/aotMapLogger.cpp @@ -589,7 +589,6 @@ public: } Klass* real_klass() { - assert(UseCompressedClassPointers, "heap archiving requires UseCompressedClassPointers"); return _data._klass; } diff --git a/src/hotspot/share/cds/aotMappedHeapLoader.hpp b/src/hotspot/share/cds/aotMappedHeapLoader.hpp index 7c5ca1b1f9e..10f5ce3124f 100644 --- a/src/hotspot/share/cds/aotMappedHeapLoader.hpp +++ b/src/hotspot/share/cds/aotMappedHeapLoader.hpp @@ -54,7 +54,7 @@ public: // Can this VM map archived heap region? Currently only G1+compressed{oops,cp} static bool can_map() { - CDS_JAVA_HEAP_ONLY(return (UseG1GC && UseCompressedClassPointers);) + CDS_JAVA_HEAP_ONLY(return UseG1GC;) NOT_CDS_JAVA_HEAP(return false;) } diff --git a/src/hotspot/share/cds/aotMappedHeapWriter.cpp b/src/hotspot/share/cds/aotMappedHeapWriter.cpp index 3456c845938..8f810ef5244 100644 --- a/src/hotspot/share/cds/aotMappedHeapWriter.cpp +++ b/src/hotspot/share/cds/aotMappedHeapWriter.cpp @@ -450,7 +450,6 @@ int AOTMappedHeapWriter::filler_array_length(size_t fill_bytes) { } HeapWord* AOTMappedHeapWriter::init_filler_array_at_buffer_top(int array_length, size_t fill_bytes) { - assert(UseCompressedClassPointers, "Archived heap only supported for compressed klasses"); Klass* oak = Universe::objectArrayKlass(); // already relocated to point to archived klass HeapWord* mem = offset_to_buffered_address(_buffer_used); memset(mem, 0, fill_bytes); @@ -724,7 +723,6 @@ template void AOTMappedHeapWriter::mark_oop_pointer(T* buffered_add } void AOTMappedHeapWriter::update_header_for_requested_obj(oop requested_obj, oop src_obj, Klass* src_klass) { - assert(UseCompressedClassPointers, "Archived heap only supported for compressed klasses"); narrowKlass nk = ArchiveBuilder::current()->get_requested_narrow_klass(src_klass); address buffered_addr = requested_addr_to_buffered_addr(cast_from_oop
(requested_obj)); diff --git a/src/hotspot/share/cds/aotMetaspace.cpp b/src/hotspot/share/cds/aotMetaspace.cpp index 76c37194882..55e9f93b3ab 100644 --- a/src/hotspot/share/cds/aotMetaspace.cpp +++ b/src/hotspot/share/cds/aotMetaspace.cpp @@ -250,9 +250,9 @@ static bool shared_base_too_high(char* specified_base, char* aligned_base, size_ static char* compute_shared_base(size_t cds_max) { char* specified_base = (char*)SharedBaseAddress; size_t alignment = AOTMetaspace::core_region_alignment(); - if (UseCompressedClassPointers && CompressedKlassPointers::needs_class_space()) { - alignment = MAX2(alignment, Metaspace::reserve_alignment()); - } +#if INCLUDE_CLASS_SPACE + alignment = MAX2(alignment, Metaspace::reserve_alignment()); +#endif if (SharedBaseAddress == 0) { // Special meaning of -XX:SharedBaseAddress=0 -> Always map archive at os-selected address. @@ -1637,32 +1637,29 @@ MapArchiveResult AOTMetaspace::map_archives(FileMapInfo* static_mapinfo, FileMap aot_log_debug(aot)("Failed to reserve spaces (use_requested_addr=%u)", (unsigned)use_requested_addr); } else { - if (Metaspace::using_class_space()) { - prot_zone_size = protection_zone_size(); - } + CLASS_SPACE_ONLY(prot_zone_size = protection_zone_size();) -#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, - "A class space should have been reserved"); - assert(class_space_rs.base() >= archive_space_rs.end(), - "class space should follow the cds archive space"); - assert(is_aligned(archive_space_rs.base(), - core_region_alignment()), - "Archive space misaligned"); - assert(is_aligned(class_space_rs.base(), - Metaspace::reserve_alignment()), - "class space misaligned"); - } -#endif // ASSERT + +#if INCLUDE_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, + "A class space should have been reserved"); + assert(class_space_rs.base() >= archive_space_rs.end(), + "class space should follow the cds archive space"); + assert(is_aligned(archive_space_rs.base(), + core_region_alignment()), + "Archive space misaligned"); + assert(is_aligned(class_space_rs.base(), + Metaspace::reserve_alignment()), + "class space misaligned"); +#endif // INCLUDE_CLASS_SPACE aot_log_info(aot)("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(), @@ -1764,62 +1761,60 @@ MapArchiveResult AOTMetaspace::map_archives(FileMapInfo* static_mapinfo, FileMap if (result == MAP_ARCHIVE_SUCCESS) { SharedBaseAddress = (size_t)mapped_base_address; -#ifdef _LP64 - if (Metaspace::using_class_space()) { - assert(prot_zone_size > 0 && - *(mapped_base_address) == 'P' && - *(mapped_base_address + prot_zone_size - 1) == 'P', - "Protection zone was overwritten?"); - // Set up ccs in metaspace. - Metaspace::initialize_class_space(class_space_rs); +#if INCLUDE_CLASS_SPACE + assert(prot_zone_size > 0 && + *(mapped_base_address) == 'P' && + *(mapped_base_address + prot_zone_size - 1) == 'P', + "Protection zone was overwritten?"); + // 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 klass_range_start = (address)mapped_base_address; - 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, - klass_range_start, ArchiveBuilder::precomputed_narrow_klass_shift() // precomputed encoding, see ArchiveBuilder - ); - assert(CompressedKlassPointers::base() == klass_range_start, "must be"); - } else { - // Let JVM freely choose encoding base and shift - CompressedKlassPointers::initialize(klass_range_start, klass_range_size); - assert(CompressedKlassPointers::base() == nullptr || - CompressedKlassPointers::base() == klass_range_start, "must be"); - } - // Establish protection zone, but only if we need one - if (CompressedKlassPointers::base() == klass_range_start) { - CompressedKlassPointers::establish_protection_zone(klass_range_start, prot_zone_size); - } + // Set up compressed Klass pointer encoding: the encoding range must + // cover both archive and class space. + const address klass_range_start = (address)mapped_base_address; + 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, + klass_range_start, ArchiveBuilder::precomputed_narrow_klass_shift() // precomputed encoding, see ArchiveBuilder + ); + assert(CompressedKlassPointers::base() == klass_range_start, "must be"); + } else { + // Let JVM freely choose encoding base and shift + CompressedKlassPointers::initialize(klass_range_start, klass_range_size); + assert(CompressedKlassPointers::base() == nullptr || + CompressedKlassPointers::base() == klass_range_start, "must be"); + } + // Establish protection zone, but only if we need one + if (CompressedKlassPointers::base() == klass_range_start) { + CompressedKlassPointers::establish_protection_zone(klass_range_start, prot_zone_size); + } - if (static_mapinfo->can_use_heap_region()) { - if (static_mapinfo->object_streaming_mode()) { - HeapShared::initialize_loading_mode(HeapArchiveMode::_streaming); - } else { - // 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(); - HeapShared::initialize_loading_mode(HeapArchiveMode::_mapping); - } + if (static_mapinfo->can_use_heap_region()) { + if (static_mapinfo->object_streaming_mode()) { + HeapShared::initialize_loading_mode(HeapArchiveMode::_streaming); } else { - FileMapRegion* r = static_mapinfo->region_at(AOTMetaspace::hp); - if (r->used() > 0) { - AOTMetaspace::report_loading_error("Cannot use CDS heap data."); - } - if (!CDSConfig::is_dumping_static_archive()) { - CDSConfig::stop_using_full_module_graph("No CDS heap data"); - } + // 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(); + HeapShared::initialize_loading_mode(HeapArchiveMode::_mapping); + } + } else { + FileMapRegion* r = static_mapinfo->region_at(AOTMetaspace::hp); + if (r->used() > 0) { + AOTMetaspace::report_loading_error("Cannot use CDS heap data."); + } + if (!CDSConfig::is_dumping_static_archive()) { + CDSConfig::stop_using_full_module_graph("No CDS heap data"); } } -#endif // _LP64 +#endif // INCLUDE_CLASS_SPACE log_info(aot)("initial optimized module handling: %s", CDSConfig::is_using_optimized_module_handling() ? "enabled" : "disabled"); log_info(aot)("initial full module graph: %s", CDSConfig::is_using_full_module_graph() ? "enabled" : "disabled"); } else { @@ -1852,8 +1847,13 @@ MapArchiveResult AOTMetaspace::map_archives(FileMapInfo* static_mapinfo, FileMap // (The gap may result from different alignment requirements between metaspace // and CDS) // -// If UseCompressedClassPointers is disabled, only one address space will be -// reserved: +// The range encompassing both spaces will be suitable to en/decode narrow Klass +// pointers: the base will be valid for encoding the range [Base, End) and not +// surpass the max. range for that encoding. +// +// On 32-bit, a "narrow" Klass is just the pointer itself, and the Klass encoding +// range encompasses the whole address range. Consequently, we can "decode" and +// "encode" any pointer anywhere, and so are free to place the CDS archive anywhere: // // +-- Base address End // | | @@ -1867,27 +1867,21 @@ MapArchiveResult AOTMetaspace::map_archives(FileMapInfo* static_mapinfo, FileMap // use_archive_base_addr address is false, this base address is determined // by the platform. // -// If UseCompressedClassPointers=1, the range encompassing both spaces will be -// suitable to en/decode narrow Klass pointers: the base will be valid for -// encoding, the range [Base, End) and not surpass the max. range for that encoding. -// // Return: // // - On success: // - total_space_rs will be reserved as whole for archive_space_rs and -// class_space_rs if UseCompressedClassPointers is true. +// class_space_rs on 64-bit. // On Windows, try reserve archive_space_rs and class_space_rs // separately first if use_archive_base_addr is true. // - archive_space_rs will be reserved and large enough to host static and // if needed dynamic archive: [Base, A). // archive_space_rs.base and size will be aligned to CDS reserve // granularity. -// - class_space_rs: If UseCompressedClassPointers=1, class_space_rs will -// be reserved. Its start address will be aligned to metaspace reserve -// alignment, which may differ from CDS alignment. It will follow the cds -// archive space, close enough such that narrow class pointer encoding -// covers both spaces. -// If UseCompressedClassPointers=0, class_space_rs remains unreserved. +// - class_space_rs: On 64-bit, class_space_rs will be reserved. Its start +// address will be aligned to metaspace reserve alignment, which may differ +// from CDS alignment. It will follow the cds archive space, close enough +// such that narrow class pointer encoding covers both spaces. // - On error: null is returned and the spaces remain unreserved. char* AOTMetaspace::reserve_address_space_for_archives(FileMapInfo* static_mapinfo, FileMapInfo* dynamic_mapinfo, @@ -1903,32 +1897,34 @@ char* AOTMetaspace::reserve_address_space_for_archives(FileMapInfo* static_mapin 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); - if (!Metaspace::using_class_space()) { - // Get the simple case out of the way first: - // no compressed class space, simple allocation. +#if !INCLUDE_CLASS_SPACE - // When running without class space, requested archive base should be aligned to cds core alignment. - assert(is_aligned(base_address, archive_space_alignment), - "Archive base address unaligned: " PTR_FORMAT ", needs alignment: %zu.", - p2i(base_address), archive_space_alignment); + // Get the simple case out of the way first: + // no compressed class space, simple allocation. - archive_space_rs = MemoryReserver::reserve((char*)base_address, - archive_space_size, - archive_space_alignment, - os::vm_page_size(), - mtNone); - if (archive_space_rs.is_reserved()) { - assert(base_address == nullptr || - (address)archive_space_rs.base() == base_address, "Sanity"); - // Register archive space with NMT. - MemTracker::record_virtual_memory_tag(archive_space_rs, mtClassShared); - return archive_space_rs.base(); - } - return nullptr; + // When running without class space, requested archive base should be aligned to cds core alignment. + assert(is_aligned(base_address, archive_space_alignment), + "Archive base address unaligned: " PTR_FORMAT ", needs alignment: %zu.", + p2i(base_address), archive_space_alignment); + + archive_space_rs = MemoryReserver::reserve((char*)base_address, + archive_space_size, + archive_space_alignment, + os::vm_page_size(), + mtNone); + if (archive_space_rs.is_reserved()) { + assert(base_address == nullptr || + (address)archive_space_rs.base() == base_address, "Sanity"); + // Register archive space with NMT. + MemTracker::record_virtual_memory_tag(archive_space_rs, mtClassShared); + return archive_space_rs.base(); } -#ifdef _LP64 + return nullptr; +#else + + // INCLUDE_CLASS_SPACE=1 // Complex case: two spaces adjacent to each other, both to be addressable // with narrow class pointers. // We reserve the whole range spanning both spaces, then split that range up. @@ -2040,11 +2036,7 @@ char* AOTMetaspace::reserve_address_space_for_archives(FileMapInfo* static_mapin return archive_space_rs.base(); -#else - ShouldNotReachHere(); - return nullptr; -#endif - +#endif // INCLUDE_CLASS_SPACE } void AOTMetaspace::release_reserved_spaces(ReservedSpace& total_space_rs, diff --git a/src/hotspot/share/cds/aotStreamedHeapWriter.cpp b/src/hotspot/share/cds/aotStreamedHeapWriter.cpp index ad363f21fdb..25bef10a673 100644 --- a/src/hotspot/share/cds/aotStreamedHeapWriter.cpp +++ b/src/hotspot/share/cds/aotStreamedHeapWriter.cpp @@ -369,7 +369,6 @@ template void AOTStreamedHeapWriter::map_oop_field_in_buffer(oop ob } void AOTStreamedHeapWriter::update_header_for_buffered_addr(address buffered_addr, oop src_obj, Klass* src_klass) { - assert(UseCompressedClassPointers, "Archived heap only supported for compressed klasses"); narrowKlass nk = ArchiveBuilder::current()->get_requested_narrow_klass(src_klass); markWord mw = markWord::prototype(); diff --git a/src/hotspot/share/cds/archiveBuilder.cpp b/src/hotspot/share/cds/archiveBuilder.cpp index b2d6600e44f..21eef3d7b0b 100644 --- a/src/hotspot/share/cds/archiveBuilder.cpp +++ b/src/hotspot/share/cds/archiveBuilder.cpp @@ -1092,20 +1092,17 @@ class RelocateBufferToRequested : public BitMapClosure { } }; -#ifdef _LP64 int ArchiveBuilder::precomputed_narrow_klass_shift() { - // Legacy Mode: - // We use 32 bits for narrowKlass, which should cover the full 4G Klass range. Shift can be 0. + // Standard Mode: + // We use 32 bits for narrowKlass, which should cover a full 4G Klass range. Shift can be 0. // CompactObjectHeader Mode: // narrowKlass is much smaller, and we use the highest possible shift value to later get the maximum // Klass encoding range. // // Note that all of this may change in the future, if we decide to correct the pre-calculated // narrow Klass IDs at archive load time. - assert(UseCompressedClassPointers, "Only needed for compressed class pointers"); return UseCompactObjectHeaders ? CompressedKlassPointers::max_shift() : 0; } -#endif // _LP64 void ArchiveBuilder::relocate_to_requested() { if (!ro_region()->is_packed()) { diff --git a/src/hotspot/share/cds/archiveBuilder.hpp b/src/hotspot/share/cds/archiveBuilder.hpp index b3667ea11b4..6a9df87092b 100644 --- a/src/hotspot/share/cds/archiveBuilder.hpp +++ b/src/hotspot/share/cds/archiveBuilder.hpp @@ -484,7 +484,6 @@ public: void print_stats(); void report_out_of_space(const char* name, size_t needed_bytes); -#ifdef _LP64 // The CDS archive contains pre-computed narrow Klass IDs. It carries them in the headers of // archived heap objects. With +UseCompactObjectHeaders, it also carries them in prototypes // in Klass. @@ -504,7 +503,6 @@ public: // TinyClassPointer Mode: // We use the highest possible shift value to maximize the encoding range size. static int precomputed_narrow_klass_shift(); -#endif // _LP64 }; diff --git a/src/hotspot/share/cds/archiveUtils.cpp b/src/hotspot/share/cds/archiveUtils.cpp index f79b1e134e8..6e0608e196b 100644 --- a/src/hotspot/share/cds/archiveUtils.cpp +++ b/src/hotspot/share/cds/archiveUtils.cpp @@ -360,8 +360,8 @@ char* DumpRegion::allocate_metaspace_obj(size_t num_bytes, address src, Metaspac bool is_instance_class = is_class && ((Klass*)src)->is_instance_klass(); #ifdef _LP64 - // More strict alignments needed for UseCompressedClassPointers - if (is_class && UseCompressedClassPointers) { + // More strict alignments needed for Klass objects + if (is_class) { size_t klass_alignment = checked_cast(nth_bit(ArchiveBuilder::precomputed_narrow_klass_shift())); alignment = MAX2(alignment, klass_alignment); precond(is_aligned(alignment, SharedSpaceObjectAlignment)); diff --git a/src/hotspot/share/cds/cdsConfig.cpp b/src/hotspot/share/cds/cdsConfig.cpp index 9d191bf0121..ecf3c6d2231 100644 --- a/src/hotspot/share/cds/cdsConfig.cpp +++ b/src/hotspot/share/cds/cdsConfig.cpp @@ -891,10 +891,6 @@ const char* CDSConfig::type_of_archive_being_written() { // 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 - if (!UseCompressedClassPointers) { - return "UseCompressedClassPointers must be true"; - } - return nullptr; #else return "JVM not configured for writing Java heap objects"; diff --git a/src/hotspot/share/cds/filemap.cpp b/src/hotspot/share/cds/filemap.cpp index a07f13cefca..38502b2b2d8 100644 --- a/src/hotspot/share/cds/filemap.cpp +++ b/src/hotspot/share/cds/filemap.cpp @@ -225,15 +225,9 @@ void FileMapHeader::populate(FileMapInfo *info, size_t core_region_alignment, } #endif _compressed_oops = UseCompressedOops; - _compressed_class_ptrs = UseCompressedClassPointers; - if (UseCompressedClassPointers) { -#ifdef _LP64 - _narrow_klass_pointer_bits = CompressedKlassPointers::narrow_klass_pointer_bits(); - _narrow_klass_shift = ArchiveBuilder::precomputed_narrow_klass_shift(); -#endif - } else { - _narrow_klass_pointer_bits = _narrow_klass_shift = -1; - } + _narrow_klass_pointer_bits = CompressedKlassPointers::narrow_klass_pointer_bits(); + _narrow_klass_shift = ArchiveBuilder::precomputed_narrow_klass_shift(); + // Which JIT compier is used _compiler_type = (u1)CompilerConfig::compiler_type(); _type_profile_level = TypeProfileLevel; @@ -295,7 +289,6 @@ void FileMapHeader::print(outputStream* st) { st->print_cr("- max_heap_size: %zu", _max_heap_size); st->print_cr("- narrow_oop_mode: %d", _narrow_oop_mode); st->print_cr("- compressed_oops: %d", _compressed_oops); - st->print_cr("- compressed_class_ptrs: %d", _compressed_class_ptrs); st->print_cr("- narrow_klass_pointer_bits: %d", _narrow_klass_pointer_bits); st->print_cr("- narrow_klass_shift: %d", _narrow_klass_shift); st->print_cr("- cloned_vtables: %u", cast_to_u4(_cloned_vtables)); @@ -1926,11 +1919,12 @@ bool FileMapHeader::validate() { _has_platform_or_app_classes = false; } - aot_log_info(aot)("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) { - aot_log_warning(aot)("Unable to use %s.\nThe saved state of UseCompressedOops and UseCompressedClassPointers is " - "different from runtime, CDS will be disabled.", file_type); + aot_log_info(aot)("The %s was created with UseCompressedOops = %d, UseCompactObjectHeaders = %d", + file_type, compressed_oops(), compact_headers()); + if (compressed_oops() != UseCompressedOops) { + aot_log_warning(aot)("Unable to use %s.\nThe saved state of UseCompressedOops (%d) is " + "different from runtime (%d), CDS will be disabled.", file_type, + compressed_oops(), UseCompressedOops); return false; } diff --git a/src/hotspot/share/cds/filemap.hpp b/src/hotspot/share/cds/filemap.hpp index 56b88df378a..bae08bd5bc7 100644 --- a/src/hotspot/share/cds/filemap.hpp +++ b/src/hotspot/share/cds/filemap.hpp @@ -120,7 +120,6 @@ private: CompressedOops::Mode _narrow_oop_mode; // compressed oop encoding mode bool _object_streaming_mode; // dump was created for object streaming bool _compressed_oops; // save the flag UseCompressedOops - bool _compressed_class_ptrs; // save the flag UseCompressedClassPointers int _narrow_klass_pointer_bits; // save number of bits in narrowKlass int _narrow_klass_shift; // save shift width used to pre-compute narrowKlass IDs in archived heap objects narrowPtr _cloned_vtables; // The address of the first cloned vtable @@ -200,7 +199,6 @@ public: bool has_platform_or_app_classes() const { return _has_platform_or_app_classes; } 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; } int narrow_klass_pointer_bits() const { return _narrow_klass_pointer_bits; } int narrow_klass_shift() const { return _narrow_klass_shift; } bool has_full_module_graph() const { return _has_full_module_graph; } diff --git a/src/hotspot/share/classfile/systemDictionaryShared.cpp b/src/hotspot/share/classfile/systemDictionaryShared.cpp index 5947050e31a..58d432a628c 100644 --- a/src/hotspot/share/classfile/systemDictionaryShared.cpp +++ b/src/hotspot/share/classfile/systemDictionaryShared.cpp @@ -89,11 +89,9 @@ DEBUG_ONLY(bool SystemDictionaryShared::_class_loading_may_happen = true;) #ifdef ASSERT static void check_klass_after_loading(const Klass* k) { -#ifdef _LP64 - if (k != nullptr && UseCompressedClassPointers) { + if (k != nullptr) { CompressedKlassPointers::check_encodable(k); } -#endif } #endif diff --git a/src/hotspot/share/code/aotCodeCache.cpp b/src/hotspot/share/code/aotCodeCache.cpp index b29cf906736..4ad5e12d808 100644 --- a/src/hotspot/share/code/aotCodeCache.cpp +++ b/src/hotspot/share/code/aotCodeCache.cpp @@ -388,9 +388,6 @@ void AOTCodeCache::Config::record(uint cpu_features_offset) { if (UseCompressedOops) { _flags |= compressedOops; } - if (UseCompressedClassPointers) { - _flags |= compressedClassPointers; - } if (UseTLAB) { _flags |= useTLAB; } @@ -474,10 +471,6 @@ bool AOTCodeCache::Config::verify(AOTCodeCache* cache) const { return false; } - if (((_flags & compressedClassPointers) != 0) != UseCompressedClassPointers) { - log_debug(aot, codecache, init)("AOT Code Cache disabled: it was created with UseCompressedClassPointers = %s", UseCompressedClassPointers ? "false" : "true"); - return false; - } if (_compressedKlassShift != (uint)CompressedKlassPointers::shift()) { log_debug(aot, codecache, init)("AOT Code Cache disabled: it was created with CompressedKlassPointers::shift() = %d vs current %d", _compressedKlassShift, CompressedKlassPointers::shift()); return false; diff --git a/src/hotspot/share/code/aotCodeCache.hpp b/src/hotspot/share/code/aotCodeCache.hpp index bd8721fea8c..7996388faa6 100644 --- a/src/hotspot/share/code/aotCodeCache.hpp +++ b/src/hotspot/share/code/aotCodeCache.hpp @@ -177,12 +177,11 @@ protected: none = 0, debugVM = 1, compressedOops = 2, - compressedClassPointers = 4, - useTLAB = 8, - systemClassAssertions = 16, - userClassAssertions = 32, - enableContendedPadding = 64, - restrictContendedPadding = 128 + useTLAB = 4, + systemClassAssertions = 8, + userClassAssertions = 16, + enableContendedPadding = 32, + restrictContendedPadding = 64 }; uint _flags; uint _cpu_features_offset; // offset in the cache where cpu features are stored diff --git a/src/hotspot/share/code/compiledIC.cpp b/src/hotspot/share/code/compiledIC.cpp index 5f5c9711441..07d96d6cd44 100644 --- a/src/hotspot/share/code/compiledIC.cpp +++ b/src/hotspot/share/code/compiledIC.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -76,11 +76,7 @@ CompiledICData::CompiledICData() // Inline cache callsite info is initialized once the first time it is resolved void CompiledICData::initialize(CallInfo* call_info, Klass* receiver_klass) { _speculated_method = call_info->selected_method(); - if (UseCompressedClassPointers) { - _speculated_klass = (uintptr_t)CompressedKlassPointers::encode_not_null(receiver_klass); - } else { - _speculated_klass = (uintptr_t)receiver_klass; - } + _speculated_klass = (uintptr_t)CompressedKlassPointers::encode_not_null(receiver_klass); if (call_info->call_kind() == CallInfo::itable_call) { assert(call_info->resolved_method() != nullptr, "virtual or interface method must be found"); _itable_defc_klass = call_info->resolved_method()->method_holder(); @@ -133,12 +129,7 @@ Klass* CompiledICData::speculated_klass() const { if (is_speculated_klass_unloaded()) { return nullptr; } - - if (UseCompressedClassPointers) { - return CompressedKlassPointers::decode_not_null((narrowKlass)_speculated_klass); - } else { - return (Klass*)_speculated_klass; - } + return CompressedKlassPointers::decode_not_null((narrowKlass)_speculated_klass); } //----------------------------------------------------------------------------- diff --git a/src/hotspot/share/gc/shared/c2/barrierSetC2.cpp b/src/hotspot/share/gc/shared/c2/barrierSetC2.cpp index a888ea81707..afe7d2acfa7 100644 --- a/src/hotspot/share/gc/shared/c2/barrierSetC2.cpp +++ b/src/hotspot/share/gc/shared/c2/barrierSetC2.cpp @@ -708,7 +708,6 @@ int BarrierSetC2::arraycopy_payload_base_offset(bool is_array) { // 12 - 64-bit VM, compressed klass // 16 - 64-bit VM, normal klass if (base_off % BytesPerLong != 0) { - assert(UseCompressedClassPointers, ""); assert(!UseCompactObjectHeaders, ""); if (is_array) { // Exclude length to copy by 8 bytes words. diff --git a/src/hotspot/share/gc/shared/gcTrace.cpp b/src/hotspot/share/gc/shared/gcTrace.cpp index bad9c707b1e..5d0627e779e 100644 --- a/src/hotspot/share/gc/shared/gcTrace.cpp +++ b/src/hotspot/share/gc/shared/gcTrace.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -122,11 +122,10 @@ void GCTracer::report_gc_heap_summary(GCWhen::Type when, const GCHeapSummary& he void GCTracer::report_metaspace_summary(GCWhen::Type when, const MetaspaceSummary& summary) const { send_meta_space_summary_event(when, summary); - send_metaspace_chunk_free_list_summary(when, Metaspace::NonClassType, summary.metaspace_chunk_free_list_summary()); - if (UseCompressedClassPointers) { - send_metaspace_chunk_free_list_summary(when, Metaspace::ClassType, summary.class_chunk_free_list_summary()); - } +#if INCLUDE_CLASS_SPACE + send_metaspace_chunk_free_list_summary(when, Metaspace::ClassType, summary.class_chunk_free_list_summary()); +#endif } void YoungGCTracer::report_gc_end_impl(const Ticks& timestamp, TimePartitions* time_partitions) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahAsserts.cpp b/src/hotspot/share/gc/shenandoah/shenandoahAsserts.cpp index baeaffb9c7b..268f5b13035 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahAsserts.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahAsserts.cpp @@ -559,26 +559,24 @@ bool ShenandoahAsserts::extract_klass_safely(oop obj, narrowKlass& nk, const Kla if (!os::is_readable_pointer(obj)) { return false; } - if (UseCompressedClassPointers) { - if (UseCompactObjectHeaders) { // look in forwardee - markWord mark = obj->mark(); - if (mark.is_marked()) { - oop fwd = cast_to_oop(mark.clear_lock_bits().to_pointer()); - if (!os::is_readable_pointer(fwd)) { - return false; - } - mark = fwd->mark(); + + if (UseCompactObjectHeaders) { // look in forwardee + markWord mark = obj->mark(); + if (mark.is_marked()) { + oop fwd = cast_to_oop(mark.clear_lock_bits().to_pointer()); + if (!os::is_readable_pointer(fwd)) { + return false; } - nk = mark.narrow_klass(); - } else { - nk = obj->narrow_klass(); + mark = fwd->mark(); } - if (!CompressedKlassPointers::is_valid_narrow_klass_id(nk)) { - return false; - } - k = CompressedKlassPointers::decode_not_null_without_asserts(nk); + nk = mark.narrow_klass(); } else { - k = obj->klass(); + nk = obj->narrow_klass(); } + if (!CompressedKlassPointers::is_valid_narrow_klass_id(nk)) { + return false; + } + k = CompressedKlassPointers::decode_not_null_without_asserts(nk); + return k != nullptr; } diff --git a/src/hotspot/share/gc/z/c2/zBarrierSetC2.cpp b/src/hotspot/share/gc/z/c2/zBarrierSetC2.cpp index 650918e2d30..0a3dac1e100 100644 --- a/src/hotspot/share/gc/z/c2/zBarrierSetC2.cpp +++ b/src/hotspot/share/gc/z/c2/zBarrierSetC2.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -442,7 +442,7 @@ void ZBarrierSetC2::clone_at_expansion(PhaseMacroExpand* phase, ArrayCopyNode* a assert(src_offset == dest_offset, "should be equal"); const jlong offset = src_offset->get_long(); if (offset != arrayOopDesc::base_offset_in_bytes(T_OBJECT)) { - assert(!UseCompressedClassPointers || UseCompactObjectHeaders, "should only happen without compressed class pointers"); + assert(UseCompactObjectHeaders, "should only happen with COH"); assert((arrayOopDesc::base_offset_in_bytes(T_OBJECT) - offset) == BytesPerLong, "unexpected offset"); length = phase->transform_later(new SubLNode(length, phase->longcon(1))); // Size is in longs src_offset = phase->longcon(arrayOopDesc::base_offset_in_bytes(T_OBJECT)); diff --git a/src/hotspot/share/gc/z/zDebug.gdb b/src/hotspot/share/gc/z/zDebug.gdb index d502eea7ce3..df087c4a42d 100644 --- a/src/hotspot/share/gc/z/zDebug.gdb +++ b/src/hotspot/share/gc/z/zDebug.gdb @@ -50,11 +50,7 @@ define zpo end printf "\t Page: %llu\n", ((uintptr_t)$obj & ZAddressOffsetMask) >> ZGranuleSizeShift x/16gx $obj - if (UseCompressedClassPointers) - set $klass = (Klass*)(void*)((uintptr_t)CompressedKlassPointers::_base +((uintptr_t)$obj->_metadata->_compressed_klass << CompressedKlassPointers::_shift)) - else - set $klass = $obj->_metadata->_klass - end + set $klass = (Klass*)(void*)((uintptr_t)CompressedKlassPointers::_base +((uintptr_t)$obj->_compressed_klass << CompressedKlassPointers::_shift)) printf "Mark: 0x%016llx\tKlass: %s\n", (uintptr_t)$obj->_mark, (char*)$klass->_name->_body end diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdKlassQueue.cpp b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdKlassQueue.cpp index 9c57374d6c6..eab7de20545 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdKlassQueue.cpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdKlassQueue.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * 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,7 +75,7 @@ static size_t element_size(bool compressed) { } static bool can_compress_element(traceid id) { - return Metaspace::using_class_space() && id < uncompressed_threshold; + return INCLUDE_CLASS_SPACE == 1 && id < uncompressed_threshold; } static size_t element_size(const Klass* klass) { diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp index 6214f6a2746..6048c19d911 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp @@ -206,13 +206,8 @@ void CompilerToVM::Data::initialize(JVMCI_TRAPS) { Universe_narrow_oop_base = nullptr; Universe_narrow_oop_shift = 0; } - if (UseCompressedClassPointers) { - Universe_narrow_klass_base = CompressedKlassPointers::base(); - Universe_narrow_klass_shift = CompressedKlassPointers::shift(); - } else { - Universe_narrow_klass_base = nullptr; - Universe_narrow_klass_shift = 0; - } + Universe_narrow_klass_base = CompressedKlassPointers::base(); + Universe_narrow_klass_shift = CompressedKlassPointers::shift(); Universe_non_oop_bits = Universe::non_oop_word(); Universe_verify_oop_mask = Universe::verify_oop_mask(); Universe_verify_oop_bits = Universe::verify_oop_bits(); @@ -390,7 +385,6 @@ JVMCIObjectArray CompilerToVM::initialize_intrinsics(JVMCI_TRAPS) { X86_ONLY(do_int_flag(UseAVX)) \ do_bool_flag(UseCRC32Intrinsics) \ do_bool_flag(UseAdler32Intrinsics) \ - do_bool_flag(UseCompressedClassPointers) \ do_bool_flag(UseCompressedOops) \ X86_ONLY(do_bool_flag(UseCountLeadingZerosInstruction)) \ X86_ONLY(do_bool_flag(UseCountTrailingZerosInstruction)) \ diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index ac532e1bb4c..1fdf98588fd 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -342,7 +342,7 @@ volatile_nonstatic_field(ObjectMonitor, _succ, int64_t) \ \ volatile_nonstatic_field(oopDesc, _mark, markWord) \ - volatile_nonstatic_field(oopDesc, _metadata._klass, Klass*) \ + volatile_nonstatic_field(oopDesc, _compressed_klass, narrowKlass) \ \ static_field(StubRoutines, _verify_oop_count, jint) \ \ diff --git a/src/hotspot/share/memory/classLoaderMetaspace.cpp b/src/hotspot/share/memory/classLoaderMetaspace.cpp index c1ff172071d..af3b8b1b77f 100644 --- a/src/hotspot/share/memory/classLoaderMetaspace.cpp +++ b/src/hotspot/share/memory/classLoaderMetaspace.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2020 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -162,10 +162,12 @@ void ClassLoaderMetaspace::deallocate(MetaWord* ptr, size_t word_size) { MetaBlock bl(ptr, word_size); // Add to class arena only if block is usable for encodable Klass storage. MetaspaceArena* receiving_arena = non_class_space_arena(); - if (Metaspace::using_class_space() && Metaspace::is_in_class_space(ptr) && +#if INCLUDE_CLASS_SPACE + if (Metaspace::is_in_class_space(ptr) && is_aligned(ptr, class_space_arena()->allocation_alignment_bytes())) { receiving_arena = class_space_arena(); } +#endif receiving_arena->deallocate(bl); DEBUG_ONLY(InternalStats::inc_num_deallocs();) } diff --git a/src/hotspot/share/memory/classLoaderMetaspace.hpp b/src/hotspot/share/memory/classLoaderMetaspace.hpp index aa43e171708..dc782611e98 100644 --- a/src/hotspot/share/memory/classLoaderMetaspace.hpp +++ b/src/hotspot/share/memory/classLoaderMetaspace.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2026, Oracle and/or its affiliates. All rights reserved. * 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,9 +40,10 @@ namespace metaspace { // A ClassLoaderMetaspace manages MetaspaceArena(s) for a CLD. // -// A CLD owns one MetaspaceArena if UseCompressedClassPointers is false. Otherwise -// it owns two - one for the Klass* objects from the class space, one for the other -// types of MetaspaceObjs from the non-class space. +// 64-bit: +// +// A CLD owns two MetaspaceArenas - one for the Klass* objects from the class space, +// one for the other types of MetaspaceObjs from the non-class space. // // +------+ +----------------------+ +-------------------+ // | CLD | ---> | ClassLoaderMetaspace | ----> | (non class) Arena | @@ -58,6 +59,11 @@ namespace metaspace { // ^ // alloc top // +// 32-bit: +// +// A CLD owns just one MetaspaceArena. In that arena all metadata - Klass and other - +// are placed. + class ClassLoaderMetaspace : public CHeapObj { friend class metaspace::ClmsTester; // for gtests @@ -67,11 +73,10 @@ class ClassLoaderMetaspace : public CHeapObj { const Metaspace::MetaspaceType _space_type; // Arena for allocations from non-class metaspace - // (resp. for all allocations if -XX:-UseCompressedClassPointers). metaspace::MetaspaceArena* _non_class_space_arena; // Arena for allocations from class space - // (null if -XX:-UseCompressedClassPointers). + // (null for 32-bit). metaspace::MetaspaceArena* _class_space_arena; Mutex* lock() const { return _lock; } diff --git a/src/hotspot/share/memory/metaspace.cpp b/src/hotspot/share/memory/metaspace.cpp index e686b324004..da6ebc991c8 100644 --- a/src/hotspot/share/memory/metaspace.cpp +++ b/src/hotspot/share/memory/metaspace.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2026, 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -166,33 +166,33 @@ void MetaspaceUtils::print_metaspace_change(const MetaspaceCombinedStats& pre_me // it is a constant (to uninformed users, often confusingly large). For non-class space, it would // be interesting since free chunks can be uncommitted, but for now it is left out. - if (Metaspace::using_class_space()) { - log_info(gc, metaspace)(HEAP_CHANGE_FORMAT" " - HEAP_CHANGE_FORMAT" " - HEAP_CHANGE_FORMAT, - HEAP_CHANGE_FORMAT_ARGS("Metaspace", - pre_meta_values.used(), - pre_meta_values.committed(), - meta_values.used(), - meta_values.committed()), - HEAP_CHANGE_FORMAT_ARGS("NonClass", - pre_meta_values.non_class_used(), - pre_meta_values.non_class_committed(), - meta_values.non_class_used(), - meta_values.non_class_committed()), - HEAP_CHANGE_FORMAT_ARGS("Class", - pre_meta_values.class_used(), - pre_meta_values.class_committed(), - meta_values.class_used(), - meta_values.class_committed())); - } else { - log_info(gc, metaspace)(HEAP_CHANGE_FORMAT, - HEAP_CHANGE_FORMAT_ARGS("Metaspace", - pre_meta_values.used(), - pre_meta_values.committed(), - meta_values.used(), - meta_values.committed())); - } +#if INCLUDE_CLASS_SPACE + log_info(gc, metaspace)(HEAP_CHANGE_FORMAT" " + HEAP_CHANGE_FORMAT" " + HEAP_CHANGE_FORMAT, + HEAP_CHANGE_FORMAT_ARGS("Metaspace", + pre_meta_values.used(), + pre_meta_values.committed(), + meta_values.used(), + meta_values.committed()), + HEAP_CHANGE_FORMAT_ARGS("NonClass", + pre_meta_values.non_class_used(), + pre_meta_values.non_class_committed(), + meta_values.non_class_used(), + meta_values.non_class_committed()), + HEAP_CHANGE_FORMAT_ARGS("Class", + pre_meta_values.class_used(), + pre_meta_values.class_committed(), + meta_values.class_used(), + meta_values.class_committed())); +#else + log_info(gc, metaspace)(HEAP_CHANGE_FORMAT, + HEAP_CHANGE_FORMAT_ARGS("Metaspace", + pre_meta_values.used(), + pre_meta_values.committed(), + meta_values.used(), + meta_values.committed())); +#endif // INCLUDE_CLASS_SPACE } // This will print out a basic metaspace usage report but @@ -226,41 +226,36 @@ void MetaspaceUtils::print_on(outputStream* out) { stats.committed()/K, stats.reserved()/K); - if (Metaspace::using_class_space()) { - StreamIndentor si(out, 1); - out->print("class space "); - out->fill_to(17); - out->print_cr("used %zuK, " - "committed %zuK, " - "reserved %zuK", - stats.class_space_stats().used()/K, - stats.class_space_stats().committed()/K, - stats.class_space_stats().reserved()/K); - } +#if INCLUDE_CLASS_SPACE + StreamIndentor si(out, 1); + out->print("class space "); + out->fill_to(17); + out->print_cr("used %zuK, " + "committed %zuK, " + "reserved %zuK", + stats.class_space_stats().used()/K, + stats.class_space_stats().committed()/K, + stats.class_space_stats().reserved()/K); +#endif // INCLUDE_CLASS_SPACE } #ifdef ASSERT void MetaspaceUtils::verify() { if (Metaspace::initialized()) { - // Verify non-class chunkmanager... ChunkManager* cm = ChunkManager::chunkmanager_nonclass(); cm->verify(); - // ... and space list. VirtualSpaceList* vsl = VirtualSpaceList::vslist_nonclass(); vsl->verify(); - if (Metaspace::using_class_space()) { - // If we use compressed class pointers, verify class chunkmanager... - cm = ChunkManager::chunkmanager_class(); - cm->verify(); - - // ... and class spacelist. - vsl = VirtualSpaceList::vslist_class(); - vsl->verify(); - } +#if INCLUDE_CLASS_SPACE + cm = ChunkManager::chunkmanager_class(); + cm->verify(); + vsl = VirtualSpaceList::vslist_class(); + vsl->verify(); +#endif // INCLUDE_CLASS_SPACE } } #endif @@ -387,7 +382,8 @@ void MetaspaceGC::post_initialize() { bool MetaspaceGC::can_expand(size_t word_size, bool is_class) { // Check if the compressed class space is full. - if (is_class && Metaspace::using_class_space()) { +#if INCLUDE_CLASS_SPACE + if (is_class) { size_t class_committed = MetaspaceUtils::committed_bytes(Metaspace::ClassType); if (class_committed + word_size * BytesPerWord > CompressedClassSpaceSize) { log_trace(gc, metaspace, freelist)("Cannot expand %s metaspace by %zu words (CompressedClassSpaceSize = %zu words)", @@ -395,6 +391,7 @@ bool MetaspaceGC::can_expand(size_t word_size, bool is_class) { return false; } } +#endif // INCLUDE_CLASS_SPACE // Check if the user has imposed a limit on the metaspace memory. size_t committed_bytes = MetaspaceUtils::committed_bytes(); @@ -548,7 +545,7 @@ const void* Metaspace::_class_space_end = nullptr; bool Metaspace::initialized() { return metaspace::MetaspaceContext::context_nonclass() != nullptr - LP64_ONLY(&& (using_class_space() ? Metaspace::class_space_is_initialized() : true)); + CLASS_SPACE_ONLY(&& Metaspace::class_space_is_initialized()); } #ifdef _LP64 @@ -566,9 +563,9 @@ void Metaspace::print_compressed_class_space(outputStream* st) { // Given a prereserved space, use that to set up the compressed class space list. void Metaspace::initialize_class_space(ReservedSpace rs) { + STATIC_ASSERT(INCLUDE_CLASS_SPACE == 1); assert(rs.size() >= CompressedClassSpaceSize, "%zu != %zu", rs.size(), CompressedClassSpaceSize); - assert(using_class_space(), "Must be using class space"); assert(rs.size() == CompressedClassSpaceSize, "%zu != %zu", rs.size(), CompressedClassSpaceSize); @@ -658,49 +655,51 @@ void Metaspace::ergo_initialize() { MaxMetaspaceSize = MAX2(MaxMetaspaceSize, commit_alignment()); - if (UseCompressedClassPointers) { - // Let Class Space not be larger than 80% of MaxMetaspaceSize. Note that is - // grossly over-dimensioned for most usage scenarios; typical ratio of - // class space : non class space usage is about 1:6. With many small classes, - // it can get as low as 1:2. It is not a big deal though since ccs is only - // reserved and will be committed on demand only. - const size_t max_ccs_size = 8 * (MaxMetaspaceSize / 10); +#if INCLUDE_CLASS_SPACE - // Sanity check. - const size_t max_klass_range = CompressedKlassPointers::max_klass_range_size(); - assert(max_klass_range >= reserve_alignment(), - "Klass range (%zu) must cover at least a full root chunk (%zu)", - max_klass_range, reserve_alignment()); + // Let Class Space not be larger than 80% of MaxMetaspaceSize. Note that is + // grossly over-dimensioned for most usage scenarios; typical ratio of + // class space : non class space usage is about 1:6. With many small classes, + // it can get as low as 1:2. It is not a big deal though since ccs is only + // reserved and will be committed on demand only. + const size_t max_ccs_size = 8 * (MaxMetaspaceSize / 10); - size_t adjusted_ccs_size = MIN3(CompressedClassSpaceSize, max_ccs_size, max_klass_range); + // Sanity check. + const size_t max_klass_range = CompressedKlassPointers::max_klass_range_size(); + assert(max_klass_range >= reserve_alignment(), + "Klass range (%zu) must cover at least a full root chunk (%zu)", + max_klass_range, reserve_alignment()); - // CCS must be aligned to root chunk size, and be at least the size of one - // root chunk. - adjusted_ccs_size = align_up(adjusted_ccs_size, reserve_alignment()); - adjusted_ccs_size = MAX2(adjusted_ccs_size, reserve_alignment()); + size_t adjusted_ccs_size = MIN3(CompressedClassSpaceSize, max_ccs_size, max_klass_range); - // Print a warning if the adjusted size differs from the users input - if (CompressedClassSpaceSize != adjusted_ccs_size) { - #define X "CompressedClassSpaceSize adjusted from user input " \ - "%zu bytes to %zu bytes", CompressedClassSpaceSize, adjusted_ccs_size - if (FLAG_IS_CMDLINE(CompressedClassSpaceSize)) { - log_warning(metaspace)(X); - } else { - log_info(metaspace)(X); - } - #undef X - } - - // Note: re-adjusting may have us left with a CompressedClassSpaceSize - // larger than MaxMetaspaceSize for very small values of MaxMetaspaceSize. - // Lets just live with that, its not a big deal. - if (adjusted_ccs_size != CompressedClassSpaceSize) { - FLAG_SET_ERGO(CompressedClassSpaceSize, adjusted_ccs_size); - log_info(metaspace)("Setting CompressedClassSpaceSize to %zu.", - CompressedClassSpaceSize); + // CCS must be aligned to root chunk size, and be at least the size of one + // root chunk. + adjusted_ccs_size = align_up(adjusted_ccs_size, reserve_alignment()); + adjusted_ccs_size = MAX2(adjusted_ccs_size, reserve_alignment()); + + // Print a warning if the adjusted size differs from the users input + if (CompressedClassSpaceSize != adjusted_ccs_size) { + #define X "CompressedClassSpaceSize adjusted from user input " \ + "%zu bytes to %zu bytes", CompressedClassSpaceSize, adjusted_ccs_size + if (FLAG_IS_CMDLINE(CompressedClassSpaceSize)) { + log_warning(metaspace)(X); + } else { + log_info(metaspace)(X); } + #undef X } + // Note: re-adjusting may have us left with a CompressedClassSpaceSize + // larger than MaxMetaspaceSize for very small values of MaxMetaspaceSize. + // Lets just live with that, its not a big deal. + if (adjusted_ccs_size != CompressedClassSpaceSize) { + FLAG_SET_ERGO(CompressedClassSpaceSize, adjusted_ccs_size); + log_info(metaspace)("Setting CompressedClassSpaceSize to %zu.", + CompressedClassSpaceSize); + } + +#endif // INCLUDE_CLASS_SPACE + // Set MetaspaceSize, MinMetaspaceExpansion and MaxMetaspaceExpansion if (MetaspaceSize > MaxMetaspaceSize) { MetaspaceSize = MaxMetaspaceSize; @@ -724,15 +723,12 @@ void Metaspace::global_initialize() { AOTMetaspace::initialize_for_static_dump(); } - // If UseCompressedClassPointers=1, we have two cases: + // We have two cases: // a) if CDS is active (runtime, Xshare=on), it will create the class space - // for us, initialize it and set up CompressedKlassPointers encoding. - // Class space will be reserved above the mapped archives. + // for us. It then will set up encoding to cover both CDS archive space and class space. // b) if CDS either deactivated (Xshare=off) or a static dump is to be done (Xshare:dump), - // we will create the class space on our own. It will be placed above the java heap, - // since we assume it has been placed in low - // address regions. We may rethink this (see JDK-8244943). Failing that, - // it will be placed anywhere. + // we will create the class space on our own and set up encoding to only cover the + // class space. #if INCLUDE_CDS // case (a) @@ -746,9 +742,9 @@ void Metaspace::global_initialize() { } #endif // INCLUDE_CDS -#ifdef _LP64 +#if INCLUDE_CLASS_SPACE - if (using_class_space() && !class_space_is_initialized()) { + if (!class_space_is_initialized()) { assert(!CDSConfig::is_using_archive(), "CDS archive is not mapped at this point"); // case (b) (No CDS) @@ -835,28 +831,23 @@ void Metaspace::global_initialize() { } #else - // +UseCompressedClassPointers on 32-bit: does not need class space. Klass can live wherever. - if (UseCompressedClassPointers) { - const address start = (address)os::vm_min_address(); // but not in the zero page - const address end = (address)CompressedKlassPointers::max_klass_range_size(); - CompressedKlassPointers::initialize(start, end - start); - } -#endif // __LP64 + // 32-bit: + const address start = (address)os::vm_min_address(); // but not in the zero page + const address end = (address)CompressedKlassPointers::max_klass_range_size(); + CompressedKlassPointers::initialize(start, end - start); +#endif // INCLUDE_CLASS_SPACE // Initialize non-class virtual space list, and its chunk manager: MetaspaceContext::initialize_nonclass_space_context(); _tracer = new MetaspaceTracer(); - if (UseCompressedClassPointers) { - // Note: "cds" would be a better fit but keep this for backward compatibility. - LogTarget(Info, gc, metaspace) lt; - if (lt.is_enabled()) { - LogStream ls(lt); - CDS_ONLY(AOTMetaspace::print_on(&ls);) - Metaspace::print_compressed_class_space(&ls); - CompressedKlassPointers::print_mode(&ls); - } + LogTarget(Info, gc, metaspace) lt; + if (lt.is_enabled()) { + LogStream ls(lt); + CDS_ONLY(AOTMetaspace::print_on(&ls);) + Metaspace::print_compressed_class_space(&ls); + CompressedKlassPointers::print_mode(&ls); } } @@ -888,15 +879,13 @@ MetaWord* Metaspace::allocate(ClassLoaderData* loader_data, size_t word_size, MetaWord* result = loader_data->metaspace_non_null()->allocate(word_size, mdtype); if (result != nullptr) { -#ifdef ASSERT - if (using_class_space() && mdtype == ClassType) { + if (INCLUDE_CLASS_SPACE == 1 && mdtype == ClassType) { assert(is_in_class_space(result) && is_aligned(result, CompressedKlassPointers::klass_alignment_in_bytes()), "Sanity"); } else { assert((is_in_class_space(result) || is_in_nonclass_metaspace(result)) && is_aligned(result, Metaspace::min_allocation_alignment_bytes), "Sanity"); } -#endif // Zero initialize. Copy::fill_to_words((HeapWord*)result, word_size, 0); log_trace(metaspace)("Metaspace::allocate: type %d return " PTR_FORMAT ".", (int)type, p2i(result)); @@ -1017,12 +1006,12 @@ void Metaspace::purge(bool classes_unloaded) { if (cm != nullptr) { cm->purge(); } - if (using_class_space()) { - cm = ChunkManager::chunkmanager_class(); - if (cm != nullptr) { - cm->purge(); - } +#if INCLUDE_CLASS_SPACE + cm = ChunkManager::chunkmanager_class(); + if (cm != nullptr) { + cm->purge(); } +#endif // INCLUDE_CLASS_SPACE } // Try to satisfy queued metaspace allocation requests. diff --git a/src/hotspot/share/memory/metaspace.hpp b/src/hotspot/share/memory/metaspace.hpp index 01ef4b4dd49..96f5a2459ce 100644 --- a/src/hotspot/share/memory/metaspace.hpp +++ b/src/hotspot/share/memory/metaspace.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2017, 2021 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -164,18 +164,12 @@ public: static void print_compressed_class_space(outputStream* st) NOT_LP64({}); - // Return TRUE only if UseCompressedClassPointers is True. - static bool using_class_space() { - return NOT_LP64(false) LP64_ONLY(UseCompressedClassPointers); - } - static bool is_class_space_allocation(MetadataType mdType) { - return mdType == ClassType && using_class_space(); + return CLASS_SPACE_ONLY(mdType == ClassType) NOT_CLASS_SPACE(false); } static bool initialized(); }; - #endif // SHARE_MEMORY_METASPACE_HPP diff --git a/src/hotspot/share/memory/metaspace/metaspaceReporter.cpp b/src/hotspot/share/memory/metaspace/metaspaceReporter.cpp index 3cff2a50d03..f6683f50fd1 100644 --- a/src/hotspot/share/memory/metaspace/metaspaceReporter.cpp +++ b/src/hotspot/share/memory/metaspace/metaspaceReporter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2018, 2020 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -59,39 +59,39 @@ static void print_vs(outputStream* out, size_t scale) { const size_t committed_nc = RunningCounters::committed_words_nonclass(); const int num_nodes_nc = VirtualSpaceList::vslist_nonclass()->num_nodes(); - if (Metaspace::using_class_space()) { - const size_t reserved_c = RunningCounters::reserved_words_class(); - const size_t committed_c = RunningCounters::committed_words_class(); - const int num_nodes_c = VirtualSpaceList::vslist_class()->num_nodes(); +#if INCLUDE_CLASS_SPACE + const size_t reserved_c = RunningCounters::reserved_words_class(); + const size_t committed_c = RunningCounters::committed_words_class(); + const int num_nodes_c = VirtualSpaceList::vslist_class()->num_nodes(); - out->print(" Non-class space: "); - print_scaled_words(out, reserved_nc, scale, 7); - out->print(" reserved, "); - print_scaled_words_and_percentage(out, committed_nc, reserved_nc, scale, 7); - out->print(" committed, "); - out->print(" %d nodes.", num_nodes_nc); - out->cr(); - out->print(" Class space: "); - print_scaled_words(out, reserved_c, scale, 7); - out->print(" reserved, "); - print_scaled_words_and_percentage(out, committed_c, reserved_c, scale, 7); - out->print(" committed, "); - out->print(" %d nodes.", num_nodes_c); - out->cr(); - out->print(" Both: "); - print_scaled_words(out, reserved_c + reserved_nc, scale, 7); - out->print(" reserved, "); - print_scaled_words_and_percentage(out, committed_c + committed_nc, reserved_c + reserved_nc, scale, 7); - out->print(" committed. "); - out->cr(); - } else { - print_scaled_words(out, reserved_nc, scale, 7); - out->print(" reserved, "); - print_scaled_words_and_percentage(out, committed_nc, reserved_nc, scale, 7); - out->print(" committed, "); - out->print(" %d nodes.", num_nodes_nc); - out->cr(); - } + out->print(" Non-class space: "); + print_scaled_words(out, reserved_nc, scale, 7); + out->print(" reserved, "); + print_scaled_words_and_percentage(out, committed_nc, reserved_nc, scale, 7); + out->print(" committed, "); + out->print(" %d nodes.", num_nodes_nc); + out->cr(); + out->print(" Class space: "); + print_scaled_words(out, reserved_c, scale, 7); + out->print(" reserved, "); + print_scaled_words_and_percentage(out, committed_c, reserved_c, scale, 7); + out->print(" committed, "); + out->print(" %d nodes.", num_nodes_c); + out->cr(); + out->print(" Both: "); + print_scaled_words(out, reserved_c + reserved_nc, scale, 7); + out->print(" reserved, "); + print_scaled_words_and_percentage(out, committed_c + committed_nc, reserved_c + reserved_nc, scale, 7); + out->print(" committed. "); + out->cr(); +#else + print_scaled_words(out, reserved_nc, scale, 7); + out->print(" reserved, "); + print_scaled_words_and_percentage(out, committed_nc, reserved_nc, scale, 7); + out->print(" committed, "); + out->print(" %d nodes.", num_nodes_nc); + out->cr(); +#endif // INCLUDE_CLASS_SPACE } static void print_settings(outputStream* out, size_t scale) { @@ -102,12 +102,12 @@ static void print_settings(outputStream* out, size_t scale) { print_human_readable_size(out, MaxMetaspaceSize, scale); } out->cr(); - if (Metaspace::using_class_space()) { - out->print("CompressedClassSpaceSize: "); - print_human_readable_size(out, CompressedClassSpaceSize, scale); - } else { - out->print("No class space"); - } +#if INCLUDE_CLASS_SPACE + out->print("CompressedClassSpaceSize: "); + print_human_readable_size(out, CompressedClassSpaceSize, scale); +#else + out->print("No class space"); +#endif // INCLUDE_CLASS_SPACE out->cr(); out->print("Initial GC threshold: "); print_human_readable_size(out, MetaspaceSize, scale); @@ -117,9 +117,7 @@ static void print_settings(outputStream* out, size_t scale) { out->cr(); out->print_cr("CDS: %s", (CDSConfig::is_using_archive() ? "on" : (CDSConfig::is_dumping_static_archive() ? "dump" : "off"))); Settings::print_on(out); -#ifdef _LP64 CompressedKlassPointers::print_mode(out); -#endif } // This will print out a basic metaspace usage report but @@ -131,9 +129,7 @@ void MetaspaceReporter::print_basic_report(outputStream* out, size_t scale) { } out->cr(); out->print_cr("Usage:"); - if (Metaspace::using_class_space()) { - out->print(" Non-class: "); - } + CLASS_SPACE_ONLY(out->print(" Non-class: ");) // Note: since we want to purely rely on counters, without any locking or walking the CLDG, // for Usage stats (statistics over in-use chunks) all we can print is the @@ -144,37 +140,35 @@ void MetaspaceReporter::print_basic_report(outputStream* out, size_t scale) { print_scaled_words(out, used_nc, scale, 5); out->print(" used."); out->cr(); - if (Metaspace::using_class_space()) { - const size_t used_c = MetaspaceUtils::used_words(Metaspace::ClassType); - out->print(" Class: "); - print_scaled_words(out, used_c, scale, 5); - out->print(" used."); - out->cr(); - out->print(" Both: "); - const size_t used = used_nc + used_c; - print_scaled_words(out, used, scale, 5); - out->print(" used."); - out->cr(); - } +#if INCLUDE_CLASS_SPACE + const size_t used_c = MetaspaceUtils::used_words(Metaspace::ClassType); + out->print(" Class: "); + print_scaled_words(out, used_c, scale, 5); + out->print(" used."); + out->cr(); + out->print(" Both: "); + const size_t used = used_nc + used_c; + print_scaled_words(out, used, scale, 5); + out->print(" used."); + out->cr(); +#endif // INCLUDE_CLASS_SPACE out->cr(); out->print_cr("Virtual space:"); print_vs(out, scale); out->cr(); out->print_cr("Chunk freelists:"); - if (Metaspace::using_class_space()) { - out->print(" Non-Class: "); - } + CLASS_SPACE_ONLY(out->print(" Non-Class: ");) print_scaled_words(out, ChunkManager::chunkmanager_nonclass()->total_word_size(), scale); out->cr(); - if (Metaspace::using_class_space()) { - out->print(" Class: "); - print_scaled_words(out, ChunkManager::chunkmanager_class()->total_word_size(), scale); - out->cr(); - out->print(" Both: "); - print_scaled_words(out, ChunkManager::chunkmanager_nonclass()->total_word_size() + - ChunkManager::chunkmanager_class()->total_word_size(), scale); - out->cr(); - } +#if INCLUDE_CLASS_SPACE + out->print(" Class: "); + print_scaled_words(out, ChunkManager::chunkmanager_class()->total_word_size(), scale); + out->cr(); + out->print(" Both: "); + print_scaled_words(out, ChunkManager::chunkmanager_nonclass()->total_word_size() + + ChunkManager::chunkmanager_class()->total_word_size(), scale); + out->cr(); +#endif // INCLUDE_CLASS_SPACE out->cr(); // Print basic settings @@ -256,70 +250,70 @@ void MetaspaceReporter::print_report(outputStream* out, size_t scale, int flags) // -- Print VirtualSpaceList details. if ((flags & (int)Option::ShowVSList) > 0) { out->cr(); - out->print_cr("Virtual space list%s:", Metaspace::using_class_space() ? "s" : ""); - - if (Metaspace::using_class_space()) { - out->print_cr(" Non-Class:"); - } +#if INCLUDE_CLASS_SPACE + out->print_cr("Virtual space lists:"); + out->print_cr(" Non-Class:"); VirtualSpaceList::vslist_nonclass()->print_on(out); out->cr(); - if (Metaspace::using_class_space()) { - out->print_cr(" Class:"); - VirtualSpaceList::vslist_class()->print_on(out); - out->cr(); - } + out->print_cr(" Class:"); + VirtualSpaceList::vslist_class()->print_on(out); + out->cr(); +#else + out->print_cr("Virtual space list:"); + VirtualSpaceList::vslist_nonclass()->print_on(out); + out->cr(); +#endif // INCLUDE_CLASS_SPACE } out->cr(); //////////// Freelists (ChunkManager) section /////////////////////////// - out->cr(); - out->print_cr("Chunk freelist%s:", Metaspace::using_class_space() ? "s" : ""); - ChunkManagerStats non_class_cm_stat; ChunkManagerStats class_cm_stat; ChunkManagerStats total_cm_stat; ChunkManager::chunkmanager_nonclass()->add_to_statistics(&non_class_cm_stat); - if (Metaspace::using_class_space()) { - ChunkManager::chunkmanager_nonclass()->add_to_statistics(&non_class_cm_stat); - ChunkManager::chunkmanager_class()->add_to_statistics(&class_cm_stat); - total_cm_stat.add(non_class_cm_stat); - total_cm_stat.add(class_cm_stat); +#if INCLUDE_CLASS_SPACE + ChunkManager::chunkmanager_class()->add_to_statistics(&class_cm_stat); + total_cm_stat.add(non_class_cm_stat); + total_cm_stat.add(class_cm_stat); - out->print_cr(" Non-Class:"); - non_class_cm_stat.print_on(out, scale); - out->cr(); - out->print_cr(" Class:"); - class_cm_stat.print_on(out, scale); - out->cr(); - out->print_cr(" Both:"); - total_cm_stat.print_on(out, scale); - out->cr(); - } else { - ChunkManager::chunkmanager_nonclass()->add_to_statistics(&non_class_cm_stat); - non_class_cm_stat.print_on(out, scale); - out->cr(); - } + out->print_cr("Chunk freelists:"); + out->cr(); + out->print_cr(" Non-Class:"); + non_class_cm_stat.print_on(out, scale); + out->cr(); + out->print_cr(" Class:"); + class_cm_stat.print_on(out, scale); + out->cr(); + out->print_cr(" Both:"); + total_cm_stat.print_on(out, scale); + out->cr(); +#else + out->print_cr("Chunk freelist:"); + ChunkManager::chunkmanager_nonclass()->add_to_statistics(&non_class_cm_stat); + non_class_cm_stat.print_on(out, scale); + out->cr(); +#endif // INCLUDE_CLASS_SPACE // -- Print Chunkmanager details. if ((flags & (int)Option::ShowChunkFreeList) > 0) { out->cr(); out->print_cr("Chunk freelist details:"); - if (Metaspace::using_class_space()) { - out->print_cr(" Non-Class:"); - } +#if INCLUDE_CLASS_SPACE + out->print_cr(" Non-Class:"); ChunkManager::chunkmanager_nonclass()->print_on(out); out->cr(); - if (Metaspace::using_class_space()) { - out->print_cr(" Class:"); - ChunkManager::chunkmanager_class()->print_on(out); - out->cr(); - } + out->print_cr(" Class:"); + ChunkManager::chunkmanager_class()->print_on(out); + out->cr(); +#else + ChunkManager::chunkmanager_nonclass()->print_on(out); + out->cr(); +#endif // INCLUDE_CLASS_SPACE } out->cr(); - //////////// Waste section /////////////////////////// // As a convenience, print a summary of common waste. out->cr(); diff --git a/src/hotspot/share/memory/metaspace/metaspaceStatistics.cpp b/src/hotspot/share/memory/metaspace/metaspaceStatistics.cpp index aab46d64db5..d90e8ed090d 100644 --- a/src/hotspot/share/memory/metaspace/metaspaceStatistics.cpp +++ b/src/hotspot/share/memory/metaspace/metaspaceStatistics.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2018, 2020 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -205,28 +205,26 @@ ArenaStats ClmsStats::totals() const { void ClmsStats::print_on(outputStream* st, size_t scale, bool detailed) const { StreamIndentor si(st, 2); st->cr(); - if (Metaspace::using_class_space()) { - st->print("Non-Class: "); - } + CLASS_SPACE_ONLY(st->print("Non-Class: ");) _arena_stats_nonclass.print_on(st, scale, detailed); if (detailed) { st->cr(); } - if (Metaspace::using_class_space()) { +#if INCLUDE_CLASS_SPACE + st->cr(); + st->print(" Class: "); + _arena_stats_class.print_on(st, scale, detailed); + if (detailed) { st->cr(); - st->print(" Class: "); - _arena_stats_class.print_on(st, scale, detailed); - if (detailed) { - st->cr(); - } - st->cr(); - st->print(" Both: "); - totals().print_on(st, scale, detailed); - if (detailed) { - st->cr(); - } } st->cr(); + st->print(" Both: "); + totals().print_on(st, scale, detailed); + if (detailed) { + st->cr(); + } +#endif // INCLUDE_CLASS_SPACE + st->cr(); } #ifdef ASSERT diff --git a/src/hotspot/share/memory/metaspace/virtualSpaceNode.cpp b/src/hotspot/share/memory/metaspace/virtualSpaceNode.cpp index df4e507b104..a934a628582 100644 --- a/src/hotspot/share/memory/metaspace/virtualSpaceNode.cpp +++ b/src/hotspot/share/memory/metaspace/virtualSpaceNode.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2018, 2021 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -259,12 +259,11 @@ VirtualSpaceNode* VirtualSpaceNode::create_node(size_t word_size, } #ifndef _LP64 - // On 32-bit, with +UseCompressedClassPointers, the whole address space is the encoding range. We therefore - // don't need a class space. However, as a pragmatic workaround for pesty overflow problems on 32-bit, we leave - // a small area at the end of the address space out of the encoding range. We just assume no Klass will ever live + // On 32-bit, the whole address space is the encoding range. We therefore don't need a class space. + // However, as a pragmatic workaround for pesty overflow problems on 32-bit, we leave a small area + // at the end of the address space out of the encoding range. We just assume no Klass will ever live // there (it won't, for no OS we support on 32-bit has user-addressable memory up there). - assert(!UseCompressedClassPointers || - rs.end() <= (char*)CompressedKlassPointers::max_klass_range_size(), "Weirdly high address"); + assert(rs.end() <= (char*)CompressedKlassPointers::max_klass_range_size(), "Weirdly high address"); #endif // _LP64 MemTracker::record_virtual_memory_tag(rs, mtMetaspace); diff --git a/src/hotspot/share/nmt/memReporter.cpp b/src/hotspot/share/nmt/memReporter.cpp index 27a94ec7bc0..429db6ad31f 100644 --- a/src/hotspot/share/nmt/memReporter.cpp +++ b/src/hotspot/share/nmt/memReporter.cpp @@ -272,9 +272,7 @@ void MemSummaryReporter::report_summary_of_tag(MemTag mem_tag, } else if (mem_tag == mtClass) { // Metadata information report_metadata(Metaspace::NonClassType); - if (Metaspace::using_class_space()) { - report_metadata(Metaspace::ClassType); - } + CLASS_SPACE_ONLY(report_metadata(Metaspace::ClassType);) } out->cr(); } @@ -754,9 +752,9 @@ void MemSummaryDiffReporter::diff_summary_of_tag(MemTag mem_tag, void MemSummaryDiffReporter::print_metaspace_diff(const MetaspaceCombinedStats& current_ms, const MetaspaceCombinedStats& early_ms) const { print_metaspace_diff("Metadata", current_ms.non_class_space_stats(), early_ms.non_class_space_stats()); - if (Metaspace::using_class_space()) { - print_metaspace_diff("Class space", current_ms.class_space_stats(), early_ms.class_space_stats()); - } +#if INCLUDE_CLASS_SPACE + print_metaspace_diff("Class space", current_ms.class_space_stats(), early_ms.class_space_stats()); +#endif } void MemSummaryDiffReporter::print_metaspace_diff(const char* header, diff --git a/src/hotspot/share/oops/arrayOop.hpp b/src/hotspot/share/oops/arrayOop.hpp index f0c476a2486..836a1b9250d 100644 --- a/src/hotspot/share/oops/arrayOop.hpp +++ b/src/hotspot/share/oops/arrayOop.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * 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,8 +80,7 @@ private: // The _length field is not declared in C++. It is allocated after the // mark-word when using compact headers (+UseCompactObjectHeaders), otherwise - // after the compressed Klass* when running with compressed class-pointers - // (+UseCompressedClassPointers), or else after the full Klass*. + // after the compressed Klass*. static int length_offset_in_bytes() { return oopDesc::base_offset_in_bytes(); } diff --git a/src/hotspot/share/oops/compressedKlass.cpp b/src/hotspot/share/oops/compressedKlass.cpp index b32d10c74d2..ca1c46d4095 100644 --- a/src/hotspot/share/oops/compressedKlass.cpp +++ b/src/hotspot/share/oops/compressedKlass.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -95,7 +95,7 @@ void CompressedKlassPointers::sanity_check_after_initialization() { // We should need a class space if address space is larger than what narrowKlass can address const bool should_need_class_space = (BytesPerWord * BitsPerByte) > narrow_klass_pointer_bits(); - ASSERT_HERE(should_need_class_space == needs_class_space()); + ASSERT_HERE(should_need_class_space == (INCLUDE_CLASS_SPACE ? true : false)); const size_t klass_align = klass_alignment_in_bytes(); @@ -318,24 +318,19 @@ void CompressedKlassPointers::initialize(address addr, size_t len) { } void CompressedKlassPointers::print_mode(outputStream* st) { - st->print_cr("UseCompressedClassPointers %d, UseCompactObjectHeaders %d", - UseCompressedClassPointers, UseCompactObjectHeaders); - if (UseCompressedClassPointers) { - st->print_cr("Narrow klass pointer bits %d, Max shift %d", - _narrow_klass_pointer_bits, _max_shift); - st->print_cr("Narrow klass base: " PTR_FORMAT ", Narrow klass shift: %d", - p2i(base()), shift()); - st->print_cr("Encoding Range: " RANGE2FMT, RANGE2FMTARGS(_base, encoding_range_end())); - 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."); - } + st->print_cr("UseCompactObjectHeaders %d", UseCompactObjectHeaders); + st->print_cr("Narrow klass pointer bits %d, Max shift %d", + _narrow_klass_pointer_bits, _max_shift); + st->print_cr("Narrow klass base: " PTR_FORMAT ", Narrow klass shift: %d", + p2i(base()), shift()); + st->print_cr("Encoding Range: " RANGE2FMT, RANGE2FMTARGS(_base, encoding_range_end())); + 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("UseCompressedClassPointers off"); + st->print_cr("No protection zone."); } } diff --git a/src/hotspot/share/oops/compressedKlass.hpp b/src/hotspot/share/oops/compressedKlass.hpp index 98a9eafdbf4..fe1ce9e07ae 100644 --- a/src/hotspot/share/oops/compressedKlass.hpp +++ b/src/hotspot/share/oops/compressedKlass.hpp @@ -98,7 +98,6 @@ class Klass; // If compressed klass pointers then use narrowKlass. typedef juint narrowKlass; -// For UseCompressedClassPointers. class CompressedKlassPointers : public AllStatic { friend class VMStructs; friend class ArchiveBuilder; @@ -161,7 +160,6 @@ public: // Initialization sequence: // 1) Parse arguments. The following arguments take a role: - // - UseCompressedClassPointers // - UseCompactObjectHeaders // - Xshare on off dump // - CompressedClassSpaceSize @@ -192,12 +190,6 @@ public: // resulting from the current encoding settings (base, shift), capped to a certain max. value. static size_t max_klass_range_size(); - // On 64-bit, we need the class space to confine Klass structures to the encoding range, which is determined - // by bit size of narrowKlass IDs and the shift. On 32-bit, we support compressed class pointer only - // "pro-forma": narrowKlass have the same size as addresses (32 bits), and therefore the encoding range is - // equal to the address space size. Here, we don't need a class space. - static constexpr bool needs_class_space() { return LP64_ONLY(true) NOT_LP64(false); } - // Reserve a range of memory that is to contain Klass strucutures which are referenced by narrow Klass IDs. // If optimize_for_zero_base is true, the implementation will attempt to reserve optimized for zero-based encoding. static char* reserve_address_space_for_compressed_classes(size_t size, bool aslr, bool optimize_for_zero_base); diff --git a/src/hotspot/share/oops/compressedKlass.inline.hpp b/src/hotspot/share/oops/compressedKlass.inline.hpp index 65732b3b289..834264286bc 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, 2026, Oracle and/or its affiliates. All rights reserved. * 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,7 +75,6 @@ inline narrowKlass CompressedKlassPointers::encode(const Klass* v) { #ifdef ASSERT inline void CompressedKlassPointers::check_encodable(const void* addr) { - assert(UseCompressedClassPointers, "Only call for +UseCCP"); assert(addr != nullptr, "Null Klass?"); assert(is_encodable(addr), "Address " PTR_FORMAT " is not encodable (Klass range: " RANGEFMT ", klass alignment: %d)", @@ -84,7 +83,6 @@ inline void CompressedKlassPointers::check_encodable(const void* addr) { inline void CompressedKlassPointers::check_valid_narrow_klass_id(narrowKlass nk) { check_init(_base); - assert(UseCompressedClassPointers, "Only call for +UseCCP"); assert(nk > 0, "narrow Klass ID is 0"); const uint64_t nk_mask = ~right_n_bits(narrow_klass_pointer_bits()); assert(((uint64_t)nk & nk_mask) == 0, "narrow klass id bit spillover (%u)", nk); diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp index 919afbf3abd..d3333e72c2a 100644 --- a/src/hotspot/share/oops/instanceKlass.cpp +++ b/src/hotspot/share/oops/instanceKlass.cpp @@ -486,10 +486,8 @@ InstanceKlass* InstanceKlass::allocate_instance_klass(const ClassFileParser& par ik = new (loader_data, size, THREAD) InstanceKlass(parser); } - if (ik != nullptr && UseCompressedClassPointers) { - assert(CompressedKlassPointers::is_encodable(ik), - "Klass " PTR_FORMAT "needs a narrow Klass ID, but is not encodable", p2i(ik)); - } + assert(ik == nullptr || CompressedKlassPointers::is_encodable(ik), + "Klass " PTR_FORMAT "needs a narrow Klass ID, but is not encodable", p2i(ik)); // Check for pending exception before adding to the loader data and incrementing // class count. Can get OOM here. diff --git a/src/hotspot/share/oops/klass.cpp b/src/hotspot/share/oops/klass.cpp index 001e9eba790..84a1766a702 100644 --- a/src/hotspot/share/oops/klass.cpp +++ b/src/hotspot/share/oops/klass.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1055,14 +1055,8 @@ void Klass::verify_on(outputStream* st) { // This can be expensive, but it is worth checking that this klass is actually // in the CLD graph but not in production. -#ifdef ASSERT - if (UseCompressedClassPointers) { - // Stricter checks for both correct alignment and placement - CompressedKlassPointers::check_encodable(this); - } else { - assert(Metaspace::contains((address)this), "Should be"); - } -#endif // ASSERT + // Stricter checks for both correct alignment and placement + DEBUG_ONLY(CompressedKlassPointers::check_encodable(this)); guarantee(this->is_klass(),"should be klass"); diff --git a/src/hotspot/share/oops/objLayout.cpp b/src/hotspot/share/oops/objLayout.cpp index b8cd8249da1..2c426a7ddff 100644 --- a/src/hotspot/share/oops/objLayout.cpp +++ b/src/hotspot/share/oops/objLayout.cpp @@ -38,21 +38,17 @@ void ObjLayout::initialize() { _klass_mode = Compact; _oop_base_offset_in_bytes = sizeof(markWord); _oop_has_klass_gap = false; - } else if (UseCompressedClassPointers) { + } else { _klass_mode = Compressed; _oop_base_offset_in_bytes = sizeof(markWord) + sizeof(narrowKlass); _oop_has_klass_gap = true; - } else { - _klass_mode = Uncompressed; - _oop_base_offset_in_bytes = sizeof(markWord) + sizeof(Klass*); - _oop_has_klass_gap = false; } #else assert(_klass_mode == Undefined, "ObjLayout initialized twice"); assert(!UseCompactObjectHeaders, "COH unsupported on 32-bit"); - // We support +-UseCompressedClassPointers on 32-bit, but the layout + // We support narrow Klass pointers on 32-bit, but the layout // is exactly the same as it was with uncompressed klass pointers - _klass_mode = UseCompressedClassPointers ? Compressed : Uncompressed; + _klass_mode = Compressed; _oop_base_offset_in_bytes = sizeof(markWord) + sizeof(Klass*); _oop_has_klass_gap = false; #endif diff --git a/src/hotspot/share/oops/objLayout.hpp b/src/hotspot/share/oops/objLayout.hpp index e434524d4b0..37ed0b7a532 100644 --- a/src/hotspot/share/oops/objLayout.hpp +++ b/src/hotspot/share/oops/objLayout.hpp @@ -27,8 +27,8 @@ /* * This class helps to avoid loading more than one flag in some - * operations that require checking UseCompressedClassPointers, - * UseCompactObjectHeaders and possibly more. + * operations that require checking UseCompactObjectHeaders and - in the future - + * possibly more. * * This is important on some performance critical paths, e.g. where * the Klass* is accessed frequently, especially by GC oop iterators @@ -37,12 +37,10 @@ class ObjLayout { public: enum Mode { - // +UseCompactObjectHeaders (implies +UseCompressedClassPointers) + // +UseCompactObjectHeaders Compact, - // +UseCompressedClassPointers (-UseCompactObjectHeaders) + // -UseCompactObjectHeaders (compressed Klass pointers) Compressed, - // -UseCompressedClassPointers (-UseCompactObjectHeaders) - Uncompressed, // Not yet initialized Undefined }; diff --git a/src/hotspot/share/oops/objLayout.inline.hpp b/src/hotspot/share/oops/objLayout.inline.hpp index 6aa9e39ce28..adad490378d 100644 --- a/src/hotspot/share/oops/objLayout.inline.hpp +++ b/src/hotspot/share/oops/objLayout.inline.hpp @@ -32,10 +32,8 @@ inline ObjLayout::Mode ObjLayout::klass_mode() { assert(_klass_mode != Undefined, "KlassMode not yet initialized"); if (UseCompactObjectHeaders) { assert(_klass_mode == Compact, "Klass mode does not match flags"); - } else if (UseCompressedClassPointers) { - assert(_klass_mode == Compressed, "Klass mode does not match flags"); } else { - assert(_klass_mode == Uncompressed, "Klass mode does not match flags"); + assert(_klass_mode == Compressed, "Klass mode does not match flags"); } #endif return _klass_mode; diff --git a/src/hotspot/share/oops/oop.cpp b/src/hotspot/share/oops/oop.cpp index 5f453241c3d..415732af4f6 100644 --- a/src/hotspot/share/oops/oop.cpp +++ b/src/hotspot/share/oops/oop.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -152,8 +152,7 @@ bool oopDesc::is_typeArray_noinline() const { return is_typeArray(); } #if INCLUDE_CDS_JAVA_HEAP void oopDesc::set_narrow_klass(narrowKlass nk) { assert(CDSConfig::is_dumping_heap(), "Used by CDS only. Do not abuse!"); - assert(UseCompressedClassPointers, "must be"); - _metadata._compressed_klass = nk; + _compressed_klass = nk; } #endif diff --git a/src/hotspot/share/oops/oop.hpp b/src/hotspot/share/oops/oop.hpp index 0dc6590750e..d6cc71a60d8 100644 --- a/src/hotspot/share/oops/oop.hpp +++ b/src/hotspot/share/oops/oop.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * 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,10 +49,7 @@ class oopDesc { friend class JVMCIVMStructs; private: volatile markWord _mark; - union _metadata { - Klass* _klass; - narrowKlass _compressed_klass; - } _metadata; + narrowKlass _compressed_klass; // There may be ordering constraints on the initialization of fields that // make use of the C++ copy/assign incorrect. @@ -338,7 +335,7 @@ class oopDesc { } else #endif { - return (int)offset_of(oopDesc, _metadata._klass); + return (int)offset_of(oopDesc, _compressed_klass); } } static int klass_gap_offset_in_bytes() { diff --git a/src/hotspot/share/oops/oop.inline.hpp b/src/hotspot/share/oops/oop.inline.hpp index b445eae933b..d5cb80e1122 100644 --- a/src/hotspot/share/oops/oop.inline.hpp +++ b/src/hotspot/share/oops/oop.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * 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,9 +99,9 @@ Klass* oopDesc::klass() const { case ObjLayout::Compact: return mark().klass(); case ObjLayout::Compressed: - return CompressedKlassPointers::decode_not_null(_metadata._compressed_klass); + return CompressedKlassPointers::decode_not_null(_compressed_klass); default: - return _metadata._klass; + ShouldNotReachHere(); } } @@ -110,9 +110,9 @@ Klass* oopDesc::klass_or_null() const { case ObjLayout::Compact: return mark().klass_or_null(); case ObjLayout::Compressed: - return CompressedKlassPointers::decode(_metadata._compressed_klass); + return CompressedKlassPointers::decode(_compressed_klass); default: - return _metadata._klass; + ShouldNotReachHere(); } } @@ -121,11 +121,11 @@ Klass* oopDesc::klass_or_null_acquire() const { case ObjLayout::Compact: return mark_acquire().klass(); case ObjLayout::Compressed: { - narrowKlass narrow_klass = AtomicAccess::load_acquire(&_metadata._compressed_klass); + narrowKlass narrow_klass = AtomicAccess::load_acquire(&_compressed_klass); return CompressedKlassPointers::decode(narrow_klass); } default: - return AtomicAccess::load_acquire(&_metadata._klass); + ShouldNotReachHere(); } } @@ -134,9 +134,9 @@ Klass* oopDesc::klass_without_asserts() const { case ObjLayout::Compact: return mark().klass_without_asserts(); case ObjLayout::Compressed: - return CompressedKlassPointers::decode_without_asserts(_metadata._compressed_klass); + return CompressedKlassPointers::decode_without_asserts(_compressed_klass); default: - return _metadata._klass; + ShouldNotReachHere(); } } @@ -145,7 +145,7 @@ narrowKlass oopDesc::narrow_klass() const { case ObjLayout::Compact: return mark().narrow_klass(); case ObjLayout::Compressed: - return _metadata._compressed_klass; + return _compressed_klass; default: ShouldNotReachHere(); } @@ -154,23 +154,14 @@ narrowKlass oopDesc::narrow_klass() const { void oopDesc::set_klass(Klass* k) { assert(Universe::is_bootstrapping() || (k != nullptr && k->is_klass()), "incorrect Klass"); assert(!UseCompactObjectHeaders, "don't set Klass* with compact headers"); - if (UseCompressedClassPointers) { - _metadata._compressed_klass = CompressedKlassPointers::encode_not_null(k); - } else { - _metadata._klass = k; - } + _compressed_klass = CompressedKlassPointers::encode_not_null(k); } void oopDesc::release_set_klass(HeapWord* mem, Klass* k) { assert(Universe::is_bootstrapping() || (k != nullptr && k->is_klass()), "incorrect Klass"); assert(!UseCompactObjectHeaders, "don't set Klass* with compact headers"); char* raw_mem = ((char*)mem + klass_offset_in_bytes()); - if (UseCompressedClassPointers) { - AtomicAccess::release_store((narrowKlass*)raw_mem, - CompressedKlassPointers::encode_not_null(k)); - } else { - AtomicAccess::release_store((Klass**)raw_mem, k); - } + AtomicAccess::release_store((narrowKlass*)raw_mem, CompressedKlassPointers::encode_not_null(k)); } void oopDesc::set_klass_gap(HeapWord* mem, int v) { diff --git a/src/hotspot/share/opto/cfgnode.cpp b/src/hotspot/share/opto/cfgnode.cpp index a251a253ed1..0915f79a503 100644 --- a/src/hotspot/share/opto/cfgnode.cpp +++ b/src/hotspot/share/opto/cfgnode.cpp @@ -2689,7 +2689,7 @@ Node *PhiNode::Ideal(PhaseGVN *phase, bool can_reshape) { #ifdef _LP64 // Push DecodeN/DecodeNKlass down through phi. // The rest of phi graph will transform by split EncodeP node though phis up. - if ((UseCompressedOops || UseCompressedClassPointers) && can_reshape && progress == nullptr) { + if (can_reshape && progress == nullptr) { bool may_push = true; bool has_decodeN = false; bool is_decodeN = false; diff --git a/src/hotspot/share/opto/chaitin.cpp b/src/hotspot/share/opto/chaitin.cpp index 3ba3ffc1045..ef017ee15ec 100644 --- a/src/hotspot/share/opto/chaitin.cpp +++ b/src/hotspot/share/opto/chaitin.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2633,7 +2633,7 @@ void PhaseChaitin::verify_base_ptrs(ResourceArea* a) const { #ifdef _LP64 (UseCompressedOops && check->as_Mach()->ideal_Opcode() == Op_CastPP) || (UseCompressedOops && check->as_Mach()->ideal_Opcode() == Op_DecodeN) || - (UseCompressedClassPointers && check->as_Mach()->ideal_Opcode() == Op_DecodeNKlass) || + (check->as_Mach()->ideal_Opcode() == Op_DecodeNKlass) || #endif // _LP64 check->as_Mach()->ideal_Opcode() == Op_LoadP || check->as_Mach()->ideal_Opcode() == Op_LoadKlass))) { diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index f34c75656a4..7ab384a29c7 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -3414,8 +3414,7 @@ void Compile::final_graph_reshaping_main_switch(Node* n, Final_Reshape_Counts& f Node *addp = n->in(AddPNode::Address); assert(n->as_AddP()->address_input_has_same_base(), "Base pointers must match (addp %u)", addp->_idx ); #ifdef _LP64 - if ((UseCompressedOops || UseCompressedClassPointers) && - addp->Opcode() == Op_ConP && + if (addp->Opcode() == Op_ConP && addp == n->in(AddPNode::Base) && n->in(AddPNode::Offset)->is_Con()) { // If the transformation of ConP to ConN+DecodeN is beneficial depends @@ -3428,7 +3427,7 @@ void Compile::final_graph_reshaping_main_switch(Node* n, Final_Reshape_Counts& f bool is_klass = t->isa_klassptr() != nullptr; if ((is_oop && UseCompressedOops && Matcher::const_oop_prefer_decode() ) || - (is_klass && UseCompressedClassPointers && Matcher::const_klass_prefer_decode() && + (is_klass && Matcher::const_klass_prefer_decode() && t->isa_klassptr()->exact_klass()->is_in_encoding_range())) { Node* nn = nullptr; @@ -3975,8 +3974,7 @@ void Compile::final_graph_reshaping_walk(Node_Stack& nstack, Node* root, Final_R } // Skip next transformation if compressed oops are not used. - if ((UseCompressedOops && !Matcher::gen_narrow_oop_implicit_null_checks()) || - (!UseCompressedOops && !UseCompressedClassPointers)) + if (UseCompressedOops && !Matcher::gen_narrow_oop_implicit_null_checks()) return; // Go over safepoints nodes to skip DecodeN/DecodeNKlass nodes for debug edges. diff --git a/src/hotspot/share/opto/lcm.cpp b/src/hotspot/share/opto/lcm.cpp index 53a503866fa..450d267e821 100644 --- a/src/hotspot/share/opto/lcm.cpp +++ b/src/hotspot/share/opto/lcm.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -306,8 +306,7 @@ void PhaseCFG::implicit_null_check(Block* block, Node *proj, Node *val, int allo // cannot reason about it; is probably not implicit null exception } else { const TypePtr* tptr; - if ((UseCompressedOops && CompressedOops::shift() == 0) || - (UseCompressedClassPointers && CompressedKlassPointers::shift() == 0)) { + if ((UseCompressedOops && CompressedOops::shift() == 0) || CompressedKlassPointers::shift() == 0) { // 32-bits narrow oop can be the base of address expressions tptr = base->get_ptr_type(); } else { diff --git a/src/hotspot/share/opto/memnode.cpp b/src/hotspot/share/opto/memnode.cpp index 3cd553e4bd1..46f6729c82f 100644 --- a/src/hotspot/share/opto/memnode.cpp +++ b/src/hotspot/share/opto/memnode.cpp @@ -2486,7 +2486,6 @@ Node* LoadKlassNode::make(PhaseGVN& gvn, Node* mem, Node* adr, const TypePtr* at assert(adr_type != nullptr, "expecting TypeKlassPtr"); #ifdef _LP64 if (adr_type->is_ptr_to_narrowklass()) { - assert(UseCompressedClassPointers, "no compressed klasses"); Node* load_klass = gvn.transform(new LoadNKlassNode(mem, adr, at, tk->make_narrowklass(), MemNode::unordered)); return new DecodeNKlassNode(load_klass, load_klass->bottom_type()->make_ptr()); } @@ -2816,8 +2815,7 @@ StoreNode* StoreNode::make(PhaseGVN& gvn, Node* ctl, Node* mem, Node* adr, const val = gvn.transform(new EncodePNode(val, val->bottom_type()->make_narrowoop())); return new StoreNNode(ctl, mem, adr, adr_type, val, mo); } else if (adr->bottom_type()->is_ptr_to_narrowklass() || - (UseCompressedClassPointers && val->bottom_type()->isa_klassptr() && - adr->bottom_type()->isa_rawptr())) { + (val->bottom_type()->isa_klassptr() && adr->bottom_type()->isa_rawptr())) { val = gvn.transform(new EncodePKlassNode(val, val->bottom_type()->make_narrowklass())); return new StoreNKlassNode(ctl, mem, adr, adr_type, val, mo); } diff --git a/src/hotspot/share/opto/narrowptrnode.cpp b/src/hotspot/share/opto/narrowptrnode.cpp index 7f86b8caecf..8b91bfaa944 100644 --- a/src/hotspot/share/opto/narrowptrnode.cpp +++ b/src/hotspot/share/opto/narrowptrnode.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * 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,7 +102,7 @@ const Type* EncodePKlassNode::Value(PhaseGVN* phase) const { if (t == Type::TOP) return Type::TOP; assert (t != TypePtr::NULL_PTR, "null klass?"); - assert(UseCompressedClassPointers && t->isa_klassptr(), "only klass ptr here"); + assert(t->isa_klassptr(), "only klass ptr here"); return t->make_narrowklass(); } diff --git a/src/hotspot/share/opto/type.cpp b/src/hotspot/share/opto/type.cpp index aab2ea3cd3b..308ec819773 100644 --- a/src/hotspot/share/opto/type.cpp +++ b/src/hotspot/share/opto/type.cpp @@ -3489,7 +3489,7 @@ TypeOopPtr::TypeOopPtr(TYPES t, PTR ptr, ciKlass* k, const TypeInterfaces* inter #ifdef _LP64 if (_offset > 0 || _offset == Type::OffsetTop || _offset == Type::OffsetBot) { if (_offset == oopDesc::klass_offset_in_bytes()) { - _is_ptr_to_narrowklass = UseCompressedClassPointers; + _is_ptr_to_narrowklass = true; } else if (klass() == nullptr) { // Array with unknown body type assert(this->isa_aryptr(), "only arrays without klass"); diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index 5df1461c0fd..a13d0ba47c8 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -333,7 +333,6 @@ WB_ENTRY(void, WB_ReadFromNoaccessArea(JNIEnv* env, jobject o)) 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)); diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index dac34017e45..1d79c4d0488 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -1554,7 +1554,7 @@ void Arguments::set_heap_size() { } #ifdef _LP64 - if (UseCompressedOops || UseCompressedClassPointers) { + if (UseCompressedOops) { // HeapBaseMinAddress can be greater than default but not less than. if (!FLAG_IS_DEFAULT(HeapBaseMinAddress)) { if (HeapBaseMinAddress < DefaultHeapBaseMinAddress) { @@ -1567,9 +1567,7 @@ void Arguments::set_heap_size() { FLAG_SET_ERGO(HeapBaseMinAddress, DefaultHeapBaseMinAddress); } } - } - if (UseCompressedOops) { uintptr_t heap_end = HeapBaseMinAddress + MaxHeapSize; uintptr_t max_coop_heap = max_heap_for_compressed_oops(); @@ -3782,10 +3780,6 @@ jint Arguments::parse(const JavaVMInitArgs* initial_cmd_args) { void Arguments::set_compact_headers_flags() { #ifdef _LP64 - if (UseCompactObjectHeaders && FLAG_IS_CMDLINE(UseCompressedClassPointers) && !UseCompressedClassPointers) { - warning("Compact object headers require compressed class pointers. Disabling compact object headers."); - FLAG_SET_DEFAULT(UseCompactObjectHeaders, false); - } if (UseCompactObjectHeaders && !UseObjectMonitorTable) { // If UseCompactObjectHeaders is on the command line, turn on UseObjectMonitorTable. if (FLAG_IS_CMDLINE(UseCompactObjectHeaders)) { @@ -3799,9 +3793,6 @@ void Arguments::set_compact_headers_flags() { FLAG_SET_DEFAULT(UseObjectMonitorTable, true); } } - if (UseCompactObjectHeaders && !UseCompressedClassPointers) { - FLAG_SET_DEFAULT(UseCompressedClassPointers, true); - } #endif } @@ -3817,9 +3808,7 @@ jint Arguments::apply_ergo() { set_compact_headers_flags(); - if (UseCompressedClassPointers) { - CompressedKlassPointers::pre_initialize(); - } + CompressedKlassPointers::pre_initialize(); CDSConfig::ergo_initialize(); @@ -3864,10 +3853,6 @@ jint Arguments::apply_ergo() { DebugNonSafepoints = true; } - if (FLAG_IS_CMDLINE(CompressedClassSpaceSize) && !UseCompressedClassPointers) { - warning("Setting CompressedClassSpaceSize has no effect when compressed class pointers are not used"); - } - // Treat the odd case where local verification is enabled but remote // verification is not as if both were enabled. if (BytecodeVerificationLocal && !BytecodeVerificationRemote) { diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp index 60feddde09b..b5c19d8aa36 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -1368,9 +1368,6 @@ const int ObjectAlignmentInBytes = 8; "Maximum size of Metaspaces (in bytes)") \ constraint(MaxMetaspaceSizeConstraintFunc,AfterErgo) \ \ - product(bool, UseCompressedClassPointers, true, \ - "(Deprecated) Use 32-bit class pointers.") \ - \ product(size_t, CompressedClassSpaceSize, 1*G, \ "Maximum size of class area in Metaspace when compressed " \ "class pointers are used") \ diff --git a/src/hotspot/share/runtime/os.cpp b/src/hotspot/share/runtime/os.cpp index 129f8f76e73..d55cf454256 100644 --- a/src/hotspot/share/runtime/os.cpp +++ b/src/hotspot/share/runtime/os.cpp @@ -1285,7 +1285,7 @@ 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)) { + if (CompressedKlassPointers::is_in_protection_zone(addr)) { st->print_cr(PTR_FORMAT " points into nKlass protection zone", p2i(addr)); return; } @@ -1339,8 +1339,9 @@ void os::print_location(outputStream* st, intptr_t x, bool verbose) { } // Compressed klass needs to be decoded first. + // Todo: questionable for COH - can we do this better? #ifdef _LP64 - if (UseCompressedClassPointers && ((uintptr_t)addr &~ (uintptr_t)max_juint) == 0) { + if (((uintptr_t)addr &~ (uintptr_t)max_juint) == 0) { narrowKlass narrow_klass = (narrowKlass)(uintptr_t)addr; Klass* k = CompressedKlassPointers::decode_without_asserts(narrow_klass); diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index b6294a9a168..ad9463443b2 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -163,8 +163,7 @@ /******************************************************************/ \ \ volatile_nonstatic_field(oopDesc, _mark, markWord) \ - volatile_nonstatic_field(oopDesc, _metadata._klass, Klass*) \ - volatile_nonstatic_field(oopDesc, _metadata._compressed_klass, narrowKlass) \ + volatile_nonstatic_field(oopDesc, _compressed_klass, narrowKlass) \ static_field(BarrierSet, _barrier_set, BarrierSet*) \ nonstatic_field(ArrayKlass, _dimension, const int) \ volatile_nonstatic_field(ArrayKlass, _higher_dimension, ObjArrayKlass*) \ diff --git a/src/hotspot/share/services/memoryService.cpp b/src/hotspot/share/services/memoryService.cpp index f64da3c5477..4636f125079 100644 --- a/src/hotspot/share/services/memoryService.cpp +++ b/src/hotspot/share/services/memoryService.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -119,11 +119,11 @@ void MemoryService::add_metaspace_memory_pools() { mgr->add_pool(_metaspace_pool); _pools_list->append(_metaspace_pool); - if (UseCompressedClassPointers) { - _compressed_class_pool = new CompressedKlassSpacePool(); - mgr->add_pool(_compressed_class_pool); - _pools_list->append(_compressed_class_pool); - } +#if INCLUDE_CLASS_SPACE + _compressed_class_pool = new CompressedKlassSpacePool(); + mgr->add_pool(_compressed_class_pool); + _pools_list->append(_compressed_class_pool); +#endif _managers_list->append(mgr); } diff --git a/src/hotspot/share/utilities/macros.hpp b/src/hotspot/share/utilities/macros.hpp index a03255b5cf3..3621f675ecb 100644 --- a/src/hotspot/share/utilities/macros.hpp +++ b/src/hotspot/share/utilities/macros.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -586,6 +586,18 @@ #define BIG_ENDIAN_ONLY(code) code #endif +#ifdef _LP64 +#define INCLUDE_CLASS_SPACE 1 +#define CLASS_SPACE_ONLY(x) x +#define NOT_CLASS_SPACE(x) +#else +// On 32-bit we use fake "narrow class pointers" which are really just 32-bit pointers, +// but we don't use a class space (would cause too much address space fragmentation) +#define INCLUDE_CLASS_SPACE 0 +#define CLASS_SPACE_ONLY(x) +#define NOT_CLASS_SPACE(x) x +#endif + #define define_pd_global(type, name, value) const type pd_##name = value; // Helper macros for constructing file names for includes. diff --git a/src/hotspot/share/utilities/vmError.cpp b/src/hotspot/share/utilities/vmError.cpp index 48fae6868ab..d78fd331b56 100644 --- a/src/hotspot/share/utilities/vmError.cpp +++ b/src/hotspot/share/utilities/vmError.cpp @@ -533,8 +533,7 @@ static void report_vm_version(outputStream* st, char* buf, int buflen) { "", "", #endif UseCompressedOops ? ", compressed oops" : "", - UseCompactObjectHeaders ? ", compact obj headers" - : (UseCompressedClassPointers ? ", compressed class ptrs" : ""), + UseCompactObjectHeaders ? ", compact obj headers" : "", GCConfig::hs_err_name(), VM_Version::vm_platform_string() ); @@ -1215,7 +1214,7 @@ void VMError::report(outputStream* st, bool _verbose) { CompressedOops::print_mode(st); st->cr(); - STEP_IF("printing compressed klass pointers mode", _verbose && UseCompressedClassPointers) + STEP_IF("printing compressed klass pointers mode", _verbose) CDS_ONLY(AOTMetaspace::print_on(st);) Metaspace::print_compressed_class_space(st); CompressedKlassPointers::print_mode(st); @@ -1437,12 +1436,10 @@ void VMError::print_vm_info(outputStream* st) { #endif // STEP("printing compressed class ptrs mode") - if (UseCompressedClassPointers) { - CDS_ONLY(AOTMetaspace::print_on(st);) - Metaspace::print_compressed_class_space(st); - CompressedKlassPointers::print_mode(st); - st->cr(); - } + CDS_ONLY(AOTMetaspace::print_on(st);) + Metaspace::print_compressed_class_space(st); + CompressedKlassPointers::print_mode(st); + st->cr(); // Take heap lock over heap, GC and metaspace printing so that information // is consistent. diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Array.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Array.java index c4eeaf4a367..61067e63707 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Array.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Array.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -83,10 +83,8 @@ public class Array extends Oop { } if (VM.getVM().isCompactObjectHeadersEnabled()) { lengthOffsetInBytes = Oop.getHeaderSize(); - } else if (VM.getVM().isCompressedKlassPointersEnabled()) { - lengthOffsetInBytes = typeSize - VM.getVM().getIntSize(); } else { - lengthOffsetInBytes = typeSize; + lengthOffsetInBytes = typeSize - VM.getVM().getIntSize(); } return lengthOffsetInBytes; } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Instance.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Instance.java index 66efbe3484a..fea4fdaabc2 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Instance.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Instance.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * 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,10 +57,8 @@ public class Instance extends Oop { public static long getHeaderSize() { if (VM.getVM().isCompactObjectHeadersEnabled()) { return Oop.getHeaderSize(); - } else if (VM.getVM().isCompressedKlassPointersEnabled()) { - return typeSize - VM.getVM().getIntSize(); } else { - return typeSize; + return typeSize - VM.getVM().getIntSize(); } } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Oop.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Oop.java index 75ad4ab1d66..951499974fa 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Oop.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Oop.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * 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,7 @@ public class Oop { headerSize = markType.getSize(); } else { headerSize = type.getSize(); - klass = new MetadataField(type.getAddressField("_metadata._klass"), 0); - compressedKlass = new NarrowKlassField(type.getAddressField("_metadata._compressed_klass"), 0); + compressedKlass = new NarrowKlassField(type.getAddressField("_compressed_klass"), 0); } } @@ -75,7 +74,6 @@ public class Oop { public static long getHeaderSize() { return headerSize; } // Header size in bytes. private static CIntField mark; - private static MetadataField klass; private static NarrowKlassField compressedKlass; // Accessors for declared fields @@ -83,12 +81,9 @@ public class Oop { public Klass getKlass() { if (VM.getVM().isCompactObjectHeadersEnabled()) { - assert(VM.getVM().isCompressedKlassPointersEnabled()); return getMark().getKlass(); - } else if (VM.getVM().isCompressedKlassPointersEnabled()) { - return (Klass)compressedKlass.getValue(getHandle()); } else { - return (Klass)klass.getValue(getHandle()); + return (Klass)compressedKlass.getValue(getHandle()); } } @@ -157,11 +152,7 @@ public class Oop { if (doVMFields) { visitor.doCInt(mark, true); if (!VM.getVM().isCompactObjectHeadersEnabled()) { - if (VM.getVM().isCompressedKlassPointersEnabled()) { - visitor.doMetadata(compressedKlass, true); - } else { - visitor.doMetadata(klass, true); - } + visitor.doMetadata(compressedKlass, true); } } } @@ -220,10 +211,8 @@ public class Oop { if (VM.getVM().isCompactObjectHeadersEnabled()) { Mark mark = new Mark(handle); return mark.getKlass(); - } else if (VM.getVM().isCompressedKlassPointersEnabled()) { - return (Klass)Metadata.instantiateWrapperFor(handle.getCompKlassAddressAt(compressedKlass.getOffset())); } else { - return (Klass)Metadata.instantiateWrapperFor(handle.getAddressAt(klass.getOffset())); + return (Klass)Metadata.instantiateWrapperFor(handle.getCompKlassAddressAt(compressedKlass.getOffset())); } } }; 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 1607563150a..2ec96121934 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, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -144,7 +144,6 @@ public class VM { private static CIntegerType boolType; private Boolean sharingEnabled; private Boolean compressedOopsEnabled; - private Boolean compressedKlassPointersEnabled; private Boolean compactObjectHeadersEnabled; // command line flags supplied to VM - see struct JVMFlag in jvmFlag.hpp @@ -515,11 +514,7 @@ public class VM { heapOopSize = (int)getOopSize(); } - if (isCompressedKlassPointersEnabled()) { - klassPtrSize = (int)getIntSize(); - } else { - klassPtrSize = (int)getOopSize(); // same as an oop - } + klassPtrSize = (int)getIntSize(); } /** This could be used by a reflective runtime system */ @@ -938,15 +933,6 @@ public class VM { return compressedOopsEnabled.booleanValue(); } - public boolean isCompressedKlassPointersEnabled() { - if (compressedKlassPointersEnabled == null) { - Flag flag = getCommandLineFlag("UseCompressedClassPointers"); - compressedKlassPointersEnabled = (flag == null) ? Boolean.FALSE: - (flag.getBool()? Boolean.TRUE: Boolean.FALSE); - } - return compressedKlassPointersEnabled.booleanValue(); - } - public boolean isCompactObjectHeadersEnabled() { if (compactObjectHeadersEnabled == null) { Flag flag = getCommandLineFlag("UseCompactObjectHeaders"); diff --git a/test/hotspot/gtest/metaspace/test_is_metaspace_obj.cpp b/test/hotspot/gtest/metaspace/test_is_metaspace_obj.cpp index a35888c62e2..c1b4abfb355 100644 --- a/test/hotspot/gtest/metaspace/test_is_metaspace_obj.cpp +++ b/test/hotspot/gtest/metaspace/test_is_metaspace_obj.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2020 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -65,8 +65,8 @@ public: // Test VirtualSpaceList::contains const VirtualSpaceList* const vslist = - (mdType == Metaspace::ClassType && Metaspace::using_class_space()) ? - VirtualSpaceList::vslist_class() : VirtualSpaceList::vslist_nonclass(); + (mdType == Metaspace::ClassType && INCLUDE_CLASS_SPACE) ? + VirtualSpaceList::vslist_class() : VirtualSpaceList::vslist_nonclass(); ASSERT_TRUE(vslist->contains((MetaWord*)p)); diff --git a/test/hotspot/gtest/metaspace/test_metaspaceUtils.cpp b/test/hotspot/gtest/metaspace/test_metaspaceUtils.cpp index 49ab816c4a0..68deb283784 100644 --- a/test/hotspot/gtest/metaspace/test_metaspaceUtils.cpp +++ b/test/hotspot/gtest/metaspace/test_metaspaceUtils.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2020 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -37,15 +37,15 @@ TEST_VM(metaspace, MetaspaceUtils_reserved) { EXPECT_LE(reserved_metadata, reserved); } +#if INCLUDE_CLASS_SPACE TEST_VM(metaspace, MetaspaceUtils_reserved_compressed_class_pointers) { - if (UseCompressedClassPointers && CompressedKlassPointers::needs_class_space()) { - size_t reserved = MetaspaceUtils::reserved_bytes(); - EXPECT_GT(reserved, 0UL); - size_t reserved_class = MetaspaceUtils::reserved_bytes(Metaspace::ClassType); - EXPECT_GT(reserved_class, 0UL); - EXPECT_LE(reserved_class, reserved); - } + size_t reserved = MetaspaceUtils::reserved_bytes(); + EXPECT_GT(reserved, 0UL); + size_t reserved_class = MetaspaceUtils::reserved_bytes(Metaspace::ClassType); + EXPECT_GT(reserved_class, 0UL); + EXPECT_LE(reserved_class, reserved); } +#endif // INCLUDE_CLASS_SPACE TEST_VM(metaspace, MetaspaceUtils_committed) { size_t committed = MetaspaceUtils::committed_bytes(); @@ -59,30 +59,15 @@ TEST_VM(metaspace, MetaspaceUtils_committed) { EXPECT_LE(committed_metadata, committed); } +#if INCLUDE_CLASS_SPACE TEST_VM(metaspace, MetaspaceUtils_committed_compressed_class_pointers) { - if (UseCompressedClassPointers && CompressedKlassPointers::needs_class_space()) { - size_t committed = MetaspaceUtils::committed_bytes(); - EXPECT_GT(committed, 0UL); - size_t committed_class = MetaspaceUtils::committed_bytes(Metaspace::ClassType); - EXPECT_GT(committed_class, 0UL); - EXPECT_LE(committed_class, committed); - } -} - -TEST_VM(metaspace, MetaspaceUtils_non_compressed_class_pointers) { - if (UseCompressedClassPointers) { - return; - } - + size_t committed = MetaspaceUtils::committed_bytes(); + EXPECT_GT(committed, 0UL); size_t committed_class = MetaspaceUtils::committed_bytes(Metaspace::ClassType); - EXPECT_EQ(committed_class, 0UL); - - size_t used_class = MetaspaceUtils::used_bytes(Metaspace::ClassType); - EXPECT_EQ(used_class, 0UL); - - size_t reserved_class = MetaspaceUtils::reserved_bytes(Metaspace::ClassType); - EXPECT_EQ(reserved_class, 0UL); + EXPECT_GT(committed_class, 0UL); + EXPECT_LE(committed_class, committed); } +#endif // INCLUDE_CLASS_SPACE static void check_metaspace_stats_are_consistent(const MetaspaceStats& stats) { EXPECT_LE(stats.committed(), stats.reserved()); @@ -102,13 +87,13 @@ TEST_VM(MetaspaceUtils, MetaspaceUtils_get_statistics) { check_metaspace_stats_are_not_null(combined_stats.non_class_space_stats()); check_metaspace_stats_are_consistent(combined_stats.non_class_space_stats()); - if (CompressedKlassPointers::needs_class_space() && UseCompressedClassPointers) { - check_metaspace_stats_are_not_null(combined_stats.class_space_stats()); - check_metaspace_stats_are_consistent(combined_stats.class_space_stats()); - } else { - // if we don't have a class space, combined stats should equal non-class stats - EXPECT_EQ(combined_stats.non_class_space_stats().reserved(), combined_stats.reserved()); - EXPECT_EQ(combined_stats.non_class_space_stats().committed(), combined_stats.committed()); - EXPECT_EQ(combined_stats.non_class_space_stats().used(), combined_stats.used()); - } +#if INCLUDE_CLASS_SPACE + check_metaspace_stats_are_not_null(combined_stats.class_space_stats()); + check_metaspace_stats_are_consistent(combined_stats.class_space_stats()); +#else + // if we don't have a class space, combined stats should equal non-class stats + EXPECT_EQ(combined_stats.non_class_space_stats().reserved(), combined_stats.reserved()); + EXPECT_EQ(combined_stats.non_class_space_stats().committed(), combined_stats.committed()); + EXPECT_EQ(combined_stats.non_class_space_stats().used(), combined_stats.used()); +#endif // INCLUDE_CLASS_SPACE } diff --git a/test/hotspot/gtest/oops/test_arrayOop.cpp b/test/hotspot/gtest/oops/test_arrayOop.cpp index 33163de427c..bb5f54b3f58 100644 --- a/test/hotspot/gtest/oops/test_arrayOop.cpp +++ b/test/hotspot/gtest/oops/test_arrayOop.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -97,7 +97,7 @@ TEST_VM(arrayOopDesc, base_offset) { EXPECT_EQ(arrayOopDesc::base_offset_in_bytes(T_OBJECT), 16); EXPECT_EQ(arrayOopDesc::base_offset_in_bytes(T_ARRAY), 16); } - } else if (UseCompressedClassPointers) { + } else { EXPECT_EQ(arrayOopDesc::base_offset_in_bytes(T_BOOLEAN), 16); EXPECT_EQ(arrayOopDesc::base_offset_in_bytes(T_BYTE), 16); EXPECT_EQ(arrayOopDesc::base_offset_in_bytes(T_SHORT), 16); @@ -108,22 +108,6 @@ TEST_VM(arrayOopDesc, base_offset) { EXPECT_EQ(arrayOopDesc::base_offset_in_bytes(T_DOUBLE), 16); EXPECT_EQ(arrayOopDesc::base_offset_in_bytes(T_OBJECT), 16); EXPECT_EQ(arrayOopDesc::base_offset_in_bytes(T_ARRAY), 16); - } else { - EXPECT_EQ(arrayOopDesc::base_offset_in_bytes(T_BOOLEAN), 20); - EXPECT_EQ(arrayOopDesc::base_offset_in_bytes(T_BYTE), 20); - EXPECT_EQ(arrayOopDesc::base_offset_in_bytes(T_SHORT), 20); - EXPECT_EQ(arrayOopDesc::base_offset_in_bytes(T_CHAR), 20); - EXPECT_EQ(arrayOopDesc::base_offset_in_bytes(T_INT), 20); - EXPECT_EQ(arrayOopDesc::base_offset_in_bytes(T_FLOAT), 20); - EXPECT_EQ(arrayOopDesc::base_offset_in_bytes(T_LONG), 24); - EXPECT_EQ(arrayOopDesc::base_offset_in_bytes(T_DOUBLE), 24); - if (UseCompressedOops) { - EXPECT_EQ(arrayOopDesc::base_offset_in_bytes(T_OBJECT), 20); - EXPECT_EQ(arrayOopDesc::base_offset_in_bytes(T_ARRAY), 20); - } else { - EXPECT_EQ(arrayOopDesc::base_offset_in_bytes(T_OBJECT), 24); - EXPECT_EQ(arrayOopDesc::base_offset_in_bytes(T_ARRAY), 24); - } } #else EXPECT_EQ(arrayOopDesc::base_offset_in_bytes(T_BOOLEAN), 12); diff --git a/test/hotspot/gtest/oops/test_compressedKlass.cpp b/test/hotspot/gtest/oops/test_compressedKlass.cpp index dcdb335adb5..5a7323edc03 100644 --- a/test/hotspot/gtest/oops/test_compressedKlass.cpp +++ b/test/hotspot/gtest/oops/test_compressedKlass.cpp @@ -29,9 +29,6 @@ #include "unittest.hpp" TEST_VM(CompressedKlass, basics) { - if (!UseCompressedClassPointers) { - return; - } ASSERT_LE(CompressedKlassPointers::base(), CompressedKlassPointers::klass_range_start()); ASSERT_LT(CompressedKlassPointers::klass_range_start(), CompressedKlassPointers::klass_range_end()); ASSERT_LE(CompressedKlassPointers::klass_range_end(), CompressedKlassPointers::encoding_range_end()); @@ -54,22 +51,7 @@ TEST_VM(CompressedKlass, basics) { #endif // _LP64 } -TEST_VM(CompressedKlass, ccp_off) { - if (UseCompressedClassPointers) { - return; - } - ASSERT_EQ(CompressedKlassPointers::klass_range_start(), (address)nullptr); - ASSERT_EQ(CompressedKlassPointers::klass_range_end(), (address)nullptr); - // We should be able to call CompressedKlassPointers::is_encodable, and it should - // always return false - ASSERT_FALSE(CompressedKlassPointers::is_encodable((address)0x12345)); -} - - TEST_VM(CompressedKlass, test_too_low_address) { - if (!UseCompressedClassPointers) { - return; - } address really_low = (address) 32; ASSERT_FALSE(CompressedKlassPointers::is_encodable(really_low)); address low = CompressedKlassPointers::klass_range_start() - 1; @@ -77,9 +59,6 @@ TEST_VM(CompressedKlass, test_too_low_address) { } TEST_VM(CompressedKlass, test_too_high_address) { - if (!UseCompressedClassPointers) { - return; - } address really_high = (address) UINTPTR_MAX; ASSERT_FALSE(CompressedKlassPointers::is_encodable(really_high)); address high = CompressedKlassPointers::klass_range_end(); @@ -87,9 +66,6 @@ TEST_VM(CompressedKlass, test_too_high_address) { } TEST_VM(CompressedKlass, test_unaligned_address) { - if (!UseCompressedClassPointers) { - return; - } const size_t alignment = CompressedKlassPointers::klass_alignment_in_bytes(); address addr = CompressedKlassPointers::klass_range_start() + alignment - 1; ASSERT_FALSE(CompressedKlassPointers::is_encodable(addr)); @@ -103,9 +79,6 @@ TEST_VM(CompressedKlass, test_unaligned_address) { } TEST_VM(CompressedKlass, test_good_address) { - if (!UseCompressedClassPointers) { - return; - } const size_t alignment = CompressedKlassPointers::klass_alignment_in_bytes(); address addr = CompressedKlassPointers::klass_range_start(); ASSERT_TRUE(CompressedKlassPointers::is_encodable(addr)); @@ -114,9 +87,6 @@ TEST_VM(CompressedKlass, test_good_address) { } TEST_VM(CompressedKlass, test_is_valid_narrow_klass) { - if (!UseCompressedClassPointers) { - return; - } ASSERT_FALSE(CompressedKlassPointers::is_valid_narrow_klass_id(0)); narrowKlass nk_jlC = CompressedKlassPointers::encode((Klass*)vmClasses::Class_klass()); ASSERT_TRUE(CompressedKlassPointers::is_valid_narrow_klass_id(nk_jlC)); diff --git a/test/hotspot/gtest/oops/test_objArrayOop.cpp b/test/hotspot/gtest/oops/test_objArrayOop.cpp index 22c9b2efc11..f6a53a3031f 100644 --- a/test/hotspot/gtest/oops/test_objArrayOop.cpp +++ b/test/hotspot/gtest/oops/test_objArrayOop.cpp @@ -27,35 +27,29 @@ TEST_VM(objArrayOop, osize) { static const struct { - int objal; bool ccp; bool coops; bool coh; int result; + int objal; bool coops; bool coh; int result; } x[] = { -// ObjAligInB, UseCCP, UseCoops, UseCOH, object size in heap words +// ObjAligInB, UseCoops, UseCOH, object size in heap words #ifdef _LP64 - { 8, false, false, false, 4 }, // 20 byte header, 8 byte oops - { 8, false, true, false, 3 }, // 20 byte header, 4 byte oops - { 8, true, false, false, 3 }, // 16 byte header, 8 byte oops - { 8, true, true, false, 3 }, // 16 byte header, 4 byte oops - { 8, true, false, true, 3 }, // 12 byte header, 8 byte oops - { 8, true, true, true, 2 }, // 12 byte header, 4 byte oops - { 16, false, false, false, 4 }, // 20 byte header, 8 byte oops, 16-byte align - { 16, false, true, false, 4 }, // 20 byte header, 4 byte oops, 16-byte align - { 16, true, false, false, 4 }, // 16 byte header, 8 byte oops, 16-byte align - { 16, true, true, false, 4 }, // 16 byte header, 4 byte oops, 16-byte align - { 16, true, false, true, 4 }, // 12 byte header, 8 byte oops, 16-byte align - { 16, true, true, true, 2 }, // 12 byte header, 4 byte oops, 16-byte align - { 256, false, false, false, 32 }, // 20 byte header, 8 byte oops, 256-byte align - { 256, false, true, false, 32 }, // 20 byte header, 4 byte oops, 256-byte align - { 256, true, false, false, 32 }, // 16 byte header, 8 byte oops, 256-byte align - { 256, true, true, false, 32 }, // 16 byte header, 4 byte oops, 256-byte align - { 256, true, false, true, 32 }, // 12 byte header, 8 byte oops, 256-byte align - { 256, true, true, true, 32 }, // 12 byte header, 4 byte oops, 256-byte align + { 8, false, false, 3 }, // 16 byte header, 8 byte oops + { 8, true, false, 3 }, // 16 byte header, 4 byte oops + { 8, false, true, 3 }, // 12 byte header, 8 byte oops + { 8, true, true, 2 }, // 12 byte header, 4 byte oops + { 16, false, false, 4 }, // 16 byte header, 8 byte oops, 16-byte align + { 16, true, false, 4 }, // 16 byte header, 4 byte oops, 16-byte align + { 16, false, true, 4 }, // 12 byte header, 8 byte oops, 16-byte align + { 16, true, true, 2 }, // 12 byte header, 4 byte oops, 16-byte align + { 256, false, false, 32 }, // 16 byte header, 8 byte oops, 256-byte align + { 256, true, false, 32 }, // 16 byte header, 4 byte oops, 256-byte align + { 256, false, true, 32 }, // 12 byte header, 8 byte oops, 256-byte align + { 256, true, true, 32 }, // 12 byte header, 4 byte oops, 256-byte align #else - { 8, false, false, false, 4 }, // 12 byte header, 4 byte oops, wordsize 4 + { 8, false, false, 4 }, // 12 byte header, 4 byte oops, wordsize 4 #endif - { -1, false, false, false, -1 } + { -1, false, false, -1 } }; for (int i = 0; x[i].result != -1; i++) { - if (x[i].objal == (int)ObjectAlignmentInBytes && x[i].ccp == UseCompressedClassPointers && x[i].coops == UseCompressedOops && + if (x[i].objal == (int)ObjectAlignmentInBytes && x[i].coops == UseCompressedOops && x[i].coh == UseCompactObjectHeaders) { EXPECT_EQ(objArrayOopDesc::object_size(1), (size_t)x[i].result); } diff --git a/test/hotspot/jtreg/compiler/arraycopy/TestObjectArrayClone.java b/test/hotspot/jtreg/compiler/arraycopy/TestObjectArrayClone.java index b7e5b135c64..595205055ee 100644 --- a/test/hotspot/jtreg/compiler/arraycopy/TestObjectArrayClone.java +++ b/test/hotspot/jtreg/compiler/arraycopy/TestObjectArrayClone.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * 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,10 +34,6 @@ * @run main/othervm -XX:CompileCommand=compileonly,compiler.arraycopy.TestObjectArrayClone::testClone* * -XX:CompileCommand=compileonly,jdk.internal.reflect.GeneratedMethodAccessor*::invoke * compiler.arraycopy.TestObjectArrayClone - * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-UseCompressedClassPointers -Xmx128m - * -XX:CompileCommand=compileonly,compiler.arraycopy.TestObjectArrayClone::testClone* - * -XX:CompileCommand=compileonly,jdk.internal.reflect.GeneratedMethodAccessor*::invoke - * compiler.arraycopy.TestObjectArrayClone * @run main/othervm -Xbatch -XX:-UseTypeProfile * -XX:CompileCommand=compileonly,compiler.arraycopy.TestObjectArrayClone::testClone* * -XX:CompileCommand=compileonly,jdk.internal.reflect.GeneratedMethodAccessor*::invoke diff --git a/test/hotspot/jtreg/compiler/c1/TestArrayCopyToFromObject.java b/test/hotspot/jtreg/compiler/c1/TestArrayCopyToFromObject.java index 98c8c24dd3a..176226806a6 100644 --- a/test/hotspot/jtreg/compiler/c1/TestArrayCopyToFromObject.java +++ b/test/hotspot/jtreg/compiler/c1/TestArrayCopyToFromObject.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,8 +25,7 @@ * @test * @bug 8160591 * @summary C1-generated code for System.arraycopy() does not throw an ArrayStoreException if 'dst' is no a "proper" array (i.e., it is java.lang.Object) - * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+TieredCompilation -XX:TieredStopAtLevel=1 -Xcomp -XX:-UseCompressedClassPointers -XX:CompileOnly=TestArrayCopyToFromObject::test TestArrayCopyToFromObject - * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+TieredCompilation -XX:TieredStopAtLevel=1 -Xcomp -XX:+UseCompressedClassPointers -XX:CompileOnly=TestArrayCopyToFromObject::test TestArrayCopyToFromObject + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+TieredCompilation -XX:TieredStopAtLevel=1 -Xcomp -XX:CompileOnly=TestArrayCopyToFromObject::test TestArrayCopyToFromObject */ public class TestArrayCopyToFromObject { diff --git a/test/hotspot/jtreg/compiler/c2/TestReduceAllocationAndLoadKlass.java b/test/hotspot/jtreg/compiler/c2/TestReduceAllocationAndLoadKlass.java deleted file mode 100644 index a8997535aae..00000000000 --- a/test/hotspot/jtreg/compiler/c2/TestReduceAllocationAndLoadKlass.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test - * @bug 8330795 - * @summary Check that Reduce Allocation Merges doesn't crash when CompressedClassPointers - * is disabled and there is an access to Klass "field" through the phi. - * @requires vm.bits == 64 & vm.flagless & vm.compiler2.enabled & vm.opt.final.EliminateAllocations - * @run main/othervm -XX:CompileCommand=dontinline,*TestReduceAllocationAndLoadKlass*::test - * -XX:CompileCommand=compileonly,*TestReduceAllocationAndLoadKlass*::test - * -XX:CompileCommand=compileonly,*Shape*::*init* - * -XX:CompileCommand=compileonly,*Point*::*init* - * -XX:CompileCommand=exclude,*TestReduceAllocationAndLoadKlass*::dummy - * -XX:-TieredCompilation - * -XX:-UseCompressedClassPointers - * -Xbatch - * -Xcomp - * compiler.c2.TestReduceAllocationAndLoadKlass - */ - -package compiler.c2; - -public class TestReduceAllocationAndLoadKlass { - public static void main(String[] args) { - Point p = new Point(); - Line q = new Line(); - - test(true); - test(false); - } - - static Class test(boolean cond) { - Object p = cond ? dummy() : new Line(); - return p.getClass(); - } - - static Point dummy() { return new Point(); } - - static class Shape { } - static class Point extends Shape { } - static class Line extends Shape { } -} diff --git a/test/hotspot/jtreg/compiler/c2/irTests/scalarReplacement/AllocationMergesTests.java b/test/hotspot/jtreg/compiler/c2/irTests/scalarReplacement/AllocationMergesTests.java index 24065bd97b9..2c84ad2676e 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/scalarReplacement/AllocationMergesTests.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/scalarReplacement/AllocationMergesTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * 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,26 +46,13 @@ public class AllocationMergesTests { "-XX:+TraceReduceAllocationMerges", "-XX:+DeoptimizeALot", "-XX:+UseCompressedOops", - "-XX:+UseCompressedClassPointers", "-XX:CompileCommand=inline,*::charAt*", "-XX:CompileCommand=inline,*PicturePositions::*", "-XX:CompileCommand=inline,*Point::*", "-XX:CompileCommand=inline,*Nested::*", "-XX:CompileCommand=exclude,*::dummy*"); - Scenario scenario1 = new Scenario(1, "-XX:+UnlockDiagnosticVMOptions", - "-XX:+ReduceAllocationMerges", - "-XX:+TraceReduceAllocationMerges", - "-XX:+DeoptimizeALot", - "-XX:+UseCompressedOops", - "-XX:-UseCompressedClassPointers", - "-XX:CompileCommand=inline,*::charAt*", - "-XX:CompileCommand=inline,*PicturePositions::*", - "-XX:CompileCommand=inline,*Point::*", - "-XX:CompileCommand=inline,*Nested::*", - "-XX:CompileCommand=exclude,*::dummy*"); - - Scenario scenario2 = new Scenario(2, "-XX:+UnlockDiagnosticVMOptions", + Scenario scenario1 = new Scenario(2, "-XX:+UnlockDiagnosticVMOptions", "-XX:+ReduceAllocationMerges", "-XX:+TraceReduceAllocationMerges", "-XX:+DeoptimizeALot", @@ -76,12 +63,11 @@ public class AllocationMergesTests { "-XX:CompileCommand=inline,*Nested::*", "-XX:CompileCommand=exclude,*::dummy*"); - Scenario scenario3 = new Scenario(3, "-XX:+UnlockDiagnosticVMOptions", + Scenario scenario2 = new Scenario(3, "-XX:+UnlockDiagnosticVMOptions", "-XX:+ReduceAllocationMerges", "-XX:+TraceReduceAllocationMerges", "-XX:+DeoptimizeALot", "-XX:+UseCompressedOops", - "-XX:+UseCompressedClassPointers", "-XX:-OptimizePtrCompare", "-XX:+VerifyReduceAllocationMerges", "-XX:CompileCommand=inline,*::charAt*", @@ -90,7 +76,7 @@ public class AllocationMergesTests { "-XX:CompileCommand=inline,*Nested::*", "-XX:CompileCommand=exclude,*::dummy*"); - framework.addScenarios(scenario0, scenario1, scenario2, scenario3).start(); + framework.addScenarios(scenario0, scenario1, scenario2).start(); } // ------------------ No Scalar Replacement Should Happen in The Tests Below ------------------- // diff --git a/test/hotspot/jtreg/compiler/jvmci/compilerToVM/GetResolvedJavaTypeTest.java b/test/hotspot/jtreg/compiler/jvmci/compilerToVM/GetResolvedJavaTypeTest.java index e0302e7b5aa..1e2e2d50232 100644 --- a/test/hotspot/jtreg/compiler/jvmci/compilerToVM/GetResolvedJavaTypeTest.java +++ b/test/hotspot/jtreg/compiler/jvmci/compilerToVM/GetResolvedJavaTypeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -159,7 +159,6 @@ public class GetResolvedJavaTypeTest { /* a compressed parameter for tested method is set to false because unsafe.getKlassPointer always returns uncompressed pointer */ private static final boolean COMPRESSED = false; - // = WB.getBooleanVMFlag("UseCompressedClassPointers"); private static long getPtrToKlass() { Field field; diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/DataPatchTest.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/DataPatchTest.java index adbad3e0b4d..b0c7d11edfe 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/DataPatchTest.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/DataPatchTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -119,7 +119,6 @@ public class DataPatchTest extends CodeInstallationTest { @Test public void testInlineNarrowMetadata() { - Assume.assumeTrue(config.useCompressedClassPointers); test(asm -> { ResolvedJavaType type = metaAccess.lookupJavaType(getConstClass()); HotSpotConstant hub = (HotSpotConstant) constantReflection.asObjectHub(type); @@ -144,7 +143,6 @@ public class DataPatchTest extends CodeInstallationTest { @Test public void testNarrowMetadataInDataSection() { - Assume.assumeTrue(config.useCompressedClassPointers); test(asm -> { ResolvedJavaType type = metaAccess.lookupJavaType(getConstClass()); HotSpotConstant hub = (HotSpotConstant) constantReflection.asObjectHub(type); diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/TestHotSpotVMConfig.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/TestHotSpotVMConfig.java index a26872b96ae..4b0065d0e70 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/TestHotSpotVMConfig.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/TestHotSpotVMConfig.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 @@ public class TestHotSpotVMConfig extends HotSpotVMConfigAccess { } public final boolean useCompressedOops = getFlag("UseCompressedOops", Boolean.class); - public final boolean useCompressedClassPointers = getFlag("UseCompressedClassPointers", Boolean.class); public final long narrowOopBase = getFieldValue("CompilerToVM::Data::Universe_narrow_oop_base", Long.class, "address"); public final int narrowOopShift = getFieldValue("CompilerToVM::Data::Universe_narrow_oop_shift", Integer.class, "int"); diff --git a/test/hotspot/jtreg/compiler/types/TestCheckCastPPBecomesTOP.java b/test/hotspot/jtreg/compiler/types/TestCheckCastPPBecomesTOP.java index 5c57e479307..38ab9121b47 100644 --- a/test/hotspot/jtreg/compiler/types/TestCheckCastPPBecomesTOP.java +++ b/test/hotspot/jtreg/compiler/types/TestCheckCastPPBecomesTOP.java @@ -30,9 +30,6 @@ * @run main/othervm -XX:-TieredCompilation -XX:-UseOnStackReplacement -XX:-BackgroundCompilation * -XX:CompileOnly=TestCheckCastPPBecomesTOP::test1 -XX:LoopMaxUnroll=0 * -XX:CompileCommand=dontinline,TestCheckCastPPBecomesTOP::notInlined -XX:+UseParallelGC TestCheckCastPPBecomesTOP - * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-TieredCompilation -XX:-UseOnStackReplacement -XX:-BackgroundCompilation - * -XX:CompileOnly=TestCheckCastPPBecomesTOP::test1 -XX:LoopMaxUnroll=0 - * -XX:CompileCommand=dontinline,TestCheckCastPPBecomesTOP::notInlined -XX:+UseParallelGC -XX:-UseCompressedClassPointers TestCheckCastPPBecomesTOP * */ diff --git a/test/hotspot/jtreg/compiler/unsafe/OpaqueAccesses.java b/test/hotspot/jtreg/compiler/unsafe/OpaqueAccesses.java index 9a31cbbb057..00c3ce5fb7f 100644 --- a/test/hotspot/jtreg/compiler/unsafe/OpaqueAccesses.java +++ b/test/hotspot/jtreg/compiler/unsafe/OpaqueAccesses.java @@ -247,28 +247,14 @@ public class OpaqueAccesses { "--add-exports=java.base/jdk.internal.misc=ALL-UNNAMED", "-XX:+IgnoreUnrecognizedVMOptions", "-XX:+UnlockDiagnosticVMOptions", "-XX:-TieredCompilation", "-Xbatch", - "-XX:+UseCompressedOops", "-XX:+UseCompressedClassPointers", + "-XX:+UseCompressedOops", "-XX:CompileCommand=dontinline,compiler.unsafe.OpaqueAccesses::test*" ); TestFramework.runWithFlags( "--add-exports=java.base/jdk.internal.misc=ALL-UNNAMED", "-XX:+IgnoreUnrecognizedVMOptions", "-XX:+UnlockDiagnosticVMOptions", "-XX:-TieredCompilation", "-Xbatch", - "-XX:+UseCompressedOops", "-XX:-UseCompressedClassPointers", - "-XX:CompileCommand=dontinline,compiler.unsafe.OpaqueAccesses::test*" - ); - TestFramework.runWithFlags( - "--add-exports=java.base/jdk.internal.misc=ALL-UNNAMED", - "-XX:+IgnoreUnrecognizedVMOptions", "-XX:+UnlockDiagnosticVMOptions", - "-XX:-TieredCompilation", "-Xbatch", - "-XX:-UseCompressedOops", "-XX:+UseCompressedClassPointers", - "-XX:CompileCommand=dontinline,compiler.unsafe.OpaqueAccesses::test*" - ); - TestFramework.runWithFlags( - "--add-exports=java.base/jdk.internal.misc=ALL-UNNAMED", - "-XX:+IgnoreUnrecognizedVMOptions", "-XX:+UnlockDiagnosticVMOptions", - "-XX:-TieredCompilation", "-Xbatch", - "-XX:-UseCompressedOops", "-XX:-UseCompressedClassPointers", + "-XX:-UseCompressedOops", "-XX:CompileCommand=dontinline,compiler.unsafe.OpaqueAccesses::test*" ); } diff --git a/test/hotspot/jtreg/gc/arguments/TestCompressedClassFlags.java b/test/hotspot/jtreg/gc/arguments/TestCompressedClassFlags.java deleted file mode 100644 index b152fc8c936..00000000000 --- a/test/hotspot/jtreg/gc/arguments/TestCompressedClassFlags.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2013, 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.arguments; - -import jdk.test.lib.process.OutputAnalyzer; -import jdk.test.lib.Platform; - -/* - * @test - * @bug 8015107 - * @summary Tests that VM prints a warning when -XX:CompressedClassSpaceSize - * is used together with -XX:-UseCompressedClassPointers - * @library /test/lib - * @library / - * @modules java.base/jdk.internal.misc - * java.management - * @requires vm.opt.CompressedClassSpaceSize == null & vm.opt.UseCompressedClassPointers == null - * @run driver gc.arguments.TestCompressedClassFlags - */ -public class TestCompressedClassFlags { - public static void main(String[] args) throws Exception { - if (Platform.is64bit()) { - OutputAnalyzer output = GCArguments.executeTestJava( - "-XX:CompressedClassSpaceSize=1g", - "-XX:-UseCompressedClassPointers", - "-version"); - output.shouldContain("warning"); - output.shouldNotContain("error"); - output.shouldHaveExitValue(0); - } - } -} diff --git a/test/hotspot/jtreg/gc/g1/TestSharedArchiveWithPreTouch.java b/test/hotspot/jtreg/gc/g1/TestSharedArchiveWithPreTouch.java index 1156a2166c1..bba3c850213 100644 --- a/test/hotspot/jtreg/gc/g1/TestSharedArchiveWithPreTouch.java +++ b/test/hotspot/jtreg/gc/g1/TestSharedArchiveWithPreTouch.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -53,7 +53,7 @@ public class TestSharedArchiveWithPreTouch { List dump_args = new ArrayList(BaseOptions); if (Platform.is64bit()) { - dump_args.addAll(0, Arrays.asList(new String[] { "-XX:+UseCompressedClassPointers", "-XX:+UseCompressedOops" })); + dump_args.addFirst("-XX:+UseCompressedOops" ); } dump_args.addAll(Arrays.asList(new String[] { "-Xshare:dump", "-Xlog:cds" })); @@ -66,7 +66,7 @@ public class TestSharedArchiveWithPreTouch { List load_args = new ArrayList(BaseOptions); if (Platform.is64bit()) { - load_args.addAll(0, Arrays.asList(new String[] { "-XX:+UseCompressedClassPointers", "-XX:+UseCompressedOops" })); + load_args.addFirst("-XX:+UseCompressedOops" ); } load_args.addAll(Arrays.asList(new String[] { "-Xshare:on", "-version" })); diff --git a/test/hotspot/jtreg/gc/metaspace/TestMetaspaceMemoryPool.java b/test/hotspot/jtreg/gc/metaspace/TestMetaspaceMemoryPool.java index 71cf2003ddd..2f4ce3df8b2 100644 --- a/test/hotspot/jtreg/gc/metaspace/TestMetaspaceMemoryPool.java +++ b/test/hotspot/jtreg/gc/metaspace/TestMetaspaceMemoryPool.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2026, Oracle and/or its affiliates. All rights reserved. * 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,10 +37,9 @@ import static jdk.test.lib.Asserts.*; * @library / * @modules java.base/jdk.internal.misc * java.management - * @run main/othervm -XX:-UseCompressedOops gc.metaspace.TestMetaspaceMemoryPool - * @run main/othervm -XX:-UseCompressedOops -XX:MaxMetaspaceSize=60m gc.metaspace.TestMetaspaceMemoryPool - * @run main/othervm -XX:+UseCompressedOops -XX:+UseCompressedClassPointers gc.metaspace.TestMetaspaceMemoryPool - * @run main/othervm -XX:+UseCompressedOops -XX:+UseCompressedClassPointers -XX:CompressedClassSpaceSize=60m gc.metaspace.TestMetaspaceMemoryPool + * @run main/othervm gc.metaspace.TestMetaspaceMemoryPool + * @run main/othervm -XX:MaxMetaspaceSize=60m gc.metaspace.TestMetaspaceMemoryPool + * @run main/othervm -XX:CompressedClassSpaceSize=60m gc.metaspace.TestMetaspaceMemoryPool */ public class TestMetaspaceMemoryPool { @@ -51,10 +50,8 @@ public class TestMetaspaceMemoryPool { verifyMemoryPool(getMemoryPool("Metaspace"), isMetaspaceMaxDefined); if (Platform.is64bit()) { - if (InputArguments.contains("-XX:+UseCompressedOops")) { - MemoryPoolMXBean cksPool = getMemoryPool("Compressed Class Space"); - verifyMemoryPool(cksPool, true); - } + MemoryPoolMXBean cksPool = getMemoryPool("Compressed Class Space"); + verifyMemoryPool(cksPool, true); } } diff --git a/test/hotspot/jtreg/gc/metaspace/TestMetaspacePerfCounters.java b/test/hotspot/jtreg/gc/metaspace/TestMetaspacePerfCounters.java index b0f779109e1..5ead40c9068 100644 --- a/test/hotspot/jtreg/gc/metaspace/TestMetaspacePerfCounters.java +++ b/test/hotspot/jtreg/gc/metaspace/TestMetaspacePerfCounters.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2026, Oracle and/or its affiliates. All rights reserved. * 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,8 +48,7 @@ import gc.testlibrary.PerfCounters; * java.compiler * java.management/sun.management * jdk.internal.jvmstat/sun.jvmstat.monitor - * @run main/othervm -XX:-UseCompressedOops -XX:-UseCompressedClassPointers -XX:+UsePerfData -XX:+UseSerialGC gc.metaspace.TestMetaspacePerfCounters - * @run main/othervm -XX:+UseCompressedOops -XX:+UseCompressedClassPointers -XX:+UsePerfData -XX:+UseSerialGC gc.metaspace.TestMetaspacePerfCounters + * @run main/othervm -XX:+UseCompressedOops -XX:+UsePerfData -XX:+UseSerialGC gc.metaspace.TestMetaspacePerfCounters */ /* @test id=Parallel-64 @@ -63,8 +62,7 @@ import gc.testlibrary.PerfCounters; * java.compiler * java.management/sun.management * jdk.internal.jvmstat/sun.jvmstat.monitor - * @run main/othervm -XX:-UseCompressedOops -XX:-UseCompressedClassPointers -XX:+UsePerfData -XX:+UseParallelGC gc.metaspace.TestMetaspacePerfCounters - * @run main/othervm -XX:+UseCompressedOops -XX:+UseCompressedClassPointers -XX:+UsePerfData -XX:+UseParallelGC gc.metaspace.TestMetaspacePerfCounters + * @run main/othervm -XX:+UseCompressedOops -XX:+UsePerfData -XX:+UseParallelGC gc.metaspace.TestMetaspacePerfCounters */ /* @test id=G1-64 @@ -78,8 +76,7 @@ import gc.testlibrary.PerfCounters; * java.compiler * java.management/sun.management * jdk.internal.jvmstat/sun.jvmstat.monitor - * @run main/othervm -XX:-UseCompressedOops -XX:-UseCompressedClassPointers -XX:+UsePerfData -XX:+UseG1GC gc.metaspace.TestMetaspacePerfCounters - * @run main/othervm -XX:+UseCompressedOops -XX:+UseCompressedClassPointers -XX:+UsePerfData -XX:+UseG1GC gc.metaspace.TestMetaspacePerfCounters + * @run main/othervm -XX:+UseCompressedOops -XX:+UsePerfData -XX:+UseG1GC gc.metaspace.TestMetaspacePerfCounters */ /* @test id=Shenandoah-64 @@ -93,8 +90,7 @@ import gc.testlibrary.PerfCounters; * java.compiler * java.management/sun.management * jdk.internal.jvmstat/sun.jvmstat.monitor - * @run main/othervm -XX:-UseCompressedOops -XX:-UseCompressedClassPointers -XX:+UsePerfData -XX:+UseShenandoahGC gc.metaspace.TestMetaspacePerfCounters - * @run main/othervm -XX:+UseCompressedOops -XX:+UseCompressedClassPointers -XX:+UsePerfData -XX:+UseShenandoahGC gc.metaspace.TestMetaspacePerfCounters + * @run main/othervm -XX:+UseCompressedOops -XX:+UsePerfData -XX:+UseShenandoahGC gc.metaspace.TestMetaspacePerfCounters */ /* @test id=Epsilon-64 @@ -108,8 +104,7 @@ import gc.testlibrary.PerfCounters; * java.compiler * java.management/sun.management * jdk.internal.jvmstat/sun.jvmstat.monitor - * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:-UseCompressedOops -XX:-UseCompressedClassPointers -XX:+UsePerfData -XX:+UseEpsilonGC gc.metaspace.TestMetaspacePerfCounters - * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseCompressedOops -XX:+UseCompressedClassPointers -XX:+UsePerfData -XX:+UseEpsilonGC gc.metaspace.TestMetaspacePerfCounters + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseCompressedOops -XX:+UsePerfData -XX:+UseEpsilonGC gc.metaspace.TestMetaspacePerfCounters */ /* @test id=Serial-32 @@ -227,14 +222,8 @@ public class TestMetaspacePerfCounters { String ccs = "sun.gc.compressedclassspace"; checkPerfCounters(metaspace); - - if (isUsingCompressedClassPointers()) { - checkPerfCounters(ccs); - checkUsedIncreasesWhenLoadingClass(ccs); - } else { - checkEmptyPerfCounters(ccs); - checkUsedIncreasesWhenLoadingClass(metaspace); - } + checkPerfCounters(ccs); + checkUsedIncreasesWhenLoadingClass(ccs); } private static void checkPerfCounters(String ns) throws Exception { @@ -262,13 +251,6 @@ public class TestMetaspacePerfCounters { assertGTE(snap1.maxCapacity, snap1.capacity); } - private static void checkEmptyPerfCounters(String ns) throws Exception { - for (PerfCounter counter : countersInNamespace(ns)) { - String msg = "Expected " + counter.getName() + " to equal 0"; - assertEQ(counter.longValue(), 0L, msg); - } - } - private static void checkUsedIncreasesWhenLoadingClass(String ns) throws Exception { // Need to ensure that used is up to date and that all unreachable // classes are unloaded before doing this check. @@ -296,7 +278,4 @@ public class TestMetaspacePerfCounters { return ByteCodeLoader.load(name, byteCode); } - private static boolean isUsingCompressedClassPointers() { - return Platform.is64bit() && InputArguments.contains("-XX:+UseCompressedClassPointers"); - } } diff --git a/test/hotspot/jtreg/gc/metaspace/TestPerfCountersAndMemoryPools.java b/test/hotspot/jtreg/gc/metaspace/TestPerfCountersAndMemoryPools.java index fb32c439940..6d5cdf181b9 100644 --- a/test/hotspot/jtreg/gc/metaspace/TestPerfCountersAndMemoryPools.java +++ b/test/hotspot/jtreg/gc/metaspace/TestPerfCountersAndMemoryPools.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2026, Oracle and/or its affiliates. All rights reserved. * 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,7 @@ import gc.testlibrary.PerfCounters; * @modules java.base/jdk.internal.misc * java.management * jdk.internal.jvmstat/sun.jvmstat.monitor - * @run main/othervm -Xlog:class+load,class+unload=trace -XX:-UseCompressedOops -XX:-UseCompressedClassPointers -XX:+UseSerialGC -XX:+UsePerfData -Xint gc.metaspace.TestPerfCountersAndMemoryPools - * @run main/othervm -Xlog:class+load,class+unload=trace -XX:+UseCompressedOops -XX:+UseCompressedClassPointers -XX:+UseSerialGC -XX:+UsePerfData -Xint gc.metaspace.TestPerfCountersAndMemoryPools + * @run main/othervm -Xlog:class+load,class+unload=trace -XX:+UseCompressedOops -XX:+UseSerialGC -XX:+UsePerfData -Xint gc.metaspace.TestPerfCountersAndMemoryPools */ /* @test TestPerfCountersAndMemoryPools @@ -60,7 +59,7 @@ public class TestPerfCountersAndMemoryPools { public static void main(String[] args) throws Exception { checkMemoryUsage("Metaspace", "sun.gc.metaspace"); - if (InputArguments.contains("-XX:+UseCompressedClassPointers") && Platform.is64bit()) { + if (Platform.is64bit()) { checkMemoryUsage("Compressed Class Space", "sun.gc.compressedclassspace"); } } diff --git a/test/hotspot/jtreg/gc/metaspace/TestSizeTransitions.java b/test/hotspot/jtreg/gc/metaspace/TestSizeTransitions.java index 4237b8ce1dd..db698782e8f 100644 --- a/test/hotspot/jtreg/gc/metaspace/TestSizeTransitions.java +++ b/test/hotspot/jtreg/gc/metaspace/TestSizeTransitions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2019, Twitter, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -35,24 +35,21 @@ import java.util.List; * @requires vm.gc.Serial * @summary Tests that the metaspace size transition logging is done correctly. * @library /test/lib - * @run driver gc.metaspace.TestSizeTransitions false -XX:+UseSerialGC - * @run driver gc.metaspace.TestSizeTransitions true -XX:+UseSerialGC + * @run driver gc.metaspace.TestSizeTransitions -XX:+UseSerialGC */ /* @test TestSizeTransitionsParallel * @requires vm.gc.Parallel * @summary Tests that the metaspace size transition logging is done correctly. * @library /test/lib - * @run driver gc.metaspace.TestSizeTransitions false -XX:+UseParallelGC - * @run driver gc.metaspace.TestSizeTransitions true -XX:+UseParallelGC + * @run driver gc.metaspace.TestSizeTransitions -XX:+UseParallelGC */ /* @test TestSizeTransitionsG1 * @requires vm.gc.G1 * @summary Tests that the metaspace size transition logging is done correctly. * @library /test/lib - * @run driver gc.metaspace.TestSizeTransitions false -XX:+UseG1GC - * @run driver gc.metaspace.TestSizeTransitions true -XX:+UseG1GC + * @run driver gc.metaspace.TestSizeTransitions -XX:+UseG1GC */ public class TestSizeTransitions { @@ -76,13 +73,13 @@ public class TestSizeTransitions { private static final String SIZE_TRANSITION_REGEX = "\\d+K\\(\\d+K\\)->\\d+K\\(\\d+K\\)"; // matches -coops metaspace size transitions - private static final String NO_COMPRESSED_KLASS_POINTERS_REGEX = + private static final String WITHOUT_CLASS_SPACE_REGEX = String.format("^%s.* Metaspace: %s$", LOG_TAGS_REGEX, SIZE_TRANSITION_REGEX); // matches +coops metaspace size transitions - private static final String COMPRESSED_KLASS_POINTERS_REGEX = + private static final String WITH_CLASS_SPACE_REGEX = String.format("^%s.* Metaspace: %s NonClass: %s Class: %s$", LOG_TAGS_REGEX, SIZE_TRANSITION_REGEX, @@ -90,26 +87,11 @@ public class TestSizeTransitions { SIZE_TRANSITION_REGEX); public static void main(String... args) throws Exception { - // args: - if (args.length != 2) { - throw new RuntimeException("wrong number of args: " + args.length); + if (args.length == 0) { + throw new RuntimeException("expected jvm args: " + args.length); } - final boolean hasCompressedKlassPointers = Platform.is64bit(); - final boolean useCompressedKlassPointers = Boolean.parseBoolean(args[0]); - final String gcArg = args[1]; - - if (!hasCompressedKlassPointers && useCompressedKlassPointers) { - // No need to run this configuration. - System.out.println("Skipping test."); - return; - } - - List jvmArgs = new ArrayList<>(); - if (hasCompressedKlassPointers) { - jvmArgs.add(useCompressedKlassPointers ? "-XX:+UseCompressedClassPointers" : "-XX:-UseCompressedClassPointers"); - } - jvmArgs.add(gcArg); + List jvmArgs = new ArrayList<>(List.of(args)); jvmArgs.add("-Xmx256m"); jvmArgs.add("-Xlog:gc,gc+metaspace=info"); jvmArgs.add(TestSizeTransitions.Run.class.getName()); @@ -123,12 +105,14 @@ public class TestSizeTransitions { System.out.println(output.getStdout()); output.shouldHaveExitValue(0); - if (useCompressedKlassPointers) { - output.stdoutShouldMatch(COMPRESSED_KLASS_POINTERS_REGEX); - output.stdoutShouldNotMatch(NO_COMPRESSED_KLASS_POINTERS_REGEX); + // 32-bit uses narrow Pointers but no class space + final boolean hasClassSpace = Platform.is64bit(); + if (hasClassSpace) { + output.stdoutShouldMatch(WITH_CLASS_SPACE_REGEX); + output.stdoutShouldNotMatch(WITHOUT_CLASS_SPACE_REGEX); } else { - output.stdoutShouldMatch(NO_COMPRESSED_KLASS_POINTERS_REGEX); - output.stdoutShouldNotMatch(COMPRESSED_KLASS_POINTERS_REGEX); + output.stdoutShouldMatch(WITHOUT_CLASS_SPACE_REGEX); + output.stdoutShouldNotMatch(WITH_CLASS_SPACE_REGEX); } } } diff --git a/test/hotspot/jtreg/gtest/ArrayTests.java b/test/hotspot/jtreg/gtest/ArrayTests.java index b1afa4795d2..d3a8498d5eb 100644 --- a/test/hotspot/jtreg/gtest/ArrayTests.java +++ b/test/hotspot/jtreg/gtest/ArrayTests.java @@ -26,31 +26,18 @@ * This tests object array sizes by running gtests with different settings. */ -/* @test id=with-coops-with-ccp - * @summary Run object array size tests with compressed oops and compressed class pointers +/* @test id=with-coops + * @summary Run object array size tests with compressed oops * @library /test/lib * @modules java.base/jdk.internal.misc * java.xml - * @run main/native GTestWrapper --gtest_filter=arrayOop -XX:+UseCompressedClassPointers -XX:+UseCompressedOops + * @run main/native GTestWrapper --gtest_filter=arrayOop -XX:+UseCompressedOops */ -/* @test id=with-coops-no-ccp - * @summary Run object array size tests with compressed oops and compressed class pointers + +/* @test id=no-coops + * @summary Run object array size tests with compressed oops * @library /test/lib * @modules java.base/jdk.internal.misc * java.xml - * @run main/native GTestWrapper --gtest_filter=arrayOop -XX:-UseCompressedClassPointers -XX:+UseCompressedOops - */ -/* @test id=no-coops-with-ccp - * @summary Run object array size tests with compressed oops and compressed class pointers - * @library /test/lib - * @modules java.base/jdk.internal.misc - * java.xml - * @run main/native GTestWrapper --gtest_filter=arrayOop -XX:+UseCompressedClassPointers -XX:-UseCompressedOops - */ -/* @test id=no-coops-no-ccp - * @summary Run object array size tests with compressed oops and compressed class pointers - * @library /test/lib - * @modules java.base/jdk.internal.misc - * java.xml - * @run main/native GTestWrapper --gtest_filter=arrayOop -XX:-UseCompressedClassPointers -XX:-UseCompressedOops + * @run main/native GTestWrapper --gtest_filter=arrayOop -XX:-UseCompressedOops */ diff --git a/test/hotspot/jtreg/gtest/CompressedKlassGtest.java b/test/hotspot/jtreg/gtest/CompressedKlassGtest.java index ba801724558..24f1dff5a30 100644 --- a/test/hotspot/jtreg/gtest/CompressedKlassGtest.java +++ b/test/hotspot/jtreg/gtest/CompressedKlassGtest.java @@ -1,6 +1,6 @@ /* * Copyright (c) 2024, Red Hat, Inc. All rights reserved. - * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 @@ * @run main/native GTestWrapper --gtest_filter=CompressedKlass* -XX:-UseCompactObjectHeaders -Xlog:metaspace* -Xmx6g -Xms128m -Xshare:off -XX:CompressedClassSpaceSize=128m */ -/* @test id=ccp_off - * @library /test/lib - * @requires vm.bits == "64" - * @modules java.base/jdk.internal.misc - * java.xml - * @run main/native GTestWrapper --gtest_filter=CompressedKlass* -XX:-UseCompressedClassPointers -Xlog:metaspace* -Xmx6g -Xms128m - */ - /* @test id=use-zero-based-encoding-coh * @library /test/lib * @requires vm.bits == "64" diff --git a/test/hotspot/jtreg/gtest/MetaspaceGtests.java b/test/hotspot/jtreg/gtest/MetaspaceGtests.java index 38fef145125..26faa2c7c2d 100644 --- a/test/hotspot/jtreg/gtest/MetaspaceGtests.java +++ b/test/hotspot/jtreg/gtest/MetaspaceGtests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2020, 2023 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -40,15 +40,6 @@ * @run main/native GTestWrapper --gtest_filter=metaspace* -XX:+UnlockDiagnosticVMOptions -XX:VerifyMetaspaceInterval=1 */ -/* @test id=no-ccs - * @summary Run metaspace-related gtests with compressed class pointers off - * @library /test/lib - * @modules java.base/jdk.internal.misc - * java.xml - * @requires vm.bits == 64 - * @requires vm.flagless - * @run main/native GTestWrapper --gtest_filter=metaspace* -XX:+UnlockDiagnosticVMOptions -XX:-UseCompressedClassPointers - */ /* @test id=UseCompactObjectHeaders * @summary Run metaspace-related gtests with tiny classpointers diff --git a/test/hotspot/jtreg/gtest/ObjArrayTests.java b/test/hotspot/jtreg/gtest/ObjArrayTests.java index baae1840417..ede85948335 100644 --- a/test/hotspot/jtreg/gtest/ObjArrayTests.java +++ b/test/hotspot/jtreg/gtest/ObjArrayTests.java @@ -26,60 +26,34 @@ * This tests object array sizes by running gtests with different settings. */ -/* @test id=with-coops-with-ccp - * @summary Run object array size tests with compressed oops and compressed class pointers +/* @test id=with-coops + * @summary Run object array size tests with compressed oops * @library /test/lib * @modules java.base/jdk.internal.misc * java.xml - * @run main/native GTestWrapper --gtest_filter=objArrayOop -XX:+UseCompressedClassPointers -XX:+UseCompressedOops - */ -/* @test id=with-coops-no-ccp - * @summary Run object array size tests with compressed oops and compressed class pointers - * @library /test/lib - * @modules java.base/jdk.internal.misc - * java.xml - * @run main/native GTestWrapper --gtest_filter=objArrayOop -XX:-UseCompressedClassPointers -XX:+UseCompressedOops - */ -/* @test id=no-coops-with-ccp - * @summary Run object array size tests with compressed oops and compressed class pointers - * @library /test/lib - * @modules java.base/jdk.internal.misc - * java.xml - * @run main/native GTestWrapper --gtest_filter=objArrayOop -XX:+UseCompressedClassPointers -XX:-UseCompressedOops - */ -/* @test id=no-coops-no-ccp - * @summary Run object array size tests with compressed oops and compressed class pointers - * @library /test/lib - * @modules java.base/jdk.internal.misc - * java.xml - * @run main/native GTestWrapper --gtest_filter=objArrayOop -XX:-UseCompressedClassPointers -XX:-UseCompressedOops + * @run main/native GTestWrapper --gtest_filter=objArrayOop -XX:+UseCompressedOops */ -/* @test id=with-coops-with-ccp-large-align - * @summary Run object array size tests with compressed oops and compressed class pointers +/* @test id=no-coops + * @summary Run object array size tests with compressed oops * @library /test/lib * @modules java.base/jdk.internal.misc * java.xml - * @run main/native GTestWrapper --gtest_filter=objArrayOop -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:ObjAlignmentInBytes=256 + * @run main/native GTestWrapper --gtest_filter=objArrayOop -XX:-UseCompressedOops */ -/* @test id=with-coops-no-ccp-large-align - * @summary Run object array size tests with compressed oops and compressed class pointers + +/* @test id=with-coops-large-align + * @summary Run object array size tests with compressed oops * @library /test/lib * @modules java.base/jdk.internal.misc * java.xml - * @run main/native GTestWrapper --gtest_filter=objArrayOop -XX:-UseCompressedClassPointers -XX:+UseCompressedOops -XX:ObjAlignmentInBytes=256 + * @run main/native GTestWrapper --gtest_filter=objArrayOop -XX:+UseCompressedOops -XX:ObjAlignmentInBytes=256 */ -/* @test id=no-coops-with-ccp-large-align - * @summary Run object array size tests with compressed oops and compressed class pointers + +/* @test id=no-coops-large-align + * @summary Run object array size tests with compressed oops * @library /test/lib * @modules java.base/jdk.internal.misc * java.xml - * @run main/native GTestWrapper --gtest_filter=objArrayOop -XX:+UseCompressedClassPointers -XX:-UseCompressedOops -XX:ObjAlignmentInBytes=256 - */ -/* @test id=no-coops-no-ccp-large-align - * @summary Run object array size tests with compressed oops and compressed class pointers - * @library /test/lib - * @modules java.base/jdk.internal.misc - * java.xml - * @run main/native GTestWrapper --gtest_filter=objArrayOop -XX:-UseCompressedClassPointers -XX:-UseCompressedOops -XX:ObjAlignmentInBytes=256 + * @run main/native GTestWrapper --gtest_filter=objArrayOop -XX:-UseCompressedOops -XX:ObjAlignmentInBytes=256 */ diff --git a/test/hotspot/jtreg/runtime/CDSCompressedKPtrs/CDSCompressedKPtrs.java b/test/hotspot/jtreg/runtime/CDSCompressedKPtrs/CDSCompressedKPtrs.java deleted file mode 100644 index 51b0469ce46..00000000000 --- a/test/hotspot/jtreg/runtime/CDSCompressedKPtrs/CDSCompressedKPtrs.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2013, 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 - * @requires vm.cds - * @requires vm.bits == 64 - * @requires vm.flagless - * @bug 8003424 - * @summary Testing UseCompressedClassPointers with CDS - * @library /test/lib - * @modules java.base/jdk.internal.misc - * java.management - * @run driver CDSCompressedKPtrs - */ - -import jdk.test.lib.Platform; -import jdk.test.lib.process.ProcessTools; -import jdk.test.lib.process.OutputAnalyzer; -import jtreg.SkippedException; - -public class CDSCompressedKPtrs { - public static void main(String[] args) throws Exception { - ProcessBuilder pb; - pb = ProcessTools.createLimitedTestJavaProcessBuilder( - "-XX:+UseCompressedClassPointers", "-XX:+UseCompressedOops", - "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=./CDSCompressedKPtrs.jsa", "-Xshare:dump", "-Xlog:cds"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); - try { - output.shouldContain("Loading classes to share"); - output.shouldHaveExitValue(0); - - pb = ProcessTools.createLimitedTestJavaProcessBuilder( - "-XX:+UseCompressedClassPointers", "-XX:+UseCompressedOops", - "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=./CDSCompressedKPtrs.jsa", "-Xshare:on", "-version"); - output = new OutputAnalyzer(pb.start()); - output.shouldContain("sharing"); - output.shouldHaveExitValue(0); - - } catch (RuntimeException e) { - output.shouldContain("Unable to use shared archive"); - output.shouldHaveExitValue(1); - throw new SkippedException("CDS was turned off"); - } - } -} diff --git a/test/hotspot/jtreg/runtime/CompressedOops/CompressedClassPointers.java b/test/hotspot/jtreg/runtime/CompressedOops/CompressedClassPointers.java index e4b6f2a0548..fe1f8cb92fc 100644 --- a/test/hotspot/jtreg/runtime/CompressedOops/CompressedClassPointers.java +++ b/test/hotspot/jtreg/runtime/CompressedOops/CompressedClassPointers.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,7 +40,6 @@ import jdk.test.lib.Platform; import jdk.test.lib.process.ProcessTools; import jdk.test.lib.process.OutputAnalyzer; -import jtreg.SkippedException; public class CompressedClassPointers { @@ -218,7 +217,6 @@ public class CompressedClassPointers { public static void smallHeapTestNoCoop() throws Exception { ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( "-XX:-UseCompressedOops", - "-XX:+UseCompressedClassPointers", "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedBaseAddress=8g", "-Xmx128m", @@ -236,7 +234,6 @@ public class CompressedClassPointers { public static void smallHeapTestWith1GNoCoop() throws Exception { ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( "-XX:-UseCompressedOops", - "-XX:+UseCompressedClassPointers", "-XX:+UnlockDiagnosticVMOptions", "-XX:CompressedClassSpaceSize=1g", "-Xmx128m", @@ -258,7 +255,6 @@ public class CompressedClassPointers { public static void largeHeapTestNoCoop() throws Exception { ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( "-XX:-UseCompressedOops", - "-XX:+UseCompressedClassPointers", "-XX:+UnlockDiagnosticVMOptions", "-XX:+UnlockExperimentalVMOptions", "-Xmx30g", @@ -280,7 +276,6 @@ public class CompressedClassPointers { public static void largePagesTestNoCoop() throws Exception { ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( "-XX:-UseCompressedOops", - "-XX:+UseCompressedClassPointers", "-XX:+UnlockDiagnosticVMOptions", "-Xmx128m", "-XX:+UseLargePages", @@ -291,23 +286,10 @@ public class CompressedClassPointers { output.shouldHaveExitValue(0); } - public static void heapBaseMinAddressTestNoCoop() throws Exception { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( - "-XX:-UseCompressedOops", - "-XX:+UseCompressedClassPointers", - "-XX:HeapBaseMinAddress=1m", - "-Xlog:gc+heap+coops=debug", - "-version"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); - output.shouldContain("HeapBaseMinAddress must be at least"); - output.shouldHaveExitValue(0); - } - public static void sharingTestNoCoop() throws Exception { // Test small heaps ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( "-XX:-UseCompressedOops", - "-XX:+UseCompressedClassPointers", "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=./CompressedClassPointers.jsa", "-Xmx128m", @@ -325,7 +307,6 @@ public class CompressedClassPointers { pb = ProcessTools.createLimitedTestJavaProcessBuilder( "-XX:-UseCompressedOops", - "-XX:+UseCompressedClassPointers", "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=./CompressedClassPointers.jsa", "-Xmx128m", @@ -356,7 +337,6 @@ public class CompressedClassPointers { smallHeapTestWith1GNoCoop(); largeHeapTestNoCoop(); largePagesTestNoCoop(); - heapBaseMinAddressTestNoCoop(); sharingTestNoCoop(); } } diff --git a/test/hotspot/jtreg/runtime/CompressedOops/CompressedClassSpaceSize.java b/test/hotspot/jtreg/runtime/CompressedOops/CompressedClassSpaceSize.java index 7bbb9edb7b4..0898e6b96eb 100644 --- a/test/hotspot/jtreg/runtime/CompressedOops/CompressedClassSpaceSize.java +++ b/test/hotspot/jtreg/runtime/CompressedOops/CompressedClassSpaceSize.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -107,13 +107,6 @@ public class CompressedClassSpaceSize { output = new OutputAnalyzer(pb.start()); output.shouldContain("outside the allowed range") .shouldHaveExitValue(1); - - pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:-UseCompressedClassPointers", - "-XX:CompressedClassSpaceSize=" + minAllowedClassSpaceSize, - "-version"); - output = new OutputAnalyzer(pb.start()); - output.shouldContain("Setting CompressedClassSpaceSize has no effect when compressed class pointers are not used") - .shouldHaveExitValue(0); } break; case "valid_small": { diff --git a/test/hotspot/jtreg/runtime/CompressedOops/CompressedKlassPointerAndOops.java b/test/hotspot/jtreg/runtime/CompressedOops/CompressedKlassPointerAndOops.java index 403654d1cc8..32bb432308b 100644 --- a/test/hotspot/jtreg/runtime/CompressedOops/CompressedKlassPointerAndOops.java +++ b/test/hotspot/jtreg/runtime/CompressedOops/CompressedKlassPointerAndOops.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2026, Oracle and/or its affiliates. All rights reserved. * 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,7 @@ /* * @test - * @bug 8000968 - * @summary NPG: UseCompressedClassPointers asserts with ObjectAlignmentInBytes=32 + * @summary Test Compressed Oops with different object alignments * @library /test/lib * @modules java.base/jdk.internal.misc * java.management @@ -51,7 +50,6 @@ public class CompressedKlassPointerAndOops { OutputAnalyzer output; pb = ProcessTools.createLimitedTestJavaProcessBuilder( - "-XX:+UseCompressedClassPointers", "-XX:+UseCompressedOops", "-XX:ObjectAlignmentInBytes=" + alignment, "-version"); diff --git a/test/hotspot/jtreg/runtime/ErrorHandling/TestVMConfigInHsErrFile.java b/test/hotspot/jtreg/runtime/ErrorHandling/TestVMConfigInHsErrFile.java index 1e168221726..8f41121fbc1 100644 --- a/test/hotspot/jtreg/runtime/ErrorHandling/TestVMConfigInHsErrFile.java +++ b/test/hotspot/jtreg/runtime/ErrorHandling/TestVMConfigInHsErrFile.java @@ -56,7 +56,7 @@ public class TestVMConfigInHsErrFile { public static void main(String[] args) throws Exception { switch (args[0]) { case "coh-on" -> testCompactObjectHeaders(); - case "coh-off" -> testCompressedClassPointers(); + case "coh-off" -> testNotCompactObjectHeaders(); } } @@ -79,20 +79,16 @@ public class TestVMConfigInHsErrFile { Pattern[] expectedPatterns = new Pattern[] { Pattern.compile("# Java VM: .*compact obj headers.*") }; - Pattern[] notExpectedPatterns = new Pattern[] { - Pattern.compile("# Java VM: .*compressed class ptrs.*") - }; - HsErrFileUtils.checkHsErrFileContent(f, expectedPatterns, notExpectedPatterns, true, true); + HsErrFileUtils.checkHsErrFileContent(f, expectedPatterns, null, true, true); } - private static void testCompressedClassPointers() throws Exception { + private static void testNotCompactObjectHeaders() throws Exception { ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( "-XX:+UnlockDiagnosticVMOptions", "-XX:+UnlockExperimentalVMOptions", "-XX:-UseCompactObjectHeaders", - "-XX:+UseCompressedClassPointers", "-Xmx100M", "-XX:-CreateCoredumpOnCrash", "-XX:ErrorHandlerTest=14", @@ -104,14 +100,11 @@ public class TestVMConfigInHsErrFile { // extract hs-err file File f = HsErrFileUtils.openHsErrFileFromOutput(output); - Pattern[] expectedPatterns = new Pattern[] { - Pattern.compile("# Java VM: .*compressed class ptrs.*") - }; Pattern[] notExpectedPatterns = new Pattern[] { Pattern.compile("# Java VM: .*compact obj headers.*") }; - HsErrFileUtils.checkHsErrFileContent(f, expectedPatterns, notExpectedPatterns, true, true); + HsErrFileUtils.checkHsErrFileContent(f, null, notExpectedPatterns, true, true); } } diff --git a/test/hotspot/jtreg/runtime/FieldLayout/BaseOffsets.java b/test/hotspot/jtreg/runtime/FieldLayout/BaseOffsets.java index 73f5a1c6137..00b09fec6ed 100644 --- a/test/hotspot/jtreg/runtime/FieldLayout/BaseOffsets.java +++ b/test/hotspot/jtreg/runtime/FieldLayout/BaseOffsets.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved. * 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,47 +22,29 @@ */ /* - * @test id=with-coops-with-ccp + * @test id=with-coops * @library /test/lib / * @requires vm.bits == "64" * @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 main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseCompressedOops -XX:+UseCompressedClassPointers -XX:-UseCompactObjectHeaders BaseOffsets + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseCompressedOops -XX:-UseCompactObjectHeaders BaseOffsets */ + /* - * @test id=no-coops-with-ccp + * @test id=no-coops * @library /test/lib / * @requires vm.bits == "64" * @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 main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:-UseCompressedOops -XX:+UseCompressedClassPointers -XX:-UseCompactObjectHeaders BaseOffsets + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:-UseCompressedOops -XX:-UseCompactObjectHeaders BaseOffsets */ + /* - * @test id=with-coops-no-ccp - * @library /test/lib / - * @requires vm.bits == "64" - * @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 main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseCompressedOops -XX:-UseCompressedClassPointers -XX:-UseCompactObjectHeaders BaseOffsets - */ -/* - * @test id=no-coops-no-ccp - * @library /test/lib / - * @requires vm.bits == "64" - * @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 main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:-UseCompressedOops -XX:-UseCompressedClassPointers -XX:-UseCompactObjectHeaders BaseOffsets - */ -/* - * @test id=with-coop--with-coh + * @test id=with-coop-with-coh * @library /test/lib / * @requires vm.bits == "64" * @modules java.base/jdk.internal.misc @@ -71,6 +53,7 @@ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseCompressedOops -XX:+UseCompactObjectHeaders BaseOffsets */ + /* * @test id=no-coops-with-coh * @library /test/lib / @@ -81,6 +64,7 @@ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:-UseCompressedOops -XX:+UseCompactObjectHeaders BaseOffsets */ + /* * @test id=32bit * @library /test/lib / @@ -117,14 +101,10 @@ public class BaseOffsets { INT_OFFSET = 8; INT_ARRAY_OFFSET = 12; LONG_ARRAY_OFFSET = 16; - } else if (WB.getBooleanVMFlag("UseCompressedClassPointers")) { + } else { INT_OFFSET = 12; INT_ARRAY_OFFSET = 16; LONG_ARRAY_OFFSET = 16; - } else { - INT_OFFSET = 16; - INT_ARRAY_OFFSET = 20; - LONG_ARRAY_OFFSET = 24; } } diff --git a/test/hotspot/jtreg/runtime/FieldLayout/FieldDensityTest.java b/test/hotspot/jtreg/runtime/FieldLayout/FieldDensityTest.java index 5f4fb7a79c4..019b428ae84 100644 --- a/test/hotspot/jtreg/runtime/FieldLayout/FieldDensityTest.java +++ b/test/hotspot/jtreg/runtime/FieldLayout/FieldDensityTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * 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,8 +37,7 @@ * @library /test/lib * @modules java.base/jdk.internal.misc * java.management - * @run main/othervm -XX:+UseCompressedOops -XX:+UseCompressedClassPointers FieldDensityTest - * @run main/othervm -XX:+UseCompressedOops -XX:-UseCompressedClassPointers FieldDensityTest + * @run main/othervm -XX:+UseCompressedOops FieldDensityTest */ import java.lang.reflect.Field; diff --git a/test/hotspot/jtreg/runtime/FieldLayout/TestOopMapSizeMinimal.java b/test/hotspot/jtreg/runtime/FieldLayout/TestOopMapSizeMinimal.java index 861f1aa3d1b..263bd750ca3 100644 --- a/test/hotspot/jtreg/runtime/FieldLayout/TestOopMapSizeMinimal.java +++ b/test/hotspot/jtreg/runtime/FieldLayout/TestOopMapSizeMinimal.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2025, Red Hat, Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -30,47 +30,27 @@ import java.util.ArrayList; import java.util.List; /* - * @test id=no_coops_no_ccptr_no_coh + * @test id=no_coops_no_coh * @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 main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UnlockExperimentalVMOptions -XX:-UseCompressedOops -XX:-UseCompressedClassPointers -XX:-UseCompactObjectHeaders TestOopMapSizeMinimal + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UnlockExperimentalVMOptions -XX:-UseCompressedOops -XX:-UseCompactObjectHeaders TestOopMapSizeMinimal */ /* - * @test id=coops_no_ccptr_no_coh + * @test id=coops_no_coh * @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 main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UnlockExperimentalVMOptions -XX:+UseCompressedOops -XX:-UseCompressedClassPointers -XX:-UseCompactObjectHeaders TestOopMapSizeMinimal + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UnlockExperimentalVMOptions -XX:+UseCompressedOops -XX:-UseCompactObjectHeaders TestOopMapSizeMinimal */ /* - * @test id=no_coops_ccptr_no_coh - * @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 main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UnlockExperimentalVMOptions -XX:-UseCompressedOops -XX:+UseCompressedClassPointers -XX:-UseCompactObjectHeaders TestOopMapSizeMinimal - */ - -/* - * @test id=coops_ccptr_no_coh - * @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 main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UnlockExperimentalVMOptions -XX:+UseCompressedOops -XX:+UseCompressedClassPointers -XX:-UseCompactObjectHeaders TestOopMapSizeMinimal - */ - -/* - * @test id=no_coops_ccptr_coh + * @test id=no_coops_coh * @library /test/lib * @modules java.base/jdk.internal.misc * java.management @@ -79,6 +59,16 @@ import java.util.List; * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UnlockExperimentalVMOptions -XX:-UseCompressedOops -XX:+UseCompactObjectHeaders TestOopMapSizeMinimal */ +/* + * @test id=coops_coh + * @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 main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UnlockExperimentalVMOptions -XX:+UseCompressedOops -XX:+UseCompactObjectHeaders TestOopMapSizeMinimal + */ + public class TestOopMapSizeMinimal { public static int OOP_SIZE_IN_BYTES = -1; @@ -99,10 +89,8 @@ public class TestOopMapSizeMinimal { if (is_64_bit) { if (WB.getBooleanVMFlag("UseCompactObjectHeaders")) { HEADER_SIZE_IN_BYTES = 8; - } else if (WB.getBooleanVMFlag("UseCompressedClassPointers")) { - HEADER_SIZE_IN_BYTES = 12; } else { - HEADER_SIZE_IN_BYTES = 16; + HEADER_SIZE_IN_BYTES = 12; } } else { HEADER_SIZE_IN_BYTES = 8; @@ -188,10 +176,9 @@ public class TestOopMapSizeMinimal { // DERIVED4 o4 oopmap entry 2 (reversed order) // i4 - // There are two combinations that have gaps: - // -UseCompressedOops + +COH, and -UseCompressedOops + -UseCompressedClassPointers. - // In both cases there is a gap following i1, and i2 will therefore nestle into that gap. - // Otherwise the same logic applies. + // There is one combination that has gaps: + // -UseCompressedOops + +COH: A gap will be following i1, and i2 will therefore nestle into that gap. + // Otherwise, the same logic applies. if (OOP_SIZE_IN_BYTES == 4 || // oop size == int size (OOP_SIZE_IN_BYTES == 8 && HEADER_SIZE_IN_BYTES == 12) diff --git a/test/hotspot/jtreg/runtime/Metaspace/MaxMetaspaceSizeTest.java b/test/hotspot/jtreg/runtime/Metaspace/MaxMetaspaceSizeTest.java index b2ff8ed9bde..a42a6ee3a52 100644 --- a/test/hotspot/jtreg/runtime/Metaspace/MaxMetaspaceSizeTest.java +++ b/test/hotspot/jtreg/runtime/Metaspace/MaxMetaspaceSizeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ public class MaxMetaspaceSizeTest { "-Xshare:off", "-Xmx1g", "-XX:MaxMetaspaceSize=4K", - "-XX:+UseCompressedClassPointers", "-XX:CompressedClassSpaceSize=1g", "--version"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); diff --git a/test/hotspot/jtreg/runtime/Metaspace/PrintMetaspaceDcmd.java b/test/hotspot/jtreg/runtime/Metaspace/PrintMetaspaceDcmd.java index 7ff19326324..f526405900d 100644 --- a/test/hotspot/jtreg/runtime/Metaspace/PrintMetaspaceDcmd.java +++ b/test/hotspot/jtreg/runtime/Metaspace/PrintMetaspaceDcmd.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2018, SAP and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -22,62 +22,27 @@ * questions. */ +import jdk.test.lib.Platform; import jdk.test.lib.dcmd.PidJcmdExecutor; import jdk.test.lib.process.OutputAnalyzer; -/* - * @test id=test-64bit-ccs - * @summary Test the VM.metaspace command - * @requires vm.bits == "64" - * @library /test/lib - * @modules java.base/jdk.internal.misc - * java.management - * @run main/othervm -Dwith-compressed-class-space -XX:MaxMetaspaceSize=201M -Xmx100M -XX:+UseCompressedOops -XX:+UseCompressedClassPointers PrintMetaspaceDcmd - */ +import java.io.IOException; /* - * @test id=test-64bit-noccs + * @test * @summary Test the VM.metaspace command - * @requires vm.bits == "64" * @library /test/lib * @modules java.base/jdk.internal.misc * java.management - * @run main/othervm -Dwithout-compressed-class-space -XX:MaxMetaspaceSize=201M -Xmx100M -XX:-UseCompressedOops -XX:-UseCompressedClassPointers PrintMetaspaceDcmd - */ - - /* - * @test id=test-nospecified - * @summary Test the VM.metaspace command - * @requires vm.bits == "64" - * @library /test/lib - * @modules java.base/jdk.internal.misc - * java.management - * @run main/othervm -Dno-specified-flag -Xmx100M -XX:-UseCompressedOops -XX:-UseCompressedClassPointers PrintMetaspaceDcmd - */ - -/* - * @test test-32bit - * @summary Test the VM.metaspace command - * @requires vm.bits == "32" - * @library /test/lib - * @modules java.base/jdk.internal.misc - * java.management - * @run main/othervm -Dwithout-compressed-class-space -XX:MaxMetaspaceSize=201M -Xmx100M PrintMetaspaceDcmd + * @run main/othervm -Dwith-compressed-class-space -XX:MaxMetaspaceSize=201M -Xmx100M PrintMetaspaceDcmd */ public class PrintMetaspaceDcmd { - private static void doTheNoSpecifiedPropTest() throws Exception { - ProcessBuilder pb = new ProcessBuilder(); - OutputAnalyzer output; + public static void main(String [] args) throws IOException { - pb.command(new PidJcmdExecutor().getCommandLine("VM.metaspace", "basic")); - output = new OutputAnalyzer(pb.start()); - output.shouldHaveExitValue(0); - output.shouldMatch("MaxMetaspaceSize: unlimited"); - } + final boolean usesCompressedClassSpace = Platform.is64bit(); - private static void doTheCCSPropTest(boolean usesCompressedClassSpace) throws Exception { ProcessBuilder pb = new ProcessBuilder(); OutputAnalyzer output; @@ -172,15 +137,4 @@ public class PrintMetaspaceDcmd { output.shouldMatch("MaxMetaspaceSize:.*210763776 bytes"); } - public static void main(String args[]) throws Exception { - if (System.getProperty("no-specified-flag") != null) { - doTheNoSpecifiedPropTest(); - } else if (System.getProperty("with-compressed-class-space") != null) { - doTheCCSPropTest(true); - } else if (System.getProperty("without-compressed-class-space") != null) { - doTheCCSPropTest(false); - } else { - throw new IllegalArgumentException("Unrecognized running mode"); - } - } } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/CommandLineFlagCombo.java b/test/hotspot/jtreg/runtime/cds/appcds/CommandLineFlagCombo.java index 6ab9b18c1e9..da994edeb27 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/CommandLineFlagCombo.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/CommandLineFlagCombo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,7 +55,6 @@ public class CommandLineFlagCombo { private static final String[] testTable = { "-XX:+UseG1GC", "-XX:+UseSerialGC", "-XX:+UseParallelGC", "-XX:+UseLargePages", // may only take effect on machines with large-pages - "-XX:+UseCompressedClassPointers", "-XX:+UseCompressedOops", "-XX:ObjectAlignmentInBytes=16", "-XX:ObjectAlignmentInBytes=32", @@ -123,7 +122,6 @@ public class CommandLineFlagCombo { if (Platform.is32bit()) { if (testEntry.equals("-XX:+UseCompressedOops") || - testEntry.equals("-XX:+UseCompressedClassPointers") || testEntry.contains("ObjectAlignmentInBytes") ) { System.out.println("Test case not applicable on 32-bit platforms"); diff --git a/test/hotspot/jtreg/runtime/cds/appcds/CommandLineFlagComboNegative.java b/test/hotspot/jtreg/runtime/cds/appcds/CommandLineFlagComboNegative.java index 89fe868349b..d5aafb2bcf6 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/CommandLineFlagComboNegative.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/CommandLineFlagComboNegative.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -66,9 +66,9 @@ public class CommandLineFlagComboNegative { "An error has occurred while processing the shared archive file", 1) ); } testTable.add( new TestVector("-XX:+UseCompressedOops", "-XX:-UseCompressedOops", - "The saved state of UseCompressedOops and UseCompressedClassPointers is different from runtime, CDS will be disabled.", 1) ); - testTable.add( new TestVector("-XX:+UseCompressedClassPointers", "-XX:-UseCompressedClassPointers", - "The saved state of UseCompressedOops and UseCompressedClassPointers is different from runtime, CDS will be disabled.", 1) ); + "The saved state of UseCompressedOops (1) is different from runtime (0), CDS will be disabled.", 1) ); + testTable.add( new TestVector("-XX:-UseCompressedOops", "-XX:+UseCompressedOops", + "The saved state of UseCompressedOops (0) is different from runtime (1), CDS will be disabled.", 1) ); } private void runTests() throws Exception diff --git a/test/hotspot/jtreg/runtime/cds/appcds/FillerObjectLoadTest.java b/test/hotspot/jtreg/runtime/cds/appcds/FillerObjectLoadTest.java deleted file mode 100644 index 8538155375c..00000000000 --- a/test/hotspot/jtreg/runtime/cds/appcds/FillerObjectLoadTest.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2022, Tencent. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please 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 8286066 - * @summary VM crash caused by unloaded FillerObject_klass - * @library /test/lib - * @requires vm.cds - * @requires vm.flagless - * @run driver FillerObjectLoadTest - */ - -import jdk.test.lib.process.OutputAnalyzer; -import jdk.test.lib.process.ProcessTools; - -public class FillerObjectLoadTest { - public static void main(String... args) throws Exception { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( - "-XX:+IgnoreUnrecognizedVMOptions", "-XX:-UseCompressedClassPointers", - "-XX:+UnlockExperimentalVMOptions", "-XX:+UseEpsilonGC", "-Xshare:dump", - "-XX:SharedArchiveFile=" + TestCommon.getNewArchiveName()); - OutputAnalyzer analyzer = new OutputAnalyzer(pb.start()); - analyzer.shouldHaveExitValue(0); - - pb = ProcessTools.createLimitedTestJavaProcessBuilder( - "-XX:+IgnoreUnrecognizedVMOptions", "-XX:-UseCompressedClassPointers", - "-XX:TLABSize=2048", "-Xshare:dump", - "-XX:SharedArchiveFile=" + TestCommon.getNewArchiveName()); - analyzer = new OutputAnalyzer(pb.start()); - analyzer.shouldHaveExitValue(0); - } -} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/TestCombinedCompressedFlags.java b/test/hotspot/jtreg/runtime/cds/appcds/TestCombinedCompressedFlags.java index 4f3681d30df..f0700b14b55 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/TestCombinedCompressedFlags.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/TestCombinedCompressedFlags.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * 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,12 +46,10 @@ public class TestCombinedCompressedFlags { static class ConfArg { public boolean useCompressedOops; // UseCompressedOops - public boolean useCompressedClassPointers; // UseCompressedClassPointers public String msg; public int code; - public ConfArg(boolean useCompressedOops, boolean useCompressedClassPointers, String msg, int code) { + public ConfArg(boolean useCompressedOops, String msg, int code) { this.useCompressedOops = useCompressedOops; - this.useCompressedClassPointers = useCompressedClassPointers; this.msg = msg; this.code = code; } @@ -65,67 +63,13 @@ public class TestCombinedCompressedFlags { initExecArgs(); } private void initExecArgs() { - /* The combinations have four cases. - * UseCompressedOops UseCompressedClassPointers Result - * 1. - * dump: on on - * test: on on Pass - * on off Fail - * off on Fail - * off off Fail - * 2. - * dump: on off - * test: on off Pass - * on on Fail - * off on Pass - * off off Fail - * 3. - * dump: off on - * test: off on Pass - * on on Fail - * on off Fail - * 4. - * dump: off off - * test: off off Pass - * on on Fail - * on off Fail - **/ + // We fail this test if the UseCompressedOops setting used at dumptime differs from runtime, + // succeed if it is identical execArgs = new ArrayList(); - if (dumpArg.useCompressedOops && dumpArg.useCompressedClassPointers) { - execArgs - .add(new ConfArg(true, true, HELLO_STRING, PASS)); - execArgs - .add(new ConfArg(true, false, EXEC_ABNORMAL_MSG, FAIL)); - execArgs - .add(new ConfArg(false, true, EXEC_ABNORMAL_MSG, FAIL)); - execArgs - .add(new ConfArg(false, false, EXEC_ABNORMAL_MSG, FAIL)); - - } else if(dumpArg.useCompressedOops && !dumpArg.useCompressedClassPointers) { - execArgs - .add(new ConfArg(true, false, HELLO_STRING, PASS)); - execArgs - .add(new ConfArg(true, true, EXEC_ABNORMAL_MSG, FAIL)); - execArgs - .add(new ConfArg(false, true, EXEC_ABNORMAL_MSG, FAIL)); - execArgs - .add(new ConfArg(false, false, EXEC_ABNORMAL_MSG, FAIL)); - - } else if (!dumpArg.useCompressedOops && dumpArg.useCompressedClassPointers) { - execArgs - .add(new ConfArg(false, true, HELLO_STRING, PASS)); - execArgs - .add(new ConfArg(true, true, EXEC_ABNORMAL_MSG, FAIL)); - execArgs - .add(new ConfArg(true, false, EXEC_ABNORMAL_MSG, FAIL)); - } else if (!dumpArg.useCompressedOops && !dumpArg.useCompressedClassPointers) { - execArgs - .add(new ConfArg(false, false, HELLO_STRING, PASS)); - execArgs - .add(new ConfArg(true, true, EXEC_ABNORMAL_MSG, FAIL)); - execArgs - .add(new ConfArg(true, false, EXEC_ABNORMAL_MSG, FAIL)); - } + execArgs + .add(new ConfArg(dumpArg.useCompressedOops, HELLO_STRING, PASS)); + execArgs + .add(new ConfArg(!dumpArg.useCompressedOops, EXEC_ABNORMAL_MSG, FAIL)); } } @@ -134,23 +78,14 @@ public class TestCombinedCompressedFlags { else return "-XX:-UseCompressedOops"; } - public static String getCompressedClassPointersArg(boolean on) { - if (on) return "-XX:+UseCompressedClassPointers"; - else return "-XX:-UseCompressedClassPointers"; - } - public static List runList; public static void configureRunArgs() { runList = new ArrayList(); runList - .add(new RunArg(new ConfArg(true, true, null, PASS))); + .add(new RunArg(new ConfArg(true, null, PASS))); runList - .add(new RunArg(new ConfArg(true, false, null, PASS))); - runList - .add(new RunArg(new ConfArg(false, true, null, PASS))); - runList - .add(new RunArg(new ConfArg(false, false, null, PASS))); + .add(new RunArg(new ConfArg(false, null, PASS))); } public static void main(String[] args) throws Exception { @@ -162,7 +97,6 @@ public class TestCombinedCompressedFlags { .dump(helloJar, new String[] {"Hello"}, getCompressedOopsArg(t.dumpArg.useCompressedOops), - getCompressedClassPointersArg(t.dumpArg.useCompressedClassPointers), "-Xlog:cds", "-XX:NativeMemoryTracking=detail"); out.shouldContain("Dumping shared data to file:"); @@ -175,7 +109,6 @@ public class TestCombinedCompressedFlags { "-Xlog:cds", "-XX:NativeMemoryTracking=detail", getCompressedOopsArg(c.useCompressedOops), - getCompressedClassPointersArg(c.useCompressedClassPointers), "Hello"); out.shouldContain(c.msg); out.shouldHaveExitValue(c.code); diff --git a/test/hotspot/jtreg/runtime/cds/appcds/TestZGCWithCDS.java b/test/hotspot/jtreg/runtime/cds/appcds/TestZGCWithCDS.java index eb42bb9f93d..bff2bcc727d 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/TestZGCWithCDS.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/TestZGCWithCDS.java @@ -36,7 +36,6 @@ * @comment Driver sets compressed oops/class pointers, jtreg overrides will cause problems. Only run the test if the flags are not set via the command line. * @requires vm.opt.UseCompressedOops == null - * @requires vm.opt.UseCompressedClassPointers == null * @run driver TestZGCWithCDS true */ @@ -55,7 +54,6 @@ * @comment Driver sets compressed oops/class pointers, jtreg overrides will cause problems. Only run the test if the flags are not set via the command line. * @requires vm.opt.UseCompressedOops == null - * @requires vm.opt.UseCompressedClassPointers == null * @run driver TestZGCWithCDS false */ @@ -65,7 +63,7 @@ import jdk.test.lib.process.OutputAnalyzer; public class TestZGCWithCDS { public final static String HELLO = "Hello World"; public final static String UNABLE_TO_USE_ARCHIVE = "Unable to use shared archive."; - public final static String ERR_MSG = "The saved state of UseCompressedOops and UseCompressedClassPointers is different from runtime, CDS will be disabled."; + public final static String ERR_MSG = "The saved state of UseCompressedOops (0) is different from runtime (1), CDS will be disabled."; public static void main(String... args) throws Exception { boolean compactHeadersOn = Boolean.valueOf(args[0]); String compactHeaders = "-XX:" + (compactHeadersOn ? "+" : "-") + "UseCompactObjectHeaders"; @@ -80,7 +78,7 @@ public class TestZGCWithCDS { out.shouldContain("Dumping shared data to file:"); out.shouldHaveExitValue(0); - System.out.println("1. Run with same args of dump"); + System.out.println("Run with same args of dump"); out = TestCommon .exec(helloJar, "-XX:+UseZGC", @@ -90,12 +88,11 @@ public class TestZGCWithCDS { out.shouldContain(HELLO); out.shouldHaveExitValue(0); - System.out.println("2. Run with +UseCompressedOops +UseCompressedClassPointers"); + System.out.println("Run with ZGC, +UseCompressedOops"); out = TestCommon .exec(helloJar, "-XX:-UseZGC", "-XX:+UseCompressedOops", // in case turned off by vmoptions - "-XX:+UseCompressedClassPointers", // by jtreg compactHeaders, "-Xlog:cds", "Hello"); @@ -103,37 +100,22 @@ public class TestZGCWithCDS { out.shouldContain(ERR_MSG); out.shouldHaveExitValue(1); - System.out.println("3. Run with -UseCompressedOops -UseCompressedClassPointers"); + System.out.println("Run with SerialGC, -UseCompressedOops"); out = TestCommon .exec(helloJar, "-XX:+UseSerialGC", "-XX:-UseCompressedOops", - "-XX:-UseCompressedClassPointers", - compactHeaders, - "-Xlog:cds", - "Hello"); - out.shouldContain(UNABLE_TO_USE_ARCHIVE); - out.shouldContain(ERR_MSG); - out.shouldHaveExitValue(1); - - System.out.println("4. Run with -UseCompressedOops +UseCompressedClassPointers"); - out = TestCommon - .exec(helloJar, - "-XX:+UseSerialGC", - "-XX:-UseCompressedOops", - "-XX:+UseCompressedClassPointers", compactHeaders, "-Xlog:cds", "Hello"); out.shouldContain(HELLO); out.shouldHaveExitValue(0); - System.out.println("5. Run with +UseCompressedOops -UseCompressedClassPointers"); + System.out.println("Run with SerialGC, +UseCompressedOops"); out = TestCommon .exec(helloJar, "-XX:+UseSerialGC", "-XX:+UseCompressedOops", - "-XX:-UseCompressedClassPointers", compactHeaders, "-Xlog:cds", "Hello"); @@ -141,39 +123,5 @@ public class TestZGCWithCDS { out.shouldContain(ERR_MSG); out.shouldHaveExitValue(1); - System.out.println("6. Run with +UseCompressedOops +UseCompressedClassPointers"); - out = TestCommon - .exec(helloJar, - "-XX:+UseSerialGC", - "-XX:+UseCompressedOops", - "-XX:+UseCompressedClassPointers", - compactHeaders, - "-Xlog:cds", - "Hello"); - out.shouldContain(UNABLE_TO_USE_ARCHIVE); - out.shouldContain(ERR_MSG); - out.shouldHaveExitValue(1); - - System.out.println("7. Dump with -UseCompressedOops -UseCompressedClassPointers"); - out = TestCommon - .dump(helloJar, - new String[] {"Hello"}, - "-XX:+UseSerialGC", - "-XX:-UseCompressedOops", - "-XX:+UseCompressedClassPointers", - compactHeaders, - "-Xlog:cds"); - out.shouldContain("Dumping shared data to file:"); - out.shouldHaveExitValue(0); - - System.out.println("8. Run with ZGC"); - out = TestCommon - .exec(helloJar, - "-XX:+UseZGC", - compactHeaders, - "-Xlog:cds", - "Hello"); - out.shouldContain(HELLO); - out.shouldHaveExitValue(0); } } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/OldClassSupport2.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/OldClassSupport2.java index 16a4d258e4f..b0db450e352 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/OldClassSupport2.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/OldClassSupport2.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * 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,11 +53,6 @@ public class OldClassSupport2 { // This will disable AOT class linking. Tester tester2 = new Tester("-Djdk.module.showModuleResolution=true"); tester2.run(new String[] {"AOT", "--two-step-training"} ); - - // Heap archiving is disable with -XX:-UseCompressedClassPointers. - // This will disable AOT class linking. - Tester tester3 = new Tester("-XX:-UseCompressedClassPointers"); - tester3.run(new String[] {"AOT", "--two-step-training"} ); } static class Tester extends CDSAppTester { diff --git a/test/hotspot/jtreg/runtime/cds/appcds/cacheObject/DifferentHeapSizes.java b/test/hotspot/jtreg/runtime/cds/appcds/cacheObject/DifferentHeapSizes.java index aeeac7ee0a4..fbf84a2a42d 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/cacheObject/DifferentHeapSizes.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/cacheObject/DifferentHeapSizes.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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 DifferentHeapSizes { } else { result .assertAbnormalExit("Unable to use shared archive.", - "The saved state of UseCompressedOops and UseCompressedClassPointers is different from runtime, CDS will be disabled."); + "The saved state of UseCompressedOops (1) is different from runtime (0), CDS will be disabled."); } } } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/CDSStreamTestDriver.java b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/CDSStreamTestDriver.java index 88af964d836..8d66ff3336f 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/CDSStreamTestDriver.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/CDSStreamTestDriver.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -69,7 +69,7 @@ public class CDSStreamTestDriver extends DynamicArchiveTestBase { } catch (SkippedException s) { if (GC.Z.isSelected() && s.toString().equals(skippedException)) { System.out.println("Got " + s.toString() + " as expected."); - System.out.println("Because the test was run with ZGC with UseCompressedOops and UseCompressedClassPointers disabled,"); + System.out.println("Because the test was run with ZGC with UseCompressedOops disabled,"); System.out.println("but the base archive was created with the options enabled"); } else { throw new RuntimeException("Archive mapping should always succeed after JDK-8231610 (did the machine run out of memory?)"); diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/DynamicArchiveTestBase.java b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/DynamicArchiveTestBase.java index 108002246db..8ee3b405604 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/DynamicArchiveTestBase.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/DynamicArchiveTestBase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -306,9 +306,8 @@ class DynamicArchiveTestBase { * the JDK was built via cross-compilation on a different platform; * - the VM under test was started with a different options than the ones * when the default CDS archive was built. E.g. the VM was started with - * -XX:+UseZGC which implicitly disabled the UseCompressedOoops and the - * UseCompressedClassPointers options. Those "compressed" options were - * enabled when the default CDS archive was built. + * -XX:+UseZGC which implicitly disables the UseCompressedOops option. + * UseCompressedOops was enabled when the default CDS archive was built. */ public static boolean isUseSharedSpacesDisabled() { return !WB.isSharingEnabled(); diff --git a/test/hotspot/jtreg/runtime/cds/appcds/sharedStrings/IncompatibleOptions.java b/test/hotspot/jtreg/runtime/cds/appcds/sharedStrings/IncompatibleOptions.java index ddbfe2ed862..f2ec33cdefe 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/sharedStrings/IncompatibleOptions.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/sharedStrings/IncompatibleOptions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -83,7 +83,9 @@ public class IncompatibleOptions { static final String COMPACT_STRING_MISMATCH = "The shared archive file's CompactStrings setting .* does not equal the current CompactStrings setting"; static final String COMPRESSED_OOPS_NOT_CONSISTENT = - "The saved state of UseCompressedOops and UseCompressedClassPointers is different from runtime, CDS will be disabled."; + "The saved state of UseCompressedOops \\(%d\\) is different from runtime \\(%d\\), CDS will be disabled."; + static final String COMPRESSED_OOPS_NOT_CONSISTENT_10 = COMPRESSED_OOPS_NOT_CONSISTENT.formatted(1, 0); + static final String COMPRESSED_OOPS_NOT_CONSISTENT_01 = COMPRESSED_OOPS_NOT_CONSISTENT.formatted(0, 1); static String appJar; static String[] vmOptionsPrefix = {}; @@ -117,7 +119,7 @@ public class IncompatibleOptions { // Explicitly archive with compressed oops, run without. testDump(3, "-XX:+UseG1GC", "-XX:+UseCompressedOops", null, false); - testExec(3, "-XX:+UseG1GC", "-XX:-UseCompressedOops", COMPRESSED_OOPS_NOT_CONSISTENT, true); + testExec(3, "-XX:+UseG1GC", "-XX:-UseCompressedOops", COMPRESSED_OOPS_NOT_CONSISTENT_10, true); // NOTE: No warning is displayed, by design // Still run, to ensure no crash or exception @@ -130,14 +132,14 @@ public class IncompatibleOptions { testExec(4, "-XX:+UseSerialGC", "", "", false); if (GC.Z.isSupported()) { - testExec(4, "-XX:+UseZGC", "", COMPRESSED_OOPS_NOT_CONSISTENT, true); + testExec(4, "-XX:+UseZGC", "", COMPRESSED_OOPS_NOT_CONSISTENT_10, true); } // Explicitly archive with object streaming and COOPs with one GC, run with other GCs. testDump(4, "-XX:-UseCompressedOops", "-XX:+AOTStreamableObjects", null, false); - testExec(4, "-XX:+UseG1GC", "", COMPRESSED_OOPS_NOT_CONSISTENT, true); - testExec(4, "-XX:+UseParallelGC", "", COMPRESSED_OOPS_NOT_CONSISTENT, true); - testExec(4, "-XX:+UseSerialGC", "", COMPRESSED_OOPS_NOT_CONSISTENT, true); + testExec(4, "-XX:+UseG1GC", "", COMPRESSED_OOPS_NOT_CONSISTENT_01, true); + testExec(4, "-XX:+UseParallelGC", "", COMPRESSED_OOPS_NOT_CONSISTENT_01, true); + testExec(4, "-XX:+UseSerialGC", "", COMPRESSED_OOPS_NOT_CONSISTENT_01, true); testExec(4, "-XX:+UseParallelGC", "-XX:-UseCompressedOops", "", false); testExec(4, "-XX:+UseSerialGC", "-XX:-UseCompressedOops", "", false); diff --git a/test/hotspot/jtreg/serviceability/dcmd/vm/ClassLoaderStatsTest.java b/test/hotspot/jtreg/serviceability/dcmd/vm/ClassLoaderStatsTest.java index a89f2508852..aaf54e03f9e 100644 --- a/test/hotspot/jtreg/serviceability/dcmd/vm/ClassLoaderStatsTest.java +++ b/test/hotspot/jtreg/serviceability/dcmd/vm/ClassLoaderStatsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * 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,17 +32,6 @@ * @run testng/othervm --add-exports=java.base/jdk.internal.misc=ALL-UNNAMED --add-exports=jdk.internal.jvmstat/sun.jvmstat.monitor=ALL-UNNAMED ClassLoaderStatsTest */ -/* - * @test - * @summary Test of diagnostic command VM.classloader_stats (-UseCCP) - * @library /test/lib - * @requires vm.bits != "32" - * @modules java.base/jdk.internal.misc - * java.compiler - * java.management - * jdk.internal.jvmstat/sun.jvmstat.monitor - * @run testng/othervm -XX:-UseCompressedClassPointers --add-exports=java.base/jdk.internal.misc=ALL-UNNAMED --add-exports=jdk.internal.jvmstat/sun.jvmstat.monitor=ALL-UNNAMED ClassLoaderStatsTest - */ import org.testng.annotations.Test; import org.testng.Assert; @@ -110,7 +99,7 @@ public class ClassLoaderStatsTest { // Minimum expected sizes: initial capacity is governed by the chunk size of the first chunk, which // depends on the arena growth policy. Since this is a normal class loader, we expect as initial chunk - // size at least 4k (if UseCompressedClassPointers is off). + // size at least 4k. // Minimum used size is difficult to guess but should be at least 1k. // Maximum expected sizes: We just assume a reasonable maximum. We only loaded one class, so // we should not see values > 64k. diff --git a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestIRMatching.java b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestIRMatching.java index fc8a92cf9a2..e4111238b59 100644 --- a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestIRMatching.java +++ b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestIRMatching.java @@ -165,25 +165,6 @@ public class TestIRMatching { BadFailOnConstraint.create(RunTests.class, "bad1", 2, "Load") ); - runCheck(new String[] {"-XX:+IgnoreUnrecognizedVMOptions", "-XX:-UseCompressedClassPointers"}, - BadFailOnConstraint.create(Loads.class, "load", 1, 1, "Load"), - BadFailOnConstraint.create(Loads.class, "load", 1, 3, "LoadI"), - BadCountsConstraint.create(Loads.class, "load", 1, 1, 0), - BadCountsConstraint.create(Loads.class, "load", 1, 2, 1,"Load"), - GoodRuleConstraint.create(Loads.class, "load", 2), - GoodFailOnConstraint.create(Loads.class, "load", 3), - BadCountsConstraint.create(Loads.class, "load", 3, 2, 2,"Store"), - BadFailOnConstraint.create(Loads.class, "load", 4, 2, "Store"), - BadFailOnConstraint.create(Loads.class, "load", 5, "Load"), - BadFailOnConstraint.create(Loads.class, "load", 6, "Load"), - BadFailOnConstraint.create(Loads.class, "load", 7, "Load"), - GoodRuleConstraint.create(Loads.class, "load", 8), - GoodRuleConstraint.create(Loads.class, "load", 9), - GoodRuleConstraint.create(Loads.class, "load", 10), - BadFailOnConstraint.create(Loads.class, "loadKlass", 1), - BadCountsConstraint.create(Loads.class, "loadKlass", 2, 2,"Field") - ); - // Loops runCheck(BadFailOnConstraint.create(Loops.class, "loop", 1, "Loop"), GoodRuleConstraint.create(Loops.class, "loop", 2), diff --git a/test/jdk/java/lang/instrument/GetObjectSizeIntrinsicsTest.java b/test/jdk/java/lang/instrument/GetObjectSizeIntrinsicsTest.java index 44276a9f7f5..cdaa94e8289 100644 --- a/test/jdk/java/lang/instrument/GetObjectSizeIntrinsicsTest.java +++ b/test/jdk/java/lang/instrument/GetObjectSizeIntrinsicsTest.java @@ -314,8 +314,9 @@ public class GetObjectSizeIntrinsicsTest extends ASimpleInstrumentationTestCase static final int LARGE_INT_ARRAY_SIZE = 1024*1024*1024 + 1024; static final int LARGE_OBJ_ARRAY_SIZE = (4096/(int)REF_SIZE)*1024*1024 + 1024; - static final boolean CCP = WhiteBox.getWhiteBox().getBooleanVMFlag("UseCompressedClassPointers"); - static final int ARRAY_HEADER_SIZE = CCP ? 16 : (Platform.is64bit() ? 20 : 12); + // 64-bit: 8mw-4ccp-4len + // 32-bit: 4mw-4ccp-4len-4gap + static final int ARRAY_HEADER_SIZE = 16; final String mode; diff --git a/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationInNewTLABEvent.java b/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationInNewTLABEvent.java index 9112cfbc247..9cc3141cd2d 100644 --- a/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationInNewTLABEvent.java +++ b/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationInNewTLABEvent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2026, Oracle and/or its affiliates. All rights reserved. * 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,9 +64,10 @@ import jdk.test.whitebox.WhiteBox; public class TestObjectAllocationInNewTLABEvent { private final static String EVENT_NAME = EventNames.ObjectAllocationInNewTLAB; - private static final Boolean COMPRESSED_CLASS_PTRS = WhiteBox.getWhiteBox().getBooleanVMFlag("UseCompressedClassPointers"); - - private static final int BYTE_ARRAY_OVERHEAD = (Platform.is64bit() && !COMPRESSED_CLASS_PTRS) ? 24 : 16; + // 64-bit COH: MW8 + L4 + End Alignment = 16 + // 64-bit -COH: MW8 + K4 + L4 = 16 + // 32-bit : MW4 + K4 + L4 + End Alignment = 16 + private static final int BYTE_ARRAY_OVERHEAD = 16; private static final int OBJECT_SIZE = 128 * 1024; private static final int OBJECTS_TO_ALLOCATE = 100; diff --git a/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationOutsideTLABEvent.java b/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationOutsideTLABEvent.java index a7695b76849..9a4f0f28974 100644 --- a/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationOutsideTLABEvent.java +++ b/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationOutsideTLABEvent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2026, Oracle and/or its affiliates. All rights reserved. * 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,9 +64,10 @@ import jdk.test.whitebox.WhiteBox; public class TestObjectAllocationOutsideTLABEvent { private static final String EVENT_NAME = EventNames.ObjectAllocationOutsideTLAB; - private static final Boolean COMPRESSED_CLASS_PTRS = WhiteBox.getWhiteBox().getBooleanVMFlag("UseCompressedClassPointers"); - - private static final int BYTE_ARRAY_OVERHEAD = (Platform.is64bit() && !COMPRESSED_CLASS_PTRS) ? 24 : 16; + // 64-bit COH: MW8 + L4 + End Alignment = 16 + // 64-bit -COH: MW8 + K4 + L4 = 16 + // 32-bit : MW4 + K4 + L4 + End Alignment = 16 + private static final int BYTE_ARRAY_OVERHEAD = 16; private static final int OBJECT_SIZE = 128 * 1024; private static final int OBJECTS_TO_ALLOCATE = 100; diff --git a/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationSampleEventThrottling.java b/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationSampleEventThrottling.java index 47f5b31f881..214f7336a73 100644 --- a/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationSampleEventThrottling.java +++ b/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationSampleEventThrottling.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * 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,9 +52,10 @@ import jdk.test.whitebox.WhiteBox; public class TestObjectAllocationSampleEventThrottling { private static final String EVENT_NAME = EventNames.ObjectAllocationSample; - private static final Boolean COMPRESSED_CLASS_PTRS = WhiteBox.getWhiteBox().getBooleanVMFlag("UseCompressedClassPointers"); - - private static final int BYTE_ARRAY_OVERHEAD = (Platform.is64bit() && !COMPRESSED_CLASS_PTRS) ? 24 : 16; + // 64-bit COH: MW8 + L4 + End Alignment = 16 + // 64-bit -COH: MW8 + K4 + L4 = 16 + // 32-bit : MW4 + K4 + L4 + End Alignment = 16 + private static final int BYTE_ARRAY_OVERHEAD = 16; private static final int OBJECT_SIZE = 128 * 1024; private static final int OBJECTS_TO_ALLOCATE = 100; diff --git a/test/jdk/jdk/jfr/event/gc/heapsummary/TestHeapSummaryEventDefNewSerial.java b/test/jdk/jdk/jfr/event/gc/heapsummary/TestHeapSummaryEventDefNewSerial.java index f70d7a85f16..b880bd93bc5 100644 --- a/test/jdk/jdk/jfr/event/gc/heapsummary/TestHeapSummaryEventDefNewSerial.java +++ b/test/jdk/jdk/jfr/event/gc/heapsummary/TestHeapSummaryEventDefNewSerial.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2026, Oracle and/or its affiliates. All rights reserved. * 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,16 +33,6 @@ import jdk.test.lib.jfr.GCHelper; * @run main/othervm -XX:+UseSerialGC jdk.jfr.event.gc.heapsummary.TestHeapSummaryEventDefNewSerial */ -/** - * @test - * @bug 8264008 - * @requires vm.flagless - * @requires vm.hasJFR & vm.bits == 64 - * @requires vm.gc == "Serial" | vm.gc == null - * @library /test/lib /test/jdk - * @run main/othervm -XX:+UseSerialGC -XX:-UseCompressedClassPointers - * jdk.jfr.event.gc.heapsummary.TestHeapSummaryEventDefNewSerial - */ public class TestHeapSummaryEventDefNewSerial { public static void main(String[] args) throws Exception { HeapSummaryEventAllGcs.test(GCHelper.gcDefNew, GCHelper.gcSerialOld); diff --git a/test/jdk/jdk/jfr/event/gc/objectcount/ObjectCountEventVerifier.java b/test/jdk/jdk/jfr/event/gc/objectcount/ObjectCountEventVerifier.java index 0ab663f130a..d7e6b3209d3 100644 --- a/test/jdk/jdk/jfr/event/gc/objectcount/ObjectCountEventVerifier.java +++ b/test/jdk/jdk/jfr/event/gc/objectcount/ObjectCountEventVerifier.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2026, Oracle and/or its affiliates. All rights reserved. * 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 ObjectCountEventVerifier { private static long expectedFooArraySize(long count) { boolean runsOn32Bit = System.getProperty("sun.arch.data.model").equals("32"); int bytesPerWord = runsOn32Bit ? 4 : 8; - int objectHeaderSize = bytesPerWord * 3; // length will be aligned on 64 bits + int objectHeaderSize = runsOn32Bit ? 12 : 16; int alignmentInOopArray = runsOn32Bit ? 4 : 0; int ptrSize = bytesPerWord; return objectHeaderSize + alignmentInOopArray + count * ptrSize; diff --git a/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountAfterGCEventWithG1ConcurrentMark.java b/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountAfterGCEventWithG1ConcurrentMark.java index eb69289aa5e..fbf2d8b543d 100644 --- a/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountAfterGCEventWithG1ConcurrentMark.java +++ b/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountAfterGCEventWithG1ConcurrentMark.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2026, Oracle and/or its affiliates. All rights reserved. * 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 jdk.test.lib.jfr.GCHelper; * @requires (vm.gc == "G1" | vm.gc == null) * & vm.opt.ExplicitGCInvokesConcurrent != false * @library /test/lib /test/jdk - * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseG1GC -XX:+ExplicitGCInvokesConcurrent -XX:MarkSweepDeadRatio=0 -XX:-UseCompressedOops -XX:-UseCompressedClassPointers -XX:+IgnoreUnrecognizedVMOptions jdk.jfr.event.gc.objectcount.TestObjectCountAfterGCEventWithG1ConcurrentMark + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseG1GC -XX:+ExplicitGCInvokesConcurrent -XX:MarkSweepDeadRatio=0 -XX:-UseCompressedOops -XX:+IgnoreUnrecognizedVMOptions jdk.jfr.event.gc.objectcount.TestObjectCountAfterGCEventWithG1ConcurrentMark */ public class TestObjectCountAfterGCEventWithG1ConcurrentMark { public static void main(String[] args) throws Exception { diff --git a/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountAfterGCEventWithG1FullCollection.java b/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountAfterGCEventWithG1FullCollection.java index 6e91cf4c644..758ab6988b5 100644 --- a/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountAfterGCEventWithG1FullCollection.java +++ b/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountAfterGCEventWithG1FullCollection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2026, Oracle and/or its affiliates. All rights reserved. * 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 jdk.test.lib.jfr.GCHelper; * @requires (vm.gc == "G1" | vm.gc == null) * & vm.opt.ExplicitGCInvokesConcurrent != true * @library /test/lib /test/jdk - * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -XX:+UseG1GC -XX:MarkSweepDeadRatio=0 -XX:-UseCompressedOops -XX:-UseCompressedClassPointers -XX:+IgnoreUnrecognizedVMOptions jdk.jfr.event.gc.objectcount.TestObjectCountAfterGCEventWithG1FullCollection + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -XX:+UseG1GC -XX:MarkSweepDeadRatio=0 -XX:-UseCompressedOops -XX:+IgnoreUnrecognizedVMOptions jdk.jfr.event.gc.objectcount.TestObjectCountAfterGCEventWithG1FullCollection */ public class TestObjectCountAfterGCEventWithG1FullCollection { public static void main(String[] args) throws Exception { diff --git a/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountAfterGCEventWithParallelOld.java b/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountAfterGCEventWithParallelOld.java index 2a17e540be8..ac43d0d24e4 100644 --- a/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountAfterGCEventWithParallelOld.java +++ b/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountAfterGCEventWithParallelOld.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2026, Oracle and/or its affiliates. All rights reserved. * 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 jdk.test.lib.jfr.GCHelper; * @requires vm.hasJFR * @requires vm.gc == "Parallel" | vm.gc == null * @library /test/lib /test/jdk - * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -XX:+UseParallelGC -XX:MarkSweepDeadRatio=0 -XX:-UseCompressedOops -XX:-UseCompressedClassPointers -XX:+IgnoreUnrecognizedVMOptions jdk.jfr.event.gc.objectcount.TestObjectCountAfterGCEventWithParallelOld + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -XX:+UseParallelGC -XX:MarkSweepDeadRatio=0 -XX:-UseCompressedOops -XX:+IgnoreUnrecognizedVMOptions jdk.jfr.event.gc.objectcount.TestObjectCountAfterGCEventWithParallelOld */ public class TestObjectCountAfterGCEventWithParallelOld { public static void main(String[] args) throws Exception { diff --git a/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountAfterGCEventWithSerial.java b/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountAfterGCEventWithSerial.java index 888eb089027..eac0e935fea 100644 --- a/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountAfterGCEventWithSerial.java +++ b/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountAfterGCEventWithSerial.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2026, Oracle and/or its affiliates. All rights reserved. * 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 jdk.test.lib.jfr.GCHelper; * @requires vm.hasJFR * @requires vm.gc == "Serial" | vm.gc == null * @library /test/lib /test/jdk - * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -XX:+UseSerialGC -XX:MarkSweepDeadRatio=0 -XX:-UseCompressedOops -XX:-UseCompressedClassPointers -XX:+IgnoreUnrecognizedVMOptions jdk.jfr.event.gc.objectcount.TestObjectCountAfterGCEventWithSerial + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -XX:+UseSerialGC -XX:MarkSweepDeadRatio=0 -XX:-UseCompressedOops -XX:+IgnoreUnrecognizedVMOptions jdk.jfr.event.gc.objectcount.TestObjectCountAfterGCEventWithSerial */ public class TestObjectCountAfterGCEventWithSerial { public static void main(String[] args) throws Exception { diff --git a/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountEvent.java b/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountEvent.java index a9034ba0eaa..0a5d48e83c8 100644 --- a/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountEvent.java +++ b/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountEvent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2026, Oracle and/or its affiliates. All rights reserved. * 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 jdk.test.lib.jfr.Events; * @requires vm.hasJFR * @requires vm.gc == "Serial" | vm.gc == null * @library /test/lib /test/jdk - * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -XX:+UseSerialGC -XX:-UseCompressedOops -XX:-UseCompressedClassPointers -XX:MarkSweepDeadRatio=0 -XX:+IgnoreUnrecognizedVMOptions jdk.jfr.event.gc.objectcount.TestObjectCountEvent + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -XX:+UseSerialGC -XX:-UseCompressedOops -XX:MarkSweepDeadRatio=0 -XX:+IgnoreUnrecognizedVMOptions jdk.jfr.event.gc.objectcount.TestObjectCountEvent */ public class TestObjectCountEvent { private static final String objectCountEventPath = EventNames.ObjectCount; diff --git a/test/jtreg-ext/requires/VMProps.java b/test/jtreg-ext/requires/VMProps.java index 2d604a92b75..16fd32e626b 100644 --- a/test/jtreg-ext/requires/VMProps.java +++ b/test/jtreg-ext/requires/VMProps.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -474,8 +474,7 @@ public class VMProps implements Callable> { /** * @return true if it's possible for "java -Xshare:dump" to write Java heap objects - * with the current set of jtreg VM options. For example, false will be returned - * if -XX:-UseCompressedClassPointers is specified. + * with the current set of jtreg VM options. */ protected String vmCDSCanWriteArchivedJavaHeap() { return "" + ("true".equals(vmCDS()) && WB.canWriteJavaHeapArchive()); @@ -483,8 +482,7 @@ public class VMProps implements Callable> { /** * @return true if it's possible for "java -Xshare:dump" to write Java heap objects - * with the current set of jtreg VM options. For example, false will be returned - * if -XX:-UseCompressedClassPointers is specified. + * with the current set of jtreg VM options. */ protected String vmCDSCanWriteMappedArchivedJavaHeap() { return "" + ("true".equals(vmCDS()) && WB.canWriteMappedJavaHeapArchive()); @@ -492,8 +490,7 @@ public class VMProps implements Callable> { /** * @return true if it's possible for "java -Xshare:dump" to write Java heap objects - * with the current set of jtreg VM options. For example, false will be returned - * if -XX:-UseCompressedClassPointers is specified. + * with the current set of jtreg VM options. */ protected String vmCDSCanWriteStreamedArchivedJavaHeap() { return "" + ("true".equals(vmCDS()) && WB.canWriteStreamedJavaHeapArchive()); From e07ab7fb9b5e49093f84b05fb6cecfa00f1b0f52 Mon Sep 17 00:00:00 2001 From: Arno Zeller Date: Thu, 26 Mar 2026 11:17:18 +0000 Subject: [PATCH 047/359] 8380288: [BACKOUT] Incorrect Interpretation of POSIX TZ Environment Variable on AIX Reviewed-by: mbaesken, mdoerr --- .../unix/native/libjava/TimeZone_md.c | 66 +++++++------------ 1 file changed, 22 insertions(+), 44 deletions(-) diff --git a/src/java.base/unix/native/libjava/TimeZone_md.c b/src/java.base/unix/native/libjava/TimeZone_md.c index 39e7b726220..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, 2026, 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 @@ -352,15 +352,33 @@ getPlatformTimeZoneID() } static char * -getJavaTimezoneFromPlatform(const char *tz_buf, size_t tz_len, const char *mapfilename) { +mapPlatformToJavaTimezone(const char *java_home_dir, const char *tz) { FILE *tzmapf; + char mapfilename[PATH_MAX + 1]; char line[256]; int linecount = 0; + char *tz_buf = NULL; + char *temp_tz = NULL; char *javatz = NULL; + size_t tz_len = 0; + /* On AIX, the TZ environment variable may end with a comma + * followed by modifier fields until early AIX6.1. + * This restriction has been removed from AIX7. */ + + tz_buf = strdup(tz); + tz_len = strlen(tz_buf); + + /* Open tzmappings file, with buffer overrun check */ + if ((strlen(java_home_dir) + 15) > PATH_MAX) { + jio_fprintf(stderr, "Path %s/lib/tzmappings exceeds maximum path length\n", java_home_dir); + goto tzerr; + } + strcpy(mapfilename, java_home_dir); + strcat(mapfilename, "/lib/tzmappings"); if ((tzmapf = fopen(mapfilename, "r")) == NULL) { jio_fprintf(stderr, "can't open %s\n", mapfilename); - return NULL; + goto tzerr; } while (fgets(line, sizeof(line), tzmapf) != NULL) { @@ -413,50 +431,10 @@ getJavaTimezoneFromPlatform(const char *tz_buf, size_t tz_len, const char *mapfi break; } } - (void) fclose(tzmapf); - return javatz; -} - -static char * -mapPlatformToJavaTimezone(const char *java_home_dir, const char *tz) { - char mapfilename[PATH_MAX + 1]; - char *tz_buf = NULL; - char *javatz = NULL; - char *temp_tz = NULL; - size_t tz_len = 0; - - /* On AIX, the TZ environment variable may end with a comma - * followed by modifier fields until early AIX6.1. - * This restriction has been removed from AIX7. */ - - tz_buf = strdup(tz); - tz_len = strlen(tz_buf); - - /* Open tzmappings file, with buffer overrun check */ - if ((strlen(java_home_dir) + 15) > PATH_MAX) { - jio_fprintf(stderr, "Path %s/lib/tzmappings exceeds maximum path length\n", java_home_dir); - goto tzerr; - } - strcpy(mapfilename, java_home_dir); - strcat(mapfilename, "/lib/tzmappings"); - - // First attempt to find the Java timezone for the full tz string - javatz = getJavaTimezoneFromPlatform(tz_buf, tz_len, mapfilename); - - // If no match was found, check for timezone with truncated value - if (javatz == NULL) { - temp_tz = strchr(tz, ','); - tz_len = (temp_tz == NULL) ? strlen(tz) : temp_tz - tz; - free((void *) tz_buf); - tz_buf = (char *)malloc(tz_len + 1); - memcpy(tz_buf, tz, tz_len); - tz_buf[tz_len] = '\0'; - javatz = getJavaTimezoneFromPlatform(tz_buf, tz_len, mapfilename); - } tzerr: - if (tz_buf != NULL) { + if (tz_buf != NULL ) { free((void *) tz_buf); } From 407b677d5fe20f1958f530207e62234d510daca4 Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Thu, 26 Mar 2026 11:41:10 +0000 Subject: [PATCH 048/359] 8380942: Fix whitespace and conditional logic in interpreter code Reviewed-by: dholmes, aartemov --- src/hotspot/share/interpreter/interpreterRuntime.cpp | 8 +++----- src/hotspot/share/interpreter/linkResolver.cpp | 10 +++++----- src/hotspot/share/interpreter/oopMapCache.cpp | 10 +++++----- 3 files changed, 13 insertions(+), 15 deletions(-) diff --git a/src/hotspot/share/interpreter/interpreterRuntime.cpp b/src/hotspot/share/interpreter/interpreterRuntime.cpp index 59d5f29023c..e7b35b121a2 100644 --- a/src/hotspot/share/interpreter/interpreterRuntime.cpp +++ b/src/hotspot/share/interpreter/interpreterRuntime.cpp @@ -243,9 +243,9 @@ JRT_ENTRY(void, InterpreterRuntime::multianewarray(JavaThread* current, jint* fi // We may want to pass in more arguments - could make this slightly faster LastFrameAccessor last_frame(current); ConstantPool* constants = last_frame.method()->constants(); - int i = last_frame.get_index_u2(Bytecodes::_multianewarray); - Klass* klass = constants->klass_at(i, CHECK); - int nof_dims = last_frame.number_of_dimensions(); + int i = last_frame.get_index_u2(Bytecodes::_multianewarray); + Klass* klass = constants->klass_at(i, CHECK); + int nof_dims = last_frame.number_of_dimensions(); assert(klass->is_klass(), "not a class"); assert(nof_dims >= 1, "multianewarray rank must be nonzero"); @@ -756,12 +756,10 @@ JRT_LEAF(void, InterpreterRuntime::monitorexit(BasicObjectLock* elem)) elem->set_obj(nullptr); JRT_END - JRT_ENTRY(void, InterpreterRuntime::throw_illegal_monitor_state_exception(JavaThread* current)) THROW(vmSymbols::java_lang_IllegalMonitorStateException()); JRT_END - JRT_ENTRY(void, InterpreterRuntime::new_illegal_monitor_state_exception(JavaThread* current)) // Returns an illegal exception to install into the current thread. The // pending_exception flag is cleared so normal exception handling does not diff --git a/src/hotspot/share/interpreter/linkResolver.cpp b/src/hotspot/share/interpreter/linkResolver.cpp index c82398b654c..25fff580c9d 100644 --- a/src/hotspot/share/interpreter/linkResolver.cpp +++ b/src/hotspot/share/interpreter/linkResolver.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1045,7 +1045,7 @@ void LinkResolver::resolve_field(fieldDescriptor& fd, stringStream ss; ss.print("Update to %s final field %s.%s attempted from a different class (%s) than the field's declaring class", is_static ? "static" : "non-static", resolved_klass->external_name(), fd.name()->as_C_string(), - current_klass->external_name()); + current_klass->external_name()); THROW_MSG(vmSymbols::java_lang_IllegalAccessError(), ss.as_string()); } @@ -1260,7 +1260,7 @@ void LinkResolver::runtime_resolve_special_method(CallInfo& result, methodHandle sel_method(THREAD, resolved_method()); if (link_info.check_access() && - // check if the method is not + // check if the method is not , which is never inherited resolved_method->name() != vmSymbols::object_initializer_name()) { Klass* current_klass = link_info.current_klass(); @@ -1724,8 +1724,8 @@ void LinkResolver::resolve_invoke(CallInfo& result, Handle recv, const constantP } void LinkResolver::resolve_invoke(CallInfo& result, Handle& recv, - const methodHandle& attached_method, - Bytecodes::Code byte, TRAPS) { + const methodHandle& attached_method, + Bytecodes::Code byte, TRAPS) { Klass* defc = attached_method->method_holder(); Symbol* name = attached_method->name(); Symbol* type = attached_method->signature(); diff --git a/src/hotspot/share/interpreter/oopMapCache.cpp b/src/hotspot/share/interpreter/oopMapCache.cpp index d7c02296f33..5a1ad7b7883 100644 --- a/src/hotspot/share/interpreter/oopMapCache.cpp +++ b/src/hotspot/share/interpreter/oopMapCache.cpp @@ -256,8 +256,8 @@ bool OopMapCacheEntry::verify_mask(CellTypeState* vars, CellTypeState* stack, in if (log) st.print("Locals (%d): ", max_locals); for(int i = 0; i < max_locals; i++) { - bool v1 = is_oop(i) ? true : false; - bool v2 = vars[i].is_reference() ? true : false; + bool v1 = is_oop(i); + bool v2 = vars[i].is_reference(); assert(v1 == v2, "locals oop mask generation error"); if (log) st.print("%d", v1 ? 1 : 0); } @@ -265,8 +265,8 @@ bool OopMapCacheEntry::verify_mask(CellTypeState* vars, CellTypeState* stack, in if (log) st.print("Stack (%d): ", stack_top); for(int j = 0; j < stack_top; j++) { - bool v1 = is_oop(max_locals + j) ? true : false; - bool v2 = stack[j].is_reference() ? true : false; + bool v1 = is_oop(max_locals + j); + bool v2 = stack[j].is_reference(); assert(v1 == v2, "stack oop mask generation error"); if (log) st.print("%d", v1 ? 1 : 0); } @@ -350,7 +350,7 @@ void OopMapCacheEntry::set_mask(CellTypeState *vars, CellTypeState *stack, int s } // set oop bit - if ( cell->is_reference()) { + if (cell->is_reference()) { value |= (mask << oop_bit_number ); _num_oops++; } From 60ce4857f406a3fe68be008ab1ca206b032412dc Mon Sep 17 00:00:00 2001 From: Daniel Fuchs Date: Thu, 26 Mar 2026 11:48:34 +0000 Subject: [PATCH 049/359] 8380931: Refactor remaining java/nio/channels TestNG tests to use JUnit Reviewed-by: alanb --- .../SocketChannel/AdaptorStreams.java | 81 +++-- .../SocketChannel/ConnectionReset.java | 22 +- .../SocketChannel/ReadWriteAfterClose.java | 54 +-- .../channels/etc/LocalSocketAddressType.java | 63 ++-- .../java/nio/channels/etc/OpenAndConnect.java | 199 ++++++----- .../nio/channels/etc/ProtocolFamilies.java | 239 ++++++------- .../unixdomain/EmptySunPathForSocketFile.java | 16 +- .../channels/unixdomain/FileAttributes.java | 27 +- .../nio/channels/unixdomain/IOExchanges.java | 328 ++++++++++-------- .../nio/channels/unixdomain/NullTest.java | 13 +- 10 files changed, 561 insertions(+), 481 deletions(-) diff --git a/test/jdk/java/nio/channels/SocketChannel/AdaptorStreams.java b/test/jdk/java/nio/channels/SocketChannel/AdaptorStreams.java index 3487ae45de1..240d9e3baf7 100644 --- a/test/jdk/java/nio/channels/SocketChannel/AdaptorStreams.java +++ b/test/jdk/java/nio/channels/SocketChannel/AdaptorStreams.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * 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 8222774 4430139 - * @run testng AdaptorStreams + * @run junit AdaptorStreams * @summary Exercise socket adaptor input/output streams */ @@ -44,77 +44,82 @@ import java.util.concurrent.Future; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; -import org.testng.annotations.Test; -import static org.testng.Assert.*; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; -@Test public class AdaptorStreams { /** * Test read when bytes are available */ + @Test public void testRead1() throws Exception { withConnection((sc, peer) -> { peer.getOutputStream().write(99); int n = sc.socket().getInputStream().read(); - assertEquals(n, 99); + assertEquals(99, n); }); } /** * Test read blocking before bytes are available */ + @Test public void testRead2() throws Exception { withConnection((sc, peer) -> { scheduleWrite(peer.getOutputStream(), 99, 1000); int n = sc.socket().getInputStream().read(); - assertEquals(n, 99); + assertEquals(99, n); }); } /** * Test read when peer has closed connection */ + @Test public void testRead3() throws Exception { withConnection((sc, peer) -> { peer.close(); int n = sc.socket().getInputStream().read(); - assertEquals(n, -1); + assertEquals(-1, n); }); } /** * Test read blocking before peer closes connection */ + @Test public void testRead4() throws Exception { withConnection((sc, peer) -> { scheduleClose(peer, 1000); int n = sc.socket().getInputStream().read(); - assertEquals(n, -1); + assertEquals(-1, n); }); } /** * Test async close of socket when thread blocked in read */ + @Test public void testRead5() throws Exception { withConnection((sc, peer) -> { scheduleClose(sc, 2000); InputStream in = sc.socket().getInputStream(); - expectThrows(IOException.class, () -> in.read()); + assertThrows(IOException.class, () -> in.read()); }); } /** * Test interrupted status set before read */ + @Test public void testRead6() throws Exception { withConnection((sc, peer) -> { Socket s = sc.socket(); Thread.currentThread().interrupt(); try { InputStream in = s.getInputStream(); - expectThrows(IOException.class, () -> in.read()); + assertThrows(IOException.class, () -> in.read()); } finally { Thread.interrupted(); // clear interrupt } @@ -125,13 +130,14 @@ public class AdaptorStreams { /** * Test interrupt of thread blocked in read */ + @Test public void testRead7() throws Exception { withConnection((sc, peer) -> { Future interrupter = scheduleInterrupt(Thread.currentThread(), 2000); Socket s = sc.socket(); try { InputStream in = s.getInputStream(); - expectThrows(IOException.class, () -> in.read()); + assertThrows(IOException.class, () -> in.read()); } finally { interrupter.cancel(true); Thread.interrupted(); // clear interrupt @@ -143,68 +149,74 @@ public class AdaptorStreams { /** * Test read when channel is configured non-blocking */ + @Test public void testRead8() throws Exception { withConnection((sc, peer) -> { sc.configureBlocking(false); InputStream in = sc.socket().getInputStream(); - expectThrows(IllegalBlockingModeException.class, () -> in.read()); + assertThrows(IllegalBlockingModeException.class, () -> in.read()); }); } /** * Test timed read when bytes are available */ + @Test public void testTimedRead1() throws Exception { withConnection((sc, peer) -> { peer.getOutputStream().write(99); Socket s = sc.socket(); s.setSoTimeout(60_000); int n = s.getInputStream().read(); - assertEquals(n, 99); + assertEquals(99, n); }); } /** * Test timed read blocking before bytes are available */ + @Test public void testTimedRead2() throws Exception { withConnection((sc, peer) -> { scheduleWrite(peer.getOutputStream(), 99, 1000); Socket s = sc.socket(); s.setSoTimeout(60_000); int n = s.getInputStream().read(); - assertEquals(n, 99); + assertEquals(99, n); }); } /** * Test timed read when the read times out */ + @Test public void testTimedRead3() throws Exception { withConnection((sc, peer) -> { Socket s = sc.socket(); s.setSoTimeout(500); InputStream in = s.getInputStream(); - expectThrows(SocketTimeoutException.class, () -> in.read()); + assertThrows(SocketTimeoutException.class, () -> in.read()); }); } /** * Test async close of socket when thread blocked in timed read */ + @Test public void testTimedRead4() throws Exception { withConnection((sc, peer) -> { scheduleClose(sc, 2000); Socket s = sc.socket(); s.setSoTimeout(60_000); InputStream in = s.getInputStream(); - expectThrows(IOException.class, () -> in.read()); + assertThrows(IOException.class, () -> in.read()); }); } /** * Test interrupted status set before timed read */ + @Test public void testTimedRead5() throws Exception { withConnection((sc, peer) -> { Socket s = sc.socket(); @@ -212,7 +224,7 @@ public class AdaptorStreams { try { s.setSoTimeout(60_000); InputStream in = s.getInputStream(); - expectThrows(IOException.class, () -> in.read()); + assertThrows(IOException.class, () -> in.read()); } finally { Thread.interrupted(); // clear interrupt } @@ -223,6 +235,7 @@ public class AdaptorStreams { /** * Test interrupt of thread blocked in timed read */ + @Test public void testTimedRead6() throws Exception { withConnection((sc, peer) -> { Future interrupter = scheduleInterrupt(Thread.currentThread(), 2000); @@ -230,7 +243,7 @@ public class AdaptorStreams { try { s.setSoTimeout(60_000); InputStream in = s.getInputStream(); - expectThrows(IOException.class, () -> in.read()); + assertThrows(IOException.class, () -> in.read()); assertTrue(s.isClosed()); } finally { interrupter.cancel(true); @@ -243,10 +256,11 @@ public class AdaptorStreams { /** * Test async close of socket when thread blocked in write */ + @Test public void testWrite1() throws Exception { withConnection((sc, peer) -> { scheduleClose(sc, 2000); - expectThrows(IOException.class, () -> { + assertThrows(IOException.class, () -> { OutputStream out = sc.socket().getOutputStream(); byte[] data = new byte[64*1000]; while (true) { @@ -259,13 +273,14 @@ public class AdaptorStreams { /** * Test interrupted status set before write */ + @Test public void testWrite2() throws Exception { withConnection((sc, peer) -> { Socket s = sc.socket(); Thread.currentThread().interrupt(); try { OutputStream out = s.getOutputStream(); - expectThrows(IOException.class, () -> out.write(99)); + assertThrows(IOException.class, () -> out.write(99)); } finally { Thread.interrupted(); // clear interrupt } @@ -276,12 +291,13 @@ public class AdaptorStreams { /** * Test interrupt of thread blocked in write */ + @Test public void testWrite3() throws Exception { withConnection((sc, peer) -> { Future interrupter = scheduleInterrupt(Thread.currentThread(), 2000); Socket s = sc.socket(); try { - expectThrows(IOException.class, () -> { + assertThrows(IOException.class, () -> { OutputStream out = sc.socket().getOutputStream(); byte[] data = new byte[64*1000]; while (true) { @@ -299,11 +315,12 @@ public class AdaptorStreams { /** * Test write when channel is configured non-blocking */ + @Test public void testWrite4() throws Exception { withConnection((sc, peer) -> { sc.configureBlocking(false); OutputStream out = sc.socket().getOutputStream(); - expectThrows(IllegalBlockingModeException.class, () -> out.write(99)); + assertThrows(IllegalBlockingModeException.class, () -> out.write(99)); }); } @@ -311,6 +328,7 @@ public class AdaptorStreams { * Test read when there are bytes available and another thread is blocked * in write */ + @Test public void testConcurrentReadWrite1() throws Exception { withConnection((sc, peer) -> { Socket s = sc.socket(); @@ -328,13 +346,14 @@ public class AdaptorStreams { // test read when bytes are available peer.getOutputStream().write(99); int n = s.getInputStream().read(); - assertEquals(n, 99); + assertEquals(99, n); }); } /** * Test read blocking when another thread is blocked in write */ + @Test public void testConcurrentReadWrite2() throws Exception { withConnection((sc, peer) -> { Socket s = sc.socket(); @@ -352,13 +371,14 @@ public class AdaptorStreams { // test read blocking until bytes are available scheduleWrite(peer.getOutputStream(), 99, 500); int n = s.getInputStream().read(); - assertEquals(n, 99); + assertEquals(99, n); }); } /** * Test writing when another thread is blocked in read */ + @Test public void testConcurrentReadWrite3() throws Exception { withConnection((sc, peer) -> { Socket s = sc.socket(); @@ -372,7 +392,7 @@ public class AdaptorStreams { // test write s.getOutputStream().write(99); int n = peer.getInputStream().read(); - assertEquals(n, 99); + assertEquals(99, n); }); } @@ -380,6 +400,7 @@ public class AdaptorStreams { * Test timed read when there are bytes available and another thread is * blocked in write */ + @Test public void testConcurrentTimedReadWrite1() throws Exception { withConnection((sc, peer) -> { Socket s = sc.socket(); @@ -398,13 +419,14 @@ public class AdaptorStreams { peer.getOutputStream().write(99); s.setSoTimeout(60_000); int n = s.getInputStream().read(); - assertEquals(n, 99); + assertEquals(99, n); }); } /** * Test timed read blocking when another thread is blocked in write */ + @Test public void testConcurrentTimedReadWrite2() throws Exception { withConnection((sc, peer) -> { Socket s = sc.socket(); @@ -423,13 +445,14 @@ public class AdaptorStreams { scheduleWrite(peer.getOutputStream(), 99, 500); s.setSoTimeout(60_000); int n = s.getInputStream().read(); - assertEquals(n, 99); + assertEquals(99, n); }); } /** * Test writing when another thread is blocked in read */ + @Test public void testConcurrentTimedReadWrite3() throws Exception { withConnection((sc, peer) -> { Socket s = sc.socket(); @@ -444,7 +467,7 @@ public class AdaptorStreams { // test write s.getOutputStream().write(99); int n = peer.getInputStream().read(); - assertEquals(n, 99); + assertEquals(99, n); }); } diff --git a/test/jdk/java/nio/channels/SocketChannel/ConnectionReset.java b/test/jdk/java/nio/channels/SocketChannel/ConnectionReset.java index 759d819fa4f..2d89d708110 100644 --- a/test/jdk/java/nio/channels/SocketChannel/ConnectionReset.java +++ b/test/jdk/java/nio/channels/SocketChannel/ConnectionReset.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * 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,9 +21,9 @@ * questions. */ -/** +/* * @test - * @run testng ConnectionReset + * @run junit ConnectionReset * @summary Test behavior of SocketChannel.read and the Socket adaptor read * and available methods when a connection is reset */ @@ -36,12 +36,10 @@ import java.net.ServerSocket; import java.net.Socket; import java.nio.ByteBuffer; import java.nio.channels.SocketChannel; -import java.lang.reflect.Method; -import org.testng.annotations.Test; -import static org.testng.Assert.*; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; -@Test public class ConnectionReset { static final int REPEAT_COUNT = 5; @@ -50,6 +48,7 @@ public class ConnectionReset { * Tests SocketChannel.read when the connection is reset and there are no * bytes to read. */ + @Test public void testSocketChannelReadNoData() throws IOException { System.out.println("testSocketChannelReadNoData"); withResetConnection(null, sc -> { @@ -69,6 +68,7 @@ public class ConnectionReset { * Tests SocketChannel.read when the connection is reset and there are bytes * to read. */ + @Test public void testSocketChannelReadData() throws IOException { System.out.println("testSocketChannelReadData"); byte[] data = { 1, 2, 3 }; @@ -99,6 +99,7 @@ public class ConnectionReset { * Tests available before Socket read when the connection is reset and there * are no bytes to read. */ + @Test public void testAvailableBeforeSocketReadNoData() throws IOException { System.out.println("testAvailableBeforeSocketReadNoData"); withResetConnection(null, sc -> { @@ -107,7 +108,7 @@ public class ConnectionReset { for (int i=0; i %d%n", bytesAvailable); - assertTrue(bytesAvailable == 0); + assertEquals(0, bytesAvailable); try { int bytesRead = in.read(); if (bytesRead == -1) { @@ -127,6 +128,7 @@ public class ConnectionReset { * Tests available before Socket read when the connection is reset and there * are bytes to read. */ + @Test public void testAvailableBeforeSocketReadData() throws IOException { System.out.println("testAvailableBeforeSocketReadData"); byte[] data = { 1, 2, 3 }; @@ -160,6 +162,7 @@ public class ConnectionReset { * Tests Socket read before available when the connection is reset and there * are no bytes to read. */ + @Test public void testSocketReadNoDataBeforeAvailable() throws IOException { System.out.println("testSocketReadNoDataBeforeAvailable"); withResetConnection(null, sc -> { @@ -179,7 +182,7 @@ public class ConnectionReset { } int bytesAvailable = in.available(); System.out.format("available => %d%n", bytesAvailable); - assertTrue(bytesAvailable == 0); + assertEquals(0, bytesAvailable); } }); } @@ -188,6 +191,7 @@ public class ConnectionReset { * Tests Socket read before available when the connection is reset and there * are bytes to read. */ + @Test public void testSocketReadDataBeforeAvailable() throws IOException { System.out.println("testSocketReadDataBeforeAvailable"); byte[] data = { 1, 2, 3 }; diff --git a/test/jdk/java/nio/channels/SocketChannel/ReadWriteAfterClose.java b/test/jdk/java/nio/channels/SocketChannel/ReadWriteAfterClose.java index 037e750a552..0af09df4949 100644 --- a/test/jdk/java/nio/channels/SocketChannel/ReadWriteAfterClose.java +++ b/test/jdk/java/nio/channels/SocketChannel/ReadWriteAfterClose.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * 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,9 +21,6 @@ * questions. */ -import org.testng.annotations.AfterTest; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.Test; import java.io.IOException; import java.net.InetAddress; @@ -34,38 +31,45 @@ import java.nio.channels.ClosedChannelException; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; -import static org.testng.Assert.*; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; /* * @test * @bug 8246707 - * @library /test/lib * @summary Reading or Writing to a closed SocketChannel should throw a ClosedChannelException - * @run testng/othervm ReadWriteAfterClose + * @run junit/othervm ReadWriteAfterClose */ public class ReadWriteAfterClose { - private ServerSocketChannel listener; - private SocketAddress saddr; + private static ServerSocketChannel listener; + private static SocketAddress saddr; private static final int bufCapacity = 4; private static final int bufArraySize = 4; private static final Class CCE = ClosedChannelException.class; - @BeforeTest - public void setUp() throws IOException { + @BeforeAll + public static void setUp() throws IOException { listener = ServerSocketChannel.open(); listener.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0)); saddr = listener.getLocalAddress(); } + @AfterAll + public static void tearDown() throws IOException { + if (listener != null) listener.close(); + } + @Test public void testWriteAfterClose1() throws IOException { SocketChannel sc = SocketChannel.open(saddr); sc.close(); ByteBuffer bufWrite = ByteBuffer.allocate(bufCapacity); - Throwable ex = expectThrows(CCE, () -> sc.write(bufWrite)); - assertEquals(ex.getClass(), CCE); + Throwable ex = assertThrows(CCE, () -> sc.write(bufWrite)); + assertSame(CCE, ex.getClass()); } @Test @@ -73,8 +77,8 @@ public class ReadWriteAfterClose { SocketChannel sc = SocketChannel.open(saddr); sc.close(); ByteBuffer[] bufArrayWrite = allocateBufArray(); - Throwable ex = expectThrows(CCE, () -> sc.write(bufArrayWrite)); - assertEquals(ex.getClass(), CCE); + Throwable ex = assertThrows(CCE, () -> sc.write(bufArrayWrite)); + assertSame(CCE, ex.getClass()); } @Test @@ -82,8 +86,8 @@ public class ReadWriteAfterClose { SocketChannel sc = SocketChannel.open(saddr); sc.close(); ByteBuffer[] bufArrayWrite = allocateBufArray(); - Throwable ex = expectThrows(CCE, () -> sc.write(bufArrayWrite, 0, bufArraySize)); - assertEquals(ex.getClass(), CCE); + Throwable ex = assertThrows(CCE, () -> sc.write(bufArrayWrite, 0, bufArraySize)); + assertSame(CCE, ex.getClass()); } @Test @@ -91,8 +95,8 @@ public class ReadWriteAfterClose { SocketChannel sc = SocketChannel.open(saddr); sc.close(); ByteBuffer dst = ByteBuffer.allocate(bufCapacity); - Throwable ex = expectThrows(CCE, () -> sc.read(dst)); - assertEquals(ex.getClass(), CCE); + Throwable ex = assertThrows(CCE, () -> sc.read(dst)); + assertSame(CCE, ex.getClass()); } @Test @@ -100,8 +104,8 @@ public class ReadWriteAfterClose { SocketChannel sc = SocketChannel.open(saddr); sc.close(); ByteBuffer[] dstArray = allocateBufArray(); - Throwable ex = expectThrows(CCE, () -> sc.read(dstArray)); - assertEquals(ex.getClass(), CCE); + Throwable ex = assertThrows(CCE, () -> sc.read(dstArray)); + assertSame(CCE, ex.getClass()); } @Test @@ -109,8 +113,8 @@ public class ReadWriteAfterClose { SocketChannel sc = SocketChannel.open(saddr); sc.close(); ByteBuffer[] dstArray = allocateBufArray(); - Throwable ex = expectThrows(CCE, () -> sc.read(dstArray, 0, bufArraySize)); - assertEquals(ex.getClass(), CCE); + Throwable ex = assertThrows(CCE, () -> sc.read(dstArray, 0, bufArraySize)); + assertSame(CCE, ex.getClass()); } public ByteBuffer[] allocateBufArray() { @@ -120,8 +124,4 @@ public class ReadWriteAfterClose { return bufArr; } - @AfterTest - public void tearDown() throws IOException { - listener.close(); - } } \ No newline at end of file diff --git a/test/jdk/java/nio/channels/etc/LocalSocketAddressType.java b/test/jdk/java/nio/channels/etc/LocalSocketAddressType.java index 63be790c478..60e41af6288 100644 --- a/test/jdk/java/nio/channels/etc/LocalSocketAddressType.java +++ b/test/jdk/java/nio/channels/etc/LocalSocketAddressType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * 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,40 +26,44 @@ * @summary Test local address type * @library /test/lib * @build jdk.test.lib.NetworkConfiguration - * @run testng/othervm LocalSocketAddressType - * @run testng/othervm -Djava.net.preferIPv4Stack=true LocalSocketAddressType + * @run junit/othervm LocalSocketAddressType + * @run junit/othervm -Djava.net.preferIPv4Stack=true LocalSocketAddressType */ import jdk.test.lib.NetworkConfiguration; import jdk.test.lib.net.IPSupport; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; -import java.net.*; +import java.net.InetAddress; +import java.net.InetSocketAddress; import java.nio.channels.DatagramChannel; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.util.Iterator; -import java.util.stream.Collectors; import java.util.stream.Stream; -import static java.lang.Boolean.parseBoolean; -import static java.lang.System.getProperty; import static java.lang.System.out; -import static jdk.test.lib.Asserts.assertEquals; -import static jdk.test.lib.Asserts.assertTrue; import static jdk.test.lib.net.IPSupport.*; +import jtreg.SkippedException; +import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import static org.junit.jupiter.api.Assertions.assertEquals; + public class LocalSocketAddressType { - @BeforeTest() - public void setup() { + @BeforeAll() + public static void setup() { IPSupport.printPlatformSupport(out); - throwSkippedExceptionIfNonOperational(); + try { + throwSkippedExceptionIfNonOperational(); + } catch (SkippedException skippedException) { + // jtreg.SkippedException would cause a JUnit test to fail + Assumptions.assumeTrue(false, skippedException.getMessage()); + } } - @DataProvider(name = "addresses") public static Iterator addresses() throws Exception { NetworkConfiguration nc = NetworkConfiguration.probe(); return Stream.concat(nc.ip4Addresses(), nc.ip6Addresses()) @@ -67,36 +71,39 @@ public class LocalSocketAddressType { .iterator(); } - @Test(dataProvider = "addresses") - public static void testSocketChannel(InetSocketAddress addr) throws Exception { + @ParameterizedTest + @MethodSource("addresses") + public void testSocketChannel(InetSocketAddress addr) throws Exception { try (var c = SocketChannel.open()) { Class cls = addr.getAddress().getClass(); InetAddress ia = ((InetSocketAddress)c.bind(addr).getLocalAddress()).getAddress(); - assertEquals(ia.getClass(), cls); + assertEquals(cls, ia.getClass()); ia = c.socket().getLocalAddress(); - assertEquals(ia.getClass(), cls); + assertEquals(cls, ia.getClass()); } } - @Test(dataProvider = "addresses") - public static void testServerSocketChannel(InetSocketAddress addr) throws Exception { + @ParameterizedTest + @MethodSource("addresses") + public void testServerSocketChannel(InetSocketAddress addr) throws Exception { try (var c = ServerSocketChannel.open()) { Class cls = addr.getAddress().getClass(); InetAddress ia = ((InetSocketAddress)c.bind(addr).getLocalAddress()).getAddress(); - assertEquals(ia.getClass(), cls); + assertEquals(cls, ia.getClass()); ia = c.socket().getInetAddress(); - assertEquals(ia.getClass(), cls); + assertEquals(cls, ia.getClass()); } } - @Test(dataProvider = "addresses") - public static void testDatagramChannel(InetSocketAddress addr) throws Exception { + @ParameterizedTest + @MethodSource("addresses") + public void testDatagramChannel(InetSocketAddress addr) throws Exception { try (var c = DatagramChannel.open()) { Class cls = addr.getAddress().getClass(); InetAddress ia = ((InetSocketAddress)c.bind(addr).getLocalAddress()).getAddress(); - assertEquals(ia.getClass(), cls); + assertEquals(cls, ia.getClass()); ia = c.socket().getLocalAddress(); - assertEquals(ia.getClass(), cls); + assertEquals(cls, ia.getClass()); } } } diff --git a/test/jdk/java/nio/channels/etc/OpenAndConnect.java b/test/jdk/java/nio/channels/etc/OpenAndConnect.java index b183076e49d..0e0347ebb57 100644 --- a/test/jdk/java/nio/channels/etc/OpenAndConnect.java +++ b/test/jdk/java/nio/channels/etc/OpenAndConnect.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * 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,23 +23,32 @@ import jdk.test.lib.NetworkConfiguration; import jdk.test.lib.net.IPSupport; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import java.io.IOException; -import java.net.*; -import java.nio.channels.*; -import java.util.Arrays; +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.ProtocolFamily; +import java.net.SocketAddress; +import java.nio.channels.DatagramChannel; +import java.nio.channels.ServerSocketChannel; +import java.nio.channels.SocketChannel; import java.util.List; import java.util.LinkedList; -import static java.lang.System.getProperty; import static java.lang.System.out; import static java.net.StandardProtocolFamily.INET; import static java.net.StandardProtocolFamily.INET6; import static jdk.test.lib.net.IPSupport.*; +import jtreg.SkippedException; +import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + /* * @test * @summary Test SocketChannel, ServerSocketChannel and DatagramChannel @@ -48,10 +57,9 @@ import static jdk.test.lib.net.IPSupport.*; * addresses (Inet4Address, Inet6Address). * @library /test/lib * @build jdk.test.lib.NetworkConfiguration - * @run testng/othervm OpenAndConnect + * @run junit/othervm OpenAndConnect */ - public class OpenAndConnect { static final Inet4Address IA4ANYLOCAL; static final Inet6Address IA6ANYLOCAL; @@ -77,11 +85,16 @@ public class OpenAndConnect { } } - @BeforeTest() - public void setup() { + @BeforeAll() + public static void setup() { NetworkConfiguration.printSystemConfiguration(out); IPSupport.printPlatformSupport(out); - throwSkippedExceptionIfNonOperational(); + try { + throwSkippedExceptionIfNonOperational(); + } catch (SkippedException skippedException) { + // jtreg.SkippedException would cause a JUnit test to fail + Assumptions.assumeTrue(false, skippedException.getMessage()); + } out.println("IA4LOCAL: " + IA4LOCAL); out.println("IA6LOCAL: " + IA6LOCAL); @@ -91,9 +104,8 @@ public class OpenAndConnect { out.println("IA6LOOPBACK: " + IA6LOOPBACK); } - @DataProvider(name = "openConnect") - public Object[][] openConnect() { - LinkedList l = new LinkedList<>(); + public static List openConnect() { + LinkedList l = new LinkedList<>(); if (IPSupport.hasIPv4()) { l.addAll(openConnectV4Tests); if (IA4LOCAL != null) { @@ -112,7 +124,7 @@ public class OpenAndConnect { l.addAll(openConnectV4LocalAndV6Tests); } } - return l.toArray(new Object[][]{}); + return l; } // +----- sfam is server/first socket family @@ -127,92 +139,91 @@ public class OpenAndConnect { // | | | | this is address used for connect // | | | | also. // | | | | - // | | | | - // | | | | - // | | | | - // + + + + - // { sfam, saddr, cfam, caddr, } + // | | | +---------------+ + // | | | | + // | | +---------------+ | + // | | | | + // | +---------------+ | | + // | | | | + // +---------------+ | | | + // | | | | + // + + + + + // Arguments.of( sfam, saddr, cfam, caddr, ) // Basic tests for when an IPv4 is available - public static List openConnectV4Tests = - Arrays.asList(new Object[][] { - { INET, IA4LOOPBACK, INET, IA4LOOPBACK }, - { INET, IA4LOOPBACK, null, IA4LOOPBACK }, - { INET, IA4ANYLOCAL, null, IA4LOOPBACK }, - { INET, IA4ANYLOCAL, INET, IA4LOOPBACK }, - { null, IA4LOOPBACK, INET, IA4ANYLOCAL }, - { null, IA4LOOPBACK, INET, IA4LOOPBACK }, - { null, IA4LOOPBACK, INET, null }, - { null, IA4LOOPBACK, null, null } - }); + public static List openConnectV4Tests = + List.of(Arguments.of( INET, IA4LOOPBACK, INET, IA4LOOPBACK ), + Arguments.of( INET, IA4LOOPBACK, null, IA4LOOPBACK ), + Arguments.of( INET, IA4ANYLOCAL, null, IA4LOOPBACK ), + Arguments.of( INET, IA4ANYLOCAL, INET, IA4LOOPBACK ), + Arguments.of( null, IA4LOOPBACK, INET, IA4ANYLOCAL ), + Arguments.of( null, IA4LOOPBACK, INET, IA4LOOPBACK ), + Arguments.of( null, IA4LOOPBACK, INET, null ), + Arguments.of( null, IA4LOOPBACK, null, null ) + ); // Additional tests for when an IPv4 local address is available - public List openConnectV4LocalTests = - Arrays.asList(new Object[][] { - { INET, IA4LOCAL, INET, IA4LOCAL }, - { INET, IA4LOCAL, null, IA4LOCAL }, - { INET, IA4LOCAL, null, DONT_BIND }, - { INET, IA4ANYLOCAL, INET, IA4LOCAL }, - { INET, IA4ANYLOCAL, null, IA4LOCAL }, - { null, IA4LOCAL, INET, IA4ANYLOCAL }, - { null, IA4LOCAL, INET, IA4LOCAL }, - { null, IA4LOCAL, INET, null }, - { null, IA4LOCAL, null, null } - }); + public static List openConnectV4LocalTests = + List.of(Arguments.of( INET, IA4LOCAL, INET, IA4LOCAL ), + Arguments.of( INET, IA4LOCAL, null, IA4LOCAL ), + Arguments.of( INET, IA4LOCAL, null, DONT_BIND ), + Arguments.of( INET, IA4ANYLOCAL, INET, IA4LOCAL ), + Arguments.of( INET, IA4ANYLOCAL, null, IA4LOCAL ), + Arguments.of( null, IA4LOCAL, INET, IA4ANYLOCAL ), + Arguments.of( null, IA4LOCAL, INET, IA4LOCAL ), + Arguments.of( null, IA4LOCAL, INET, null ), + Arguments.of( null, IA4LOCAL, null, null ) + ); // Basic tests for when an IPv6 is available - public List openConnectV6Tests = - Arrays.asList(new Object[][] { - { INET6, IA6ANYLOCAL, null, IA6LOOPBACK }, - { INET6, IA6ANYLOCAL, INET6, IA6LOOPBACK }, - { INET6, IA6LOOPBACK, INET6, IA6LOOPBACK }, - { INET6, IA6LOOPBACK, INET6, IA6LOOPBACK }, - { null, IA6ANYLOCAL, null, IA6LOOPBACK }, - { null, IA6ANYLOCAL, INET6, IA6LOOPBACK }, - { null, IA6LOOPBACK, INET6, IA6LOOPBACK }, - { null, IA6LOOPBACK, INET6, DONT_BIND }, - { null, IA6LOOPBACK, INET6, null }, - { null, IA6LOOPBACK, null, IA6LOOPBACK }, - { null, IA6LOOPBACK, null, null }, - { null, IA6LOOPBACK, INET6, IA6ANYLOCAL }, - { null, IA6LOOPBACK, null, IA6ANYLOCAL } - }); + public static List openConnectV6Tests = + List.of(Arguments.of( INET6, IA6ANYLOCAL, null, IA6LOOPBACK ), + Arguments.of( INET6, IA6ANYLOCAL, INET6, IA6LOOPBACK ), + Arguments.of( INET6, IA6LOOPBACK, INET6, IA6LOOPBACK ), + Arguments.of( INET6, IA6LOOPBACK, INET6, IA6LOOPBACK ), + Arguments.of( null, IA6ANYLOCAL, null, IA6LOOPBACK ), + Arguments.of( null, IA6ANYLOCAL, INET6, IA6LOOPBACK ), + Arguments.of( null, IA6LOOPBACK, INET6, IA6LOOPBACK ), + Arguments.of( null, IA6LOOPBACK, INET6, DONT_BIND ), + Arguments.of( null, IA6LOOPBACK, INET6, null ), + Arguments.of( null, IA6LOOPBACK, null, IA6LOOPBACK ), + Arguments.of( null, IA6LOOPBACK, null, null ), + Arguments.of( null, IA6LOOPBACK, INET6, IA6ANYLOCAL ), + Arguments.of( null, IA6LOOPBACK, null, IA6ANYLOCAL ) + ); // Additional tests for when an IPv6 local address is available - public List openConnectV6LocalTests = - Arrays.asList(new Object[][] { - { INET6, IA6ANYLOCAL, null, IA6LOCAL }, - { INET6, IA6ANYLOCAL, INET6, IA6LOCAL }, - { INET6, IA6LOCAL, INET6, IA6LOCAL }, - { INET6, IA6LOCAL, null, IA6LOCAL }, - { INET6, IA6LOCAL, null, DONT_BIND }, - { INET6, IA6LOCAL, INET6, IA6LOCAL }, - { null, IA6ANYLOCAL, null, IA6LOCAL }, - { null, IA6ANYLOCAL, INET6, IA6LOCAL }, - { null, IA6LOCAL, INET6, IA6LOCAL }, - { null, IA6LOCAL, INET6, IA6ANYLOCAL }, - { null, IA6LOCAL, null, IA6ANYLOCAL }, - { null, IA6LOCAL, null, IA6LOCAL }, - { null, IA6LOCAL, INET6, null }, - { null, IA6LOCAL, null, null } - }); + public static List openConnectV6LocalTests = + List.of(Arguments.of( INET6, IA6ANYLOCAL, null, IA6LOCAL ), + Arguments.of( INET6, IA6ANYLOCAL, INET6, IA6LOCAL ), + Arguments.of( INET6, IA6LOCAL, INET6, IA6LOCAL ), + Arguments.of( INET6, IA6LOCAL, null, IA6LOCAL ), + Arguments.of( INET6, IA6LOCAL, null, DONT_BIND ), + Arguments.of( INET6, IA6LOCAL, INET6, IA6LOCAL ), + Arguments.of( null, IA6ANYLOCAL, null, IA6LOCAL ), + Arguments.of( null, IA6ANYLOCAL, INET6, IA6LOCAL ), + Arguments.of( null, IA6LOCAL, INET6, IA6LOCAL ), + Arguments.of( null, IA6LOCAL, INET6, IA6ANYLOCAL ), + Arguments.of( null, IA6LOCAL, null, IA6ANYLOCAL ), + Arguments.of( null, IA6LOCAL, null, IA6LOCAL ), + Arguments.of( null, IA6LOCAL, INET6, null ), + Arguments.of( null, IA6LOCAL, null, null ) + ); // Additional tests for when IPv4 and IPv6 are available - public List openConnectV4AndV6Tests = - Arrays.asList(new Object[][] { - { null, IA4LOOPBACK, INET6, IA6ANYLOCAL }, - { null, IA4LOOPBACK, null, IA6ANYLOCAL }, - { null, IA4LOOPBACK, INET6, DONT_BIND }, - { null, IA4LOOPBACK, INET6, null } - }); + public static List openConnectV4AndV6Tests = + List.of(Arguments.of( null, IA4LOOPBACK, INET6, IA6ANYLOCAL ), + Arguments.of( null, IA4LOOPBACK, null, IA6ANYLOCAL ), + Arguments.of( null, IA4LOOPBACK, INET6, DONT_BIND ), + Arguments.of( null, IA4LOOPBACK, INET6, null ) + ); // Additional tests for when IPv4 local address and IPv6 are available - public List openConnectV4LocalAndV6Tests = - Arrays.asList(new Object[][] { - { null, IA4LOCAL, INET6, IA6ANYLOCAL }, - { null, IA4LOCAL, INET6, null }, - { null, IA4LOCAL, null, IA6ANYLOCAL } - }); + public static List openConnectV4LocalAndV6Tests = + List.of(Arguments.of( null, IA4LOCAL, INET6, IA6ANYLOCAL ), + Arguments.of( null, IA4LOCAL, INET6, null ), + Arguments.of( null, IA4LOCAL, null, IA6ANYLOCAL ) + ); /** * If the destination address is the wildcard, it is replaced by the alternate @@ -227,7 +238,8 @@ public class OpenAndConnect { return isa; } - @Test(dataProvider = "openConnect") + @ParameterizedTest + @MethodSource("openConnect") public void scOpenAndConnect(ProtocolFamily sfam, InetAddress saddr, ProtocolFamily cfam, @@ -248,7 +260,8 @@ public class OpenAndConnect { } } - @Test(dataProvider = "openConnect") + @ParameterizedTest + @MethodSource("openConnect") public void dcOpenAndConnect(ProtocolFamily sfam, InetAddress saddr, ProtocolFamily cfam, diff --git a/test/jdk/java/nio/channels/etc/ProtocolFamilies.java b/test/jdk/java/nio/channels/etc/ProtocolFamilies.java index 45226e9a97e..7f823ff35a8 100644 --- a/test/jdk/java/nio/channels/etc/ProtocolFamilies.java +++ b/test/jdk/java/nio/channels/etc/ProtocolFamilies.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * 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,20 +23,38 @@ import jdk.test.lib.NetworkConfiguration; import jdk.test.lib.net.IPSupport; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; -import org.testng.Assert.ThrowingRunnable; + import java.io.IOException; -import java.net.*; -import java.nio.channels.*; +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.ProtocolFamily; +import java.net.SocketAddress; +import java.net.StandardProtocolFamily; +import java.net.UnknownHostException; +import java.nio.channels.DatagramChannel; +import java.nio.channels.ServerSocketChannel; +import java.nio.channels.SocketChannel; +import java.nio.channels.UnsupportedAddressTypeException; import java.nio.channels.spi.SelectorProvider; +import java.util.List; + import static java.lang.System.out; import static java.net.StandardProtocolFamily.INET; import static java.net.StandardProtocolFamily.INET6; import static jdk.test.lib.net.IPSupport.*; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertThrows; + +import jtreg.SkippedException; +import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.function.Executable; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import static org.junit.jupiter.api.Assertions.assertThrows; /* * @test @@ -44,8 +62,8 @@ import static org.testng.Assert.assertThrows; * with various ProtocolFamily combinations * @library /test/lib * @build jdk.test.lib.NetworkConfiguration - * @run testng ProtocolFamilies - * @run testng/othervm -Djava.net.preferIPv4Stack=true ProtocolFamilies + * @run junit ProtocolFamilies + * @run junit/othervm -Djava.net.preferIPv4Stack=true ProtocolFamilies */ @@ -55,11 +73,16 @@ public class ProtocolFamilies { static Inet4Address ia4; static Inet6Address ia6; - @BeforeTest() - public void setup() throws Exception { + @BeforeAll() + public static void setup() throws Exception { NetworkConfiguration.printSystemConfiguration(out); IPSupport.printPlatformSupport(out); - throwSkippedExceptionIfNonOperational(); + try { + throwSkippedExceptionIfNonOperational(); + } catch (SkippedException skippedException) { + // jtreg.SkippedException would cause a JUnit test to fail + Assumptions.assumeTrue(false, skippedException.getMessage()); + } ia4 = getLocalIPv4Address(); ia6 = getLocalIPv6Address(); @@ -70,111 +93,89 @@ public class ProtocolFamilies { static final Class UATE = UnsupportedAddressTypeException.class; static final Class UOE = UnsupportedOperationException.class; - @DataProvider(name = "open") - public Object[][] open() { + public static List open() { if (hasIPv6 && !preferIPv4) { - return new Object[][]{ - { INET, null }, - { INET6, null } - }; + return List.of( + Arguments.of( INET, null ), + Arguments.of( INET6, null ) + ); } else { - return new Object[][]{ - { INET, null }, - { INET6, UOE } - }; + return List.of( + Arguments.of( INET, null ), + Arguments.of( INET6, UOE ) + ); } } - @Test(dataProvider = "open") + @ParameterizedTest + @MethodSource("open") public void scOpen(StandardProtocolFamily family, Class expectedException) - throws Throwable + throws IOException { - SocketChannel sc = null; - try { - if (expectedException == UOE) { - try { - sc = openSC(family); - } catch (UnsupportedOperationException e) {} - } else { - sc = openSC(family); - } - } finally { - if (sc != null) - sc.close(); + if (expectedException != null) { + assertThrows(expectedException, () -> openSC(family)); + } else { + try (var _ = openSC(family)) { } } } - @Test(dataProvider = "open") + @ParameterizedTest + @MethodSource("open") public void sscOpen(StandardProtocolFamily family, Class expectedException) - throws Throwable + throws IOException { - ServerSocketChannel ssc = null; - try { - if (expectedException == UOE) { - try { - ssc = openSSC(family); - } catch (UnsupportedOperationException e) {} - } else { - openSSC(family); - } - } finally { - if (ssc != null) - ssc.close(); + if (expectedException != null) { + assertThrows(expectedException, () -> openSSC(family)); + } else { + try (var _ = openSSC(family)) { } } } - @Test(dataProvider = "open") + @ParameterizedTest + @MethodSource("open") public void dcOpen(StandardProtocolFamily family, Class expectedException) - throws Throwable + throws IOException { - DatagramChannel dc = null; - try { - if (expectedException == UOE) { - try { - dc = openDC(family); - } catch (UnsupportedOperationException e) {} - } else { - openDC(family); - } - } finally { - if (dc != null) - dc.close(); + if (expectedException != null) { + assertThrows(expectedException, () -> openDC(family)); + } else { + try (var _ = openDC(family)) { } } } - @DataProvider(name = "openBind") - public Object[][] openBind() { + public static List openBind() { if (hasIPv6 && !preferIPv4) { - return new Object[][]{ - { INET, INET, null }, - { INET, INET6, UATE }, - { INET, null, null }, - { INET6, INET, null }, - { INET6, INET6, null }, - { INET6, null, null }, - { null, INET, null }, - { null, INET6, null }, - { null, null, null } - }; + return List.of( + Arguments.of( INET, INET, null ), + Arguments.of( INET, INET6, UATE ), + Arguments.of( INET, null, null ), + Arguments.of( INET6, INET, null ), + Arguments.of( INET6, INET6, null ), + Arguments.of( INET6, null, null ), + Arguments.of( null, INET, null ), + Arguments.of( null, INET6, null ), + Arguments.of( null, null, null ) + ); } else { - return new Object[][]{ - { INET, INET, null }, - { INET, INET6, UATE }, - { INET, null, null }, - { null, INET, null }, - { null, INET6, UATE }, - { null, null, null } - }; + return List.of( + Arguments.of( INET, INET, null ), + Arguments.of( INET, INET6, UATE ), + Arguments.of( INET, null, null ), + Arguments.of( null, INET, null ), + Arguments.of( null, INET6, UATE ), + Arguments.of( null, null, null ) + ); } } // SocketChannel open - INET, INET6, default // SocketChannel bind - INET, INET6, null - @Test(dataProvider = "openBind") + @ParameterizedTest + @MethodSource("openBind") public void scOpenBind(StandardProtocolFamily ofamily, StandardProtocolFamily bfamily, Class expectedException) @@ -182,9 +183,9 @@ public class ProtocolFamilies { { try (SocketChannel sc = openSC(ofamily)) { SocketAddress addr = getSocketAddress(bfamily); - ThrowingRunnable bindOp = () -> sc.bind(addr); - if (expectedException == null) - bindOp.run(); + Executable bindOp = () -> sc.bind(addr); + if (expectedException == null) + bindOp.execute(); else assertThrows(expectedException, bindOp); } @@ -193,7 +194,8 @@ public class ProtocolFamilies { // ServerSocketChannel open - INET, INET6, default // ServerSocketChannel bind - INET, INET6, null - @Test(dataProvider = "openBind") + @ParameterizedTest + @MethodSource("openBind") public void sscOpenBind(StandardProtocolFamily ofamily, StandardProtocolFamily bfamily, Class expectedException) @@ -201,9 +203,9 @@ public class ProtocolFamilies { { try (ServerSocketChannel ssc = openSSC(ofamily)) { SocketAddress addr = getSocketAddress(bfamily); - ThrowingRunnable bindOp = () -> ssc.bind(addr); + Executable bindOp = () -> ssc.bind(addr); if (expectedException == null) - bindOp.run(); + bindOp.execute(); else assertThrows(expectedException, bindOp); } @@ -212,7 +214,8 @@ public class ProtocolFamilies { // DatagramChannel open - INET, INET6, default // DatagramChannel bind - INET, INET6, null - @Test(dataProvider = "openBind") + @ParameterizedTest + @MethodSource("openBind") public void dcOpenBind(StandardProtocolFamily ofamily, StandardProtocolFamily bfamily, Class expectedException) @@ -220,9 +223,9 @@ public class ProtocolFamilies { { try (DatagramChannel dc = openDC(ofamily)) { SocketAddress addr = getSocketAddress(bfamily); - ThrowingRunnable bindOp = () -> dc.bind(addr); + Executable bindOp = () -> dc.bind(addr); if (expectedException == null) - bindOp.run(); + bindOp.execute(); else assertThrows(expectedException, bindOp); } @@ -231,32 +234,32 @@ public class ProtocolFamilies { // SocketChannel open - INET, INET6, default // SocketChannel connect - INET, INET6, default - @DataProvider(name = "openConnect") - public Object[][] openConnect() { + public static List openConnect() { if (hasIPv6 && !preferIPv4) { - return new Object[][]{ - { INET, INET, null }, - { INET, INET6, null }, - { INET, null, null }, - { INET6, INET, UATE }, - { INET6, INET6, null }, - { INET6, null, null }, - { null, INET, UATE }, - { null, INET6, null }, - { null, null, null } - }; + return List.of( + Arguments.of( INET, INET, null ), + Arguments.of( INET, INET6, null ), + Arguments.of( INET, null, null ), + Arguments.of( INET6, INET, UATE ), + Arguments.of( INET6, INET6, null ), + Arguments.of( INET6, null, null ), + Arguments.of( null, INET, UATE ), + Arguments.of( null, INET6, null ), + Arguments.of( null, null, null ) + ); } else { // INET6 channels cannot be created - UOE - tested elsewhere - return new Object[][]{ - { INET, INET, null }, - { INET, null, null }, - { null, INET, null }, - { null, null, null } - }; + return List.of( + Arguments.of( INET, INET, null ), + Arguments.of( INET, null, null ), + Arguments.of( null, INET, null ), + Arguments.of( null, null, null ) + ); } } - @Test(dataProvider = "openConnect") + @ParameterizedTest + @MethodSource("openConnect") public void scOpenConnect(StandardProtocolFamily sfamily, StandardProtocolFamily cfamily, Class expectedException) @@ -279,7 +282,7 @@ public class ProtocolFamilies { // Tests null handling @Test public void testNulls() { - assertThrows(NPE, () -> SocketChannel.open((ProtocolFamily)null)); + assertThrows(NPE, () -> SocketChannel.open((ProtocolFamily) null)); assertThrows(NPE, () -> ServerSocketChannel.open(null)); assertThrows(NPE, () -> DatagramChannel.open(null)); diff --git a/test/jdk/java/nio/channels/unixdomain/EmptySunPathForSocketFile.java b/test/jdk/java/nio/channels/unixdomain/EmptySunPathForSocketFile.java index 79f8ead7aa2..ec47babdff3 100644 --- a/test/jdk/java/nio/channels/unixdomain/EmptySunPathForSocketFile.java +++ b/test/jdk/java/nio/channels/unixdomain/EmptySunPathForSocketFile.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * 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,11 +21,11 @@ * questions. */ -/** +/* * @test * @bug 8256461 * @modules java.base/sun.nio.fs - * @run testng EmptySunPathForSocketFile + * @run junit EmptySunPathForSocketFile */ import java.nio.file.FileSystems; @@ -33,7 +33,8 @@ import java.nio.file.Path; import java.nio.file.spi.FileSystemProvider; import sun.nio.fs.AbstractFileSystemProvider; -import static org.testng.Assert.assertEquals; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; /** * Check that AbstractFileSystemProvider.getSunPathForSocketFile with @@ -41,9 +42,14 @@ import static org.testng.Assert.assertEquals; */ public class EmptySunPathForSocketFile { public static void main(String[] args) throws Exception { + new EmptySunPathForSocketFile().test(); + } + + @Test + public void test() { Path path = Path.of(""); FileSystemProvider provider = FileSystems.getDefault().provider(); byte[] bb = ((AbstractFileSystemProvider) provider).getSunPathForSocketFile(path); - assertEquals(bb, new byte[0]); + assertArrayEquals(new byte[0], bb); } } diff --git a/test/jdk/java/nio/channels/unixdomain/FileAttributes.java b/test/jdk/java/nio/channels/unixdomain/FileAttributes.java index 3ff92a6bc05..5e9b65f90b2 100644 --- a/test/jdk/java/nio/channels/unixdomain/FileAttributes.java +++ b/test/jdk/java/nio/channels/unixdomain/FileAttributes.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * 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,35 +21,34 @@ * questions. */ -/** +/* * @test * @bug 8252971 - * @library /test/lib - * @run testng FileAttributes + * @run junit FileAttributes */ import java.io.IOException; import java.io.File; -import java.net.*; -import java.nio.channels.*; +import java.net.UnixDomainSocketAddress; +import java.nio.channels.SocketChannel; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.attribute.BasicFileAttributes; -import java.util.Arrays; -import org.testng.annotations.Test; -import org.testng.SkipException; import static java.net.StandardProtocolFamily.UNIX; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertThrows; -import static org.testng.Assert.assertTrue; + +import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; /** */ public class FileAttributes { @Test - public static void test() throws Exception { + public void test() throws Exception { checkSupported(); Path path = null; try (var chan = SocketChannel.open(UNIX)) { @@ -89,7 +88,7 @@ public class FileAttributes { try { SocketChannel.open(UNIX).close(); } catch (UnsupportedOperationException e) { - throw new SkipException("Unix domain channels not supported"); + Assumptions.assumeTrue(false, "Unix domain channels not supported"); } catch (Exception e) { // continue test to see what problem is } diff --git a/test/jdk/java/nio/channels/unixdomain/IOExchanges.java b/test/jdk/java/nio/channels/unixdomain/IOExchanges.java index 33a7b5ef3c4..9924d02504a 100644 --- a/test/jdk/java/nio/channels/unixdomain/IOExchanges.java +++ b/test/jdk/java/nio/channels/unixdomain/IOExchanges.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,38 +21,45 @@ * questions. */ -/** +/* * @test * @bug 8245194 - * @run testng/othervm/timeout=480 IOExchanges + * @run junit/othervm/timeout=480 IOExchanges */ import java.io.IOException; -import java.net.*; -import java.nio.channels.*; +import java.net.ProtocolFamily; +import java.net.SocketAddress; +import java.net.UnixDomainSocketAddress; import java.nio.ByteBuffer; +import java.nio.channels.SelectionKey; +import java.nio.channels.Selector; +import java.nio.channels.ServerSocketChannel; +import java.nio.channels.SocketChannel; import java.nio.file.Files; +import java.util.List; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import static java.lang.System.out; import static java.net.StandardProtocolFamily.*; import static java.nio.channels.SelectionKey.OP_ACCEPT; import static java.nio.channels.SelectionKey.OP_READ; import static java.nio.channels.SelectionKey.OP_WRITE; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; public class IOExchanges { static boolean unixDomainSupported = true; - @BeforeTest() - public void setup() { + @BeforeAll() + public static void setup() { try { - SocketChannel.open(UNIX); + SocketChannel.open(UNIX).close(); } catch (IOException | UnsupportedOperationException e) { unixDomainSupported = false; out.println("Unix domain channels not supported"); @@ -72,8 +79,8 @@ public class IOExchanges { } public static void deleteFile(SocketAddress addr) throws Exception { - if (addr instanceof UnixDomainSocketAddress) { - Files.deleteIfExists(((UnixDomainSocketAddress) addr).getPath()); + if (addr instanceof UnixDomainSocketAddress uaddr) { + Files.deleteIfExists(uaddr.getPath()); } } @@ -118,18 +125,12 @@ public class IOExchanges { SPINBAccep_NBConn_NBIO_RW_12a */ - @DataProvider(name = "family") - public Object[][] family() { - return unixDomainSupported ? - new Object[][] { - { UNIX }, - { INET }} - : new Object[][] { - { INET } - }; + public static List family() { + return unixDomainSupported ? List.of(INET, UNIX) : List.of(INET); } - @Test(dataProvider = "family") + @ParameterizedTest + @MethodSource("family") public void BAccep_BConn_BIO_WR_1(ProtocolFamily family) throws Throwable { try (ServerSocketChannel ssc = openServerSocketChannel(family)) { @@ -140,25 +141,26 @@ public class IOExchanges { try (SocketChannel sc = openSocketChannel(family)) { assertTrue(sc.connect(addr)); ByteBuffer bb = ByteBuffer.allocate(10).put((byte) 0x01).flip(); - assertEquals(sc.write(bb), 1); + assertEquals(1, sc.write(bb)); out.printf("wrote: 0x%x%n", bb.get(0)); - assertEquals(sc.read(bb.clear()), -1); + assertEquals(-1, sc.read(bb.clear())); } }); t.start(); try (SocketChannel sc = ssc.accept()) { ByteBuffer bb = ByteBuffer.allocate(10); - assertEquals(sc.read(bb), 1); + assertEquals(1, sc.read(bb)); out.printf("read: 0x%x%n", bb.get(0)); - assertEquals(bb.get(0), 0x01); + assertEquals(0x01, bb.get(0)); } t.awaitCompletion(); deleteFile(addr); } } - @Test(dataProvider = "family") + @ParameterizedTest + @MethodSource("family") public void BAccep_BConn_BIO_RW_2(ProtocolFamily family) throws Throwable { try (ServerSocketChannel ssc = openServerSocketChannel(family)) { @@ -169,25 +171,26 @@ public class IOExchanges { try (SocketChannel sc = openSocketChannel(family)) { assertTrue(sc.connect(addr)); ByteBuffer bb = ByteBuffer.allocate(10); - assertEquals(sc.read(bb), 1); + assertEquals(1, sc.read(bb)); out.printf("read: 0x%x%n", bb.get(0)); - assertEquals(bb.get(0), 0x02); + assertEquals(0x02, bb.get(0)); } }); t.start(); try (SocketChannel sc = ssc.accept()) { ByteBuffer bb = ByteBuffer.allocate(10).put((byte) 0x02).flip(); - assertEquals(sc.write(bb), 1); + assertEquals(1, sc.write(bb)); out.printf("wrote: 0x%x%n", bb.get(0)); - assertEquals(sc.read(bb.clear()), -1); + assertEquals(-1, sc.read(bb.clear())); } t.awaitCompletion(); deleteFile(addr); } } - @Test(dataProvider = "family") + @ParameterizedTest + @MethodSource("family") public void SELNBAccep_BConn_BIO_WR_3(ProtocolFamily family) throws Throwable { try (ServerSocketChannel ssc = openServerSocketChannel(family); @@ -199,28 +202,29 @@ public class IOExchanges { try (SocketChannel sc = openSocketChannel(family)) { assertTrue(sc.connect(addr)); ByteBuffer bb = ByteBuffer.allocate(10).put((byte) 0x03).flip(); - assertEquals(sc.write(bb), 1); + assertEquals(1, sc.write(bb)); out.printf("wrote: 0x%x%n", bb.get(0)); - assertEquals(sc.read(bb.clear()), -1); + assertEquals(-1, sc.read(bb.clear())); } }); t.start(); ssc.configureBlocking(false).register(selector, OP_ACCEPT); - assertEquals(selector.select(), 1); + assertEquals(1, selector.select()); try (SocketChannel sc = ssc.accept()) { ByteBuffer bb = ByteBuffer.allocate(10); - assertEquals(sc.read(bb), 1); + assertEquals(1, sc.read(bb)); out.printf("read: 0x%x%n", bb.get(0)); - assertEquals(bb.get(0), 0x03); + assertEquals(0x03, bb.get(0)); } t.awaitCompletion(); deleteFile(addr); } } - @Test(dataProvider = "family") + @ParameterizedTest + @MethodSource("family") public void SELNBAccep_BConn_BIO_RW_4(ProtocolFamily family) throws Throwable { try (ServerSocketChannel ssc = openServerSocketChannel(family); @@ -232,21 +236,21 @@ public class IOExchanges { try (SocketChannel sc = openSocketChannel(family)) { assertTrue(sc.connect(addr)); ByteBuffer bb = ByteBuffer.allocate(10); - assertEquals(sc.read(bb), 1); + assertEquals(1, sc.read(bb)); out.printf("read: 0x%x%n", bb.get(0)); - assertEquals(bb.get(0), 0x04); + assertEquals(0x04, bb.get(0)); } }); t.start(); ssc.configureBlocking(false).register(selector, OP_ACCEPT); - assertEquals(selector.select(), 1); + assertEquals(1, selector.select()); try (SocketChannel sc = ssc.accept()) { ByteBuffer bb = ByteBuffer.allocate(10).put((byte) 0x04).flip(); - assertEquals(sc.write(bb), 1); + assertEquals(1, sc.write(bb)); out.printf("wrote: 0x%x%n", bb.get(0)); - assertEquals(sc.read(bb.clear()), -1); + assertEquals(-1, sc.read(bb.clear())); } t.awaitCompletion(); @@ -254,7 +258,8 @@ public class IOExchanges { } } - @Test(dataProvider = "family") + @ParameterizedTest + @MethodSource("family") public void SPINNBAccep_BConn_BIO_WR_5(ProtocolFamily family) throws Throwable { try (ServerSocketChannel ssc = openServerSocketChannel(family)) { @@ -265,9 +270,9 @@ public class IOExchanges { try (SocketChannel sc = openSocketChannel(family)) { assertTrue(sc.connect(addr)); ByteBuffer bb = ByteBuffer.allocate(10).put((byte) 0x05).flip(); - assertEquals(sc.write(bb), 1); + assertEquals(1, sc.write(bb)); out.printf("wrote: 0x%x%n", bb.get(0)); - assertEquals(sc.read(bb.clear()), -1); + assertEquals(-1, sc.read(bb.clear())); } }); t.start(); @@ -284,16 +289,17 @@ public class IOExchanges { try (SocketChannel sc = accepted) { ByteBuffer bb = ByteBuffer.allocate(10); - assertEquals(sc.read(bb), 1); + assertEquals(1, sc.read(bb)); out.printf("read: 0x%x%n", bb.get(0)); - assertEquals(bb.get(0), 0x05); + assertEquals(0x05, bb.get(0)); } t.awaitCompletion(); deleteFile(addr); } } - @Test(dataProvider = "family") + @ParameterizedTest + @MethodSource("family") public void SPINNBAccep_BConn_BIO_RW_6(ProtocolFamily family) throws Throwable { try (ServerSocketChannel ssc = openServerSocketChannel(family)) { @@ -304,9 +310,9 @@ public class IOExchanges { try (SocketChannel sc = openSocketChannel(family)) { assertTrue(sc.connect(addr)); ByteBuffer bb = ByteBuffer.allocate(10); - assertEquals(sc.read(bb), 1); + assertEquals(1, sc.read(bb)); out.printf("read: 0x%x%n", bb.get(0)); - assertEquals(bb.get(0), 0x06); + assertEquals(0x06, bb.get(0)); } }); t.start(); @@ -323,9 +329,9 @@ public class IOExchanges { try (SocketChannel sc = accepted) { ByteBuffer bb = ByteBuffer.allocate(10).put((byte) 0x06).flip(); - assertEquals(sc.write(bb), 1); + assertEquals(1, sc.write(bb)); out.printf("wrote: 0x%x%n", bb.get(0)); - assertEquals(sc.read(bb.clear()), -1); + assertEquals(-1, sc.read(bb.clear())); } t.awaitCompletion(); @@ -336,7 +342,8 @@ public class IOExchanges { // Similar to the previous six scenarios, but with same-thread // non-blocking connect. - @Test(dataProvider = "family") + @ParameterizedTest + @MethodSource("family") public void BAccep_NBConn_BIO_WR_7(ProtocolFamily family) throws Throwable { try (ServerSocketChannel ssc = openServerSocketChannel(family)) { @@ -352,16 +359,16 @@ public class IOExchanges { sc.configureBlocking(true); TestThread t = TestThread.of("t7", () -> { ByteBuffer bb = ByteBuffer.allocate(10).put((byte) 0x07).flip(); - assertEquals(sc.write(bb), 1); + assertEquals(1, sc.write(bb)); out.printf("wrote: 0x%x%n", bb.get(0)); - assertEquals(sc.read(bb.clear()), -1); + assertEquals(-1, sc.read(bb.clear())); }); t.start(); ByteBuffer bb = ByteBuffer.allocate(10); - assertEquals(sc2.read(bb), 1); + assertEquals(1, sc2.read(bb)); out.printf("read: 0x%x%n", bb.get(0)); - assertEquals(bb.get(0), 0x07); + assertEquals(0x07, bb.get(0)); sc2.shutdownOutput(); t.awaitCompletion(); } @@ -370,7 +377,8 @@ public class IOExchanges { } } - @Test(dataProvider = "family") + @ParameterizedTest + @MethodSource("family") public void BAccep_NBConn_BIO_RW_8(ProtocolFamily family) throws Throwable { try (ServerSocketChannel ssc = openServerSocketChannel(family)) { @@ -386,17 +394,17 @@ public class IOExchanges { sc.configureBlocking(true); TestThread t = TestThread.of("t8", () -> { ByteBuffer bb = ByteBuffer.allocate(10); - assertEquals(sc.read(bb), 1); + assertEquals(1, sc.read(bb)); out.printf("read: 0x%x%n", bb.get(0)); - assertEquals(bb.get(0), 0x08); + assertEquals(0x08, bb.get(0)); sc.shutdownOutput(); }); t.start(); ByteBuffer bb = ByteBuffer.allocate(10).put((byte) 0x08).flip(); - assertEquals(sc2.write(bb), 1); + assertEquals(1, sc2.write(bb)); out.printf("wrote: 0x%x%n", bb.get(0)); - assertEquals(sc2.read(bb.clear()), -1); + assertEquals(-1, sc2.read(bb.clear())); t.awaitCompletion(); } } @@ -404,7 +412,8 @@ public class IOExchanges { } } - @Test(dataProvider = "family") + @ParameterizedTest + @MethodSource("family") public void SELNBAccep_NBConn_BIO_WR_9(ProtocolFamily family) throws Throwable { try (ServerSocketChannel ssc = openServerSocketChannel(family)) { @@ -417,23 +426,23 @@ public class IOExchanges { sc.connect(addr); ssc.configureBlocking(false).register(selector, OP_ACCEPT); - assertEquals(selector.select(), 1); + assertEquals(1, selector.select()); try (SocketChannel sc2 = ssc.accept()) { assertTrue(sc.finishConnect()); sc.configureBlocking(true); TestThread t = TestThread.of("t9", () -> { ByteBuffer bb = ByteBuffer.allocate(10).put((byte) 0x09).flip(); - assertEquals(sc.write(bb), 1); + assertEquals(1, sc.write(bb)); out.printf("wrote: 0x%x%n", bb.get(0)); - assertEquals(sc.read(bb.clear()), -1); + assertEquals(-1, sc.read(bb.clear())); }); t.start(); ByteBuffer bb = ByteBuffer.allocate(10); - assertEquals(sc2.read(bb), 1); + assertEquals(1, sc2.read(bb)); out.printf("read: 0x%x%n", bb.get(0)); - assertEquals(bb.get(0), 0x09); + assertEquals(0x09, bb.get(0)); sc2.shutdownOutput(); t.awaitCompletion(); } @@ -442,7 +451,8 @@ public class IOExchanges { } } - @Test(dataProvider = "family") + @ParameterizedTest + @MethodSource("family") public void SELNBAccep_NBConn_BIO_RW_10(ProtocolFamily family) throws Throwable { try (ServerSocketChannel ssc = openServerSocketChannel(family)) { @@ -455,24 +465,24 @@ public class IOExchanges { sc.connect(addr); ssc.configureBlocking(false).register(selector, OP_ACCEPT); - assertEquals(selector.select(), 1); + assertEquals(1, selector.select()); try (SocketChannel sc2 = ssc.accept()) { assertTrue(sc.finishConnect()); sc.configureBlocking(true); TestThread t = TestThread.of("t10", () -> { ByteBuffer bb = ByteBuffer.allocate(10); - assertEquals(sc.read(bb), 1); + assertEquals(1, sc.read(bb)); out.printf("read: 0x%x%n", bb.get(0)); - assertEquals(bb.get(0), 0x10); + assertEquals(0x10, bb.get(0)); sc.shutdownOutput(); }); t.start(); ByteBuffer bb = ByteBuffer.allocate(10).put((byte) 0x10).flip(); - assertEquals(sc2.write(bb), 1); + assertEquals(1, sc2.write(bb)); out.printf("wrote: 0x%x%n", bb.get(0)); - assertEquals(sc2.read(bb.clear()), -1); + assertEquals(-1, sc2.read(bb.clear())); t.awaitCompletion(); } } @@ -480,7 +490,8 @@ public class IOExchanges { } } - @Test(dataProvider = "family") + @ParameterizedTest + @MethodSource("family") public void SPINNBAccep_NBConn_BIO_WR_11(ProtocolFamily family) throws Throwable { try (ServerSocketChannel ssc = openServerSocketChannel(family)) { @@ -506,16 +517,16 @@ public class IOExchanges { sc.configureBlocking(true); TestThread t = TestThread.of("t11", () -> { ByteBuffer bb = ByteBuffer.allocate(10).put((byte) 0x11).flip(); - assertEquals(sc.write(bb), 1); + assertEquals(1, sc.write(bb)); out.printf("wrote: 0x%x%n", bb.get(0)); - assertEquals(sc.read(bb.clear()), -1); + assertEquals(-1, sc.read(bb.clear())); }); t.start(); ByteBuffer bb = ByteBuffer.allocate(10); - assertEquals(sc2.read(bb), 1); + assertEquals(1, sc2.read(bb)); out.printf("read: 0x%x%n", bb.get(0)); - assertEquals(bb.get(0), 0x11); + assertEquals(0x11, bb.get(0)); sc2.shutdownOutput(); t.awaitCompletion(); } @@ -524,7 +535,8 @@ public class IOExchanges { } } - @Test(dataProvider = "family") + @ParameterizedTest + @MethodSource("family") public void SPINNBAccep_NBConn_BIO_RW_12(ProtocolFamily family) throws Throwable { try (ServerSocketChannel ssc = openServerSocketChannel(family)) { @@ -550,17 +562,17 @@ public class IOExchanges { sc.configureBlocking(true); TestThread t = TestThread.of("t12", () -> { ByteBuffer bb = ByteBuffer.allocate(10); - assertEquals(sc.read(bb), 1); + assertEquals(1, sc.read(bb)); out.printf("read: 0x%x%n", bb.get(0)); - assertEquals(bb.get(0), 0x12); + assertEquals(0x12, bb.get(0)); sc.shutdownOutput(); }); t.start(); ByteBuffer bb = ByteBuffer.allocate(10).put((byte) 0x12).flip(); - assertEquals(sc2.write(bb), 1); + assertEquals(1, sc2.write(bb)); out.printf("wrote: 0x%x%n", bb.get(0)); - assertEquals(sc2.read(bb.clear()), -1); + assertEquals(-1, sc2.read(bb.clear())); t.awaitCompletion(); } } @@ -572,7 +584,8 @@ public class IOExchanges { // Similar to the previous twelve scenarios but with non-blocking IO // --- - @Test(dataProvider = "family") + @ParameterizedTest + @MethodSource("family") public void BAccep_BConn_NBIO_WR_1a(ProtocolFamily family) throws Throwable { try (ServerSocketChannel ssc = openServerSocketChannel(family)) { @@ -589,13 +602,13 @@ public class IOExchanges { selector.select(); int c; while ((c = sc.write(bb)) < 1) ; - assertEquals(c, 1); + assertEquals(1, c); out.printf("wrote: 0x%x%n", bb.get(0)); k.interestOps(OP_READ); selector.select(); bb.clear(); while ((c = sc.read(bb)) == 0) ; - assertEquals(c, -1); + assertEquals(-1, c); } }); t.start(); @@ -608,16 +621,17 @@ public class IOExchanges { selector.select(); int c; while ((c = sc.read(bb)) == 0) ; - assertEquals(c, 1); + assertEquals(1, c); out.printf("read: 0x%x%n", bb.get(0)); - assertEquals(bb.get(0), 0x1A); + assertEquals(0x1A, bb.get(0)); } t.awaitCompletion(); deleteFile(addr); } } - @Test(dataProvider = "family") + @ParameterizedTest + @MethodSource("family") public void BAccep_BConn_NBIO_RW_2a(ProtocolFamily family) throws Throwable { try (ServerSocketChannel ssc = openServerSocketChannel(family)) { @@ -634,9 +648,9 @@ public class IOExchanges { selector.select(); int c; while ((c = sc.read(bb)) == 0) ; - assertEquals(c, 1); + assertEquals(1, c); out.printf("read: 0x%x%n", bb.get(0)); - assertEquals(bb.get(0), 0x2A); + assertEquals(0x2A, bb.get(0)); } }); t.start(); @@ -649,20 +663,21 @@ public class IOExchanges { selector.select(); int c; while ((c = sc.write(bb)) < 1) ; - assertEquals(c, 1); + assertEquals(1, c); out.printf("wrote: 0x%x%n", bb.get(0)); k.interestOps(OP_READ); selector.select(); bb.clear(); while ((c = sc.read(bb)) == 0) ; - assertEquals(c, -1); + assertEquals(-1, c); } t.awaitCompletion(); deleteFile(addr); } } - @Test(dataProvider = "family") + @ParameterizedTest + @MethodSource("family") public void SELNBAccep_BConn_NBIO_WR_3a(ProtocolFamily family) throws Throwable { try (ServerSocketChannel ssc = openServerSocketChannel(family); @@ -680,19 +695,19 @@ public class IOExchanges { selector.select(); int c; while ((c = sc.write(bb)) < 1) ; - assertEquals(c, 1); + assertEquals(1, c); out.printf("wrote: 0x%x%n", bb.get(0)); k.interestOps(OP_READ); selector.select(); bb.clear(); while ((c = sc.read(bb)) == 0) ; - assertEquals(c, -1); + assertEquals(-1, c); } }); t.start(); ssc.configureBlocking(false).register(aselector, OP_ACCEPT); - assertEquals(aselector.select(), 1); + assertEquals(1, aselector.select()); try (SocketChannel sc = ssc.accept(); Selector selector = Selector.open()) { @@ -702,16 +717,17 @@ public class IOExchanges { selector.select(); int c; while ((c = sc.read(bb)) == 0) ; - assertEquals(c, 1); + assertEquals(1, c); out.printf("read: 0x%x%n", bb.get(0)); - assertEquals(bb.get(0), 0x3A); + assertEquals(0x3A, bb.get(0)); } t.awaitCompletion(); deleteFile(addr); } } - @Test(dataProvider = "family") + @ParameterizedTest + @MethodSource("family") public void SELNBAccep_BConn_NBIO_RW_4a(ProtocolFamily family) throws Throwable { try (ServerSocketChannel ssc = openServerSocketChannel(family); @@ -729,15 +745,15 @@ public class IOExchanges { selector.select(); int c; while ((c = sc.read(bb)) == 0) ; - assertEquals(c, 1); + assertEquals(1, c); out.printf("read: 0x%x%n", bb.get(0)); - assertEquals(bb.get(0), 0x4A); + assertEquals(0x4A, bb.get(0)); } }); t.start(); ssc.configureBlocking(false).register(aselector, OP_ACCEPT); - assertEquals(aselector.select(), 1); + assertEquals(1, aselector.select()); try (SocketChannel sc = ssc.accept(); Selector selector = Selector.open()) { @@ -747,20 +763,21 @@ public class IOExchanges { selector.select(); int c; while ((c = sc.write(bb)) < 1) ; - assertEquals(c, 1); + assertEquals(1, c); out.printf("wrote: 0x%x%n", bb.get(0)); k.interestOps(OP_READ); selector.select(); bb.clear(); while ((c = sc.read(bb)) == 0) ; - assertEquals(c, -1); + assertEquals(-1, c); } t.awaitCompletion(); deleteFile(addr); } } - @Test(dataProvider = "family") + @ParameterizedTest + @MethodSource("family") public void SPINNBAccep_BConn_NBIO_WR_5a(ProtocolFamily family) throws Throwable { try (ServerSocketChannel ssc = openServerSocketChannel(family)) { @@ -777,13 +794,13 @@ public class IOExchanges { selector.select(); int c; while ((c = sc.write(bb)) < 1) ; - assertEquals(c, 1); + assertEquals(1, c); out.printf("wrote: 0x%x%n", bb.get(0)); k.interestOps(OP_READ); selector.select(); bb.clear(); while ((c = sc.read(bb)) == 0) ; - assertEquals(c, -1); + assertEquals(-1, c); } }); t.start(); @@ -806,16 +823,17 @@ public class IOExchanges { selector.select(); int c; while ((c = sc.read(bb)) == 0) ; - assertEquals(c, 1); + assertEquals(1, c); out.printf("read: 0x%x%n", bb.get(0)); - assertEquals(bb.get(0), 0x5A); + assertEquals(0x5A, bb.get(0)); } t.awaitCompletion(); deleteFile(addr); } } - @Test(dataProvider = "family") + @ParameterizedTest + @MethodSource("family") public void SPINNBAccep_BConn_NBIO_RW_6a(ProtocolFamily family) throws Throwable { try (ServerSocketChannel ssc = openServerSocketChannel(family)) { @@ -832,9 +850,9 @@ public class IOExchanges { selector.select(); int c; while ((c = sc.read(bb)) == 0) ; - assertEquals(c, 1); + assertEquals(1, c); out.printf("read: 0x%x%n", bb.get(0)); - assertEquals(bb.get(0), 0x6A); + assertEquals(0x6A, bb.get(0)); } }); t.start(); @@ -857,13 +875,13 @@ public class IOExchanges { selector.select(); int c; while ((c = sc.write(bb)) < 1) ; - assertEquals(c, 1); + assertEquals(1, c); out.printf("wrote: 0x%x%n", bb.get(0)); k.interestOps(OP_READ); selector.select(); bb.clear(); while ((c = sc.read(bb)) == 0) ; - assertEquals(c, -1); + assertEquals(-1, c); } t.awaitCompletion(); @@ -874,7 +892,8 @@ public class IOExchanges { // Similar to the previous six scenarios but with same-thread // non-blocking connect. - @Test(dataProvider = "family") + @ParameterizedTest + @MethodSource("family") public void BAccep_NBConn_NBIO_WR_7a(ProtocolFamily family) throws Throwable { try (ServerSocketChannel ssc = openServerSocketChannel(family)) { @@ -895,13 +914,13 @@ public class IOExchanges { selector.select(); int c; while ((c = sc.write(bb)) < 1) ; - assertEquals(c, 1); + assertEquals(1, c); out.printf("wrote: 0x%x%n", bb.get(0)); k.interestOps(OP_READ); selector.select(); bb.clear(); while ((c = sc.read(bb)) == 0) ; - assertEquals(c, -1); + assertEquals(-1, c); } }); t.start(); @@ -913,9 +932,9 @@ public class IOExchanges { selector.select(); int c; while ((c = sc2.read(bb)) == 0) ; - assertEquals(c, 1); + assertEquals(1, c); out.printf("read: 0x%x%n", bb.get(0)); - assertEquals(bb.get(0), 0x7A); + assertEquals(0x7A, bb.get(0)); sc2.shutdownOutput(); } t.awaitCompletion(); @@ -925,7 +944,8 @@ public class IOExchanges { } } - @Test(dataProvider = "family") + @ParameterizedTest + @MethodSource("family") public void BAccep_NBConn_NBIO_RW_8a(ProtocolFamily family) throws Throwable { try (ServerSocketChannel ssc = openServerSocketChannel(family)) { @@ -945,9 +965,9 @@ public class IOExchanges { selector.select(); int c; while ((c = sc.read(bb)) == 0) ; - assertEquals(c, 1); + assertEquals(1, c); out.printf("read: 0x%x%n", bb.get(0)); - assertEquals(bb.get(0), (byte) 0x8A); + assertEquals((byte) 0x8A, bb.get(0)); sc.shutdownOutput(); } }); @@ -960,13 +980,13 @@ public class IOExchanges { selector.select(); int c; while ((c = sc2.write(bb)) < 1) ; - assertEquals(c, 1); + assertEquals(1, c); out.printf("wrote: 0x%x%n", bb.get(0)); k.interestOps(OP_READ); selector.select(); bb.clear(); while ((c = sc2.read(bb)) == 0) ; - assertEquals(c, -1); + assertEquals(-1, c); } t.awaitCompletion(); } @@ -975,7 +995,8 @@ public class IOExchanges { } } - @Test(dataProvider = "family") + @ParameterizedTest + @MethodSource("family") public void SELNBAccep_NBConn_NBIO_WR_9a(ProtocolFamily family) throws Throwable { try (ServerSocketChannel ssc = openServerSocketChannel(family)) { @@ -988,7 +1009,7 @@ public class IOExchanges { Selector aselector = Selector.open(); ssc.configureBlocking(false).register(aselector, OP_ACCEPT); - assertEquals(aselector.select(), 1); + assertEquals(1, aselector.select()); try (SocketChannel sc2 = ssc.accept()) { assertTrue(sc.finishConnect()); @@ -1000,13 +1021,13 @@ public class IOExchanges { selector.select(); int c; while ((c = sc.write(bb)) < 1) ; - assertEquals(c, 1); + assertEquals(1, c); out.printf("wrote: 0x%x%n", bb.get(0)); k.interestOps(OP_READ); selector.select(); bb.clear(); while ((c = sc.read(bb)) == 0) ; - assertEquals(c, -1); + assertEquals(-1, c); } }); t.start(); @@ -1018,9 +1039,9 @@ public class IOExchanges { selector.select(); int c; while ((c = sc2.read(bb)) == 0) ; - assertEquals(c, 1); + assertEquals(1, c); out.printf("read: 0x%x%n", bb.get(0)); - assertEquals(bb.get(0), (byte) 0x9A); + assertEquals((byte) 0x9A, bb.get(0)); sc2.shutdownOutput(); } t.awaitCompletion(); @@ -1030,7 +1051,8 @@ public class IOExchanges { } } - @Test(dataProvider = "family") + @ParameterizedTest + @MethodSource("family") public void SELNBAccep_NBConn_NBIO_RW_10a(ProtocolFamily family) throws Throwable { try (ServerSocketChannel ssc = openServerSocketChannel(family)) { @@ -1043,7 +1065,7 @@ public class IOExchanges { Selector aselector = Selector.open(); ssc.configureBlocking(false).register(aselector, OP_ACCEPT); - assertEquals(aselector.select(), 1); + assertEquals(1, aselector.select()); try (SocketChannel sc2 = ssc.accept()) { assertTrue(sc.finishConnect()); @@ -1054,9 +1076,9 @@ public class IOExchanges { selector.select(); int c; while ((c = sc.read(bb)) == 0) ; - assertEquals(c, 1); + assertEquals(1, c); out.printf("read: 0x%x%n", bb.get(0)); - assertEquals(bb.get(0), (byte) 0xAA); + assertEquals((byte) 0xAA, bb.get(0)); sc.shutdownOutput(); } }); @@ -1069,13 +1091,13 @@ public class IOExchanges { selector.select(); int c; while ((c = sc2.write(bb)) < 1) ; - assertEquals(c, 1); + assertEquals(1, c); out.printf("wrote: 0x%x%n", bb.get(0)); k.interestOps(OP_READ); selector.select(); bb.clear(); while ((c = sc2.read(bb)) == 0) ; - assertEquals(c, -1); + assertEquals(-1, c); } t.awaitCompletion(); } @@ -1084,7 +1106,8 @@ public class IOExchanges { } } - @Test(dataProvider = "family") + @ParameterizedTest + @MethodSource("family") public void SPINBAccep_NBConn_NBIO_WR_11a(ProtocolFamily family) throws Throwable { try (ServerSocketChannel ssc = openServerSocketChannel(family)) { @@ -1115,13 +1138,13 @@ public class IOExchanges { selector.select(); int c; while ((c = sc.write(bb)) < 1) ; - assertEquals(c, 1); + assertEquals(1, c); out.printf("wrote: 0x%x%n", bb.get(0)); k.interestOps(OP_READ); selector.select(); bb.clear(); while ((c = sc.read(bb)) == 0) ; - assertEquals(c, -1); + assertEquals(-1, c); } }); t.start(); @@ -1133,9 +1156,9 @@ public class IOExchanges { selector.select(); int c; while ((c = sc2.read(bb)) == 0) ; - assertEquals(c, 1); + assertEquals(1, c); out.printf("read: 0x%x%n", bb.get(0)); - assertEquals(bb.get(0), (byte) 0xBA); + assertEquals((byte) 0xBA, bb.get(0)); sc2.shutdownOutput(); } t.awaitCompletion(); @@ -1145,7 +1168,8 @@ public class IOExchanges { } } - @Test(dataProvider = "family") + @ParameterizedTest + @MethodSource("family") public void SPINBAccep_NBConn_NBIO_RW_12a(ProtocolFamily family) throws Throwable { try (ServerSocketChannel ssc = openServerSocketChannel(family)) { @@ -1175,9 +1199,9 @@ public class IOExchanges { selector.select(); int c; while ((c = sc.read(bb)) == 0) ; - assertEquals(c, 1); + assertEquals(1, c); out.printf("read: 0x%x%n", bb.get(0)); - assertEquals(bb.get(0), (byte) 0xCA); + assertEquals((byte) 0xCA, bb.get(0)); sc.shutdownOutput(); } }); @@ -1190,13 +1214,13 @@ public class IOExchanges { selector.select(); int c; while ((c = sc2.write(bb)) < 1) ; - assertEquals(c, 1); + assertEquals(1, c); out.printf("wrote: 0x%x%n", bb.get(0)); k.interestOps(OP_READ); selector.select(); bb.clear(); while ((c = sc2.read(bb)) == 0) ; - assertEquals(c, -1); + assertEquals(-1, c); } t.awaitCompletion(); } diff --git a/test/jdk/java/nio/channels/unixdomain/NullTest.java b/test/jdk/java/nio/channels/unixdomain/NullTest.java index ed96cfdecc9..97a5b1d1b8e 100644 --- a/test/jdk/java/nio/channels/unixdomain/NullTest.java +++ b/test/jdk/java/nio/channels/unixdomain/NullTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * 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,10 +21,10 @@ * questions. */ -/** +/* * @test * @bug 8245194 - * @run testng NullTest + * @run junit NullTest */ import java.net.ProtocolFamily; @@ -32,8 +32,9 @@ import java.net.SocketAddress; import java.net.UnixDomainSocketAddress; import java.nio.channels.*; import java.nio.file.Path; -import org.testng.annotations.Test; -import static org.testng.Assert.assertThrows; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertThrows; /** * Check for NPE @@ -45,7 +46,7 @@ public class NullTest { NullPointerException.class; @Test - public static void runTest() throws Exception { + public void runTest() throws Exception { assertThrows(NPE, () -> SocketChannel.open((ProtocolFamily)null)); assertThrows(NPE, () -> SocketChannel.open((SocketAddress)null)); assertThrows(NPE, () -> ServerSocketChannel.open((ProtocolFamily)null)); From 1e3fb444c5aa0038d123c0f43858c1c4c684d958 Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Thu, 26 Mar 2026 13:54:02 +0000 Subject: [PATCH 050/359] 8380409: JVM crashes when -XX:AOTMode=create uses app.aotconf generated with JVMTI agent Reviewed-by: kvn, asmehra --- src/hotspot/share/cds/aotArtifactFinder.cpp | 27 +++++- src/hotspot/share/cds/aotArtifactFinder.hpp | 4 +- src/hotspot/share/cds/heapShared.cpp | 1 + .../aotCache/RedefineCriticalClasses.java | 83 +++++++++++++++++++ .../aotCache/TransformCriticalClasses.java | 72 ++++++++++++++++ 5 files changed, 185 insertions(+), 2 deletions(-) create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/aotCache/RedefineCriticalClasses.java create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/aotCache/TransformCriticalClasses.java diff --git a/src/hotspot/share/cds/aotArtifactFinder.cpp b/src/hotspot/share/cds/aotArtifactFinder.cpp index f85f1e46520..bd69b18a1aa 100644 --- a/src/hotspot/share/cds/aotArtifactFinder.cpp +++ b/src/hotspot/share/cds/aotArtifactFinder.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * 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 "cds/lambdaProxyClassDictionary.hpp" #include "cds/regeneratedClasses.hpp" #include "classfile/systemDictionaryShared.hpp" +#include "classfile/vmClasses.hpp" #include "logging/log.hpp" #include "memory/metaspaceClosure.hpp" #include "oops/instanceKlass.hpp" @@ -169,6 +170,7 @@ void AOTArtifactFinder::find_artifacts() { end_scanning_for_oops(); TrainingData::cleanup_training_data(); + check_critical_classes(); } void AOTArtifactFinder::start_scanning_for_oops() { @@ -233,6 +235,7 @@ void AOTArtifactFinder::add_cached_instance_class(InstanceKlass* ik) { bool created; _seen_classes->put_if_absent(ik, &created); if (created) { + check_critical_class(ik); append_to_all_cached_classes(ik); // All super types must be added. @@ -310,3 +313,25 @@ void AOTArtifactFinder::all_cached_classes_do(MetaspaceClosure* it) { it->push(_all_cached_classes->adr_at(i)); } } + +void AOTArtifactFinder::check_critical_classes() { + if (CDSConfig::is_dumping_static_archive()) { + // vmClasses are store in the AOT cache (or AOT config file, or static archive). + // If any of the vmClasses is excluded, (usually due to incompatible JVMTI agent), + // the resulting cache/config/archive is unusable. + for (auto id : EnumRange{}) { + check_critical_class(vmClasses::klass_at(id)); + } + } +} + +void AOTArtifactFinder::check_critical_class(InstanceKlass* ik) { + if (SystemDictionaryShared::is_excluded_class(ik)) { + ResourceMark rm; + const char* msg = err_msg("Critical class %s has been excluded. %s cannot be written.", + ik->external_name(), + CDSConfig::type_of_archive_being_written()); + AOTMetaspace::unrecoverable_writing_error(msg); + } +} + diff --git a/src/hotspot/share/cds/aotArtifactFinder.hpp b/src/hotspot/share/cds/aotArtifactFinder.hpp index 05bcde6b0ac..50057b6caee 100644 --- a/src/hotspot/share/cds/aotArtifactFinder.hpp +++ b/src/hotspot/share/cds/aotArtifactFinder.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -81,12 +81,14 @@ class AOTArtifactFinder : AllStatic { static void add_cached_type_array_class(TypeArrayKlass* tak); static void add_cached_instance_class(InstanceKlass* ik); static void append_to_all_cached_classes(Klass* k); + static void check_critical_class(InstanceKlass* ik); public: static void initialize(); static void find_artifacts(); static void add_cached_class(Klass* k); static void add_aot_inited_class(InstanceKlass* ik); static void all_cached_classes_do(MetaspaceClosure* it); + static void check_critical_classes(); static void dispose(); }; diff --git a/src/hotspot/share/cds/heapShared.cpp b/src/hotspot/share/cds/heapShared.cpp index 708a19e9a7d..3d10e7e1f88 100644 --- a/src/hotspot/share/cds/heapShared.cpp +++ b/src/hotspot/share/cds/heapShared.cpp @@ -564,6 +564,7 @@ bool HeapShared::archive_object(oop obj, oop referrer, KlassSubGraphInfo* subgra return false; } + AOTArtifactFinder::add_cached_class(obj->klass()); AOTOopChecker::check(obj); // Make sure contents of this oop are safe. count_allocation(obj->size()); diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/RedefineCriticalClasses.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/RedefineCriticalClasses.java new file mode 100644 index 00000000000..c4753ee3878 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/RedefineCriticalClasses.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 AOT training run should fail if critical classes have been redefined by JVMTI + * @bug 8380409 + * @requires vm.cds.supports.aot.class.linking + * @library /test/lib + * @run driver RedefineClassHelper + * @build RedefineCriticalClasses + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app.jar RedefineCriticalClassesApp + * @run driver RedefineCriticalClasses + */ + +import java.io.InputStream; +import java.net.URL; +import java.util.ArrayList; +import jdk.test.lib.cds.CDSTestUtils; +import jdk.test.lib.helpers.ClassFileInstaller; +import jdk.test.lib.process.ProcessTools; + +public class RedefineCriticalClasses { + public static void main(String... args) throws Exception { + ArrayList processArgs = new ArrayList<>(); + + // redefineagent.jar is created by "@run driver RedefineClassHelper" + processArgs.add("-javaagent:redefineagent.jar"); + + processArgs.add("-XX:AOTMode=record"); + processArgs.add("-XX:AOTConfiguration=app.aotconfig"); + processArgs.add("-Xlog:aot,cds"); + processArgs.add("-cp"); + processArgs.add("app.jar"); + processArgs.add("RedefineCriticalClassesApp"); + + ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(processArgs); + CDSTestUtils.executeAndLog(pb, "train") + .shouldContain("Redefined: class java.lang.Class") + .shouldContain("Skipping java/lang/Class: Has been redefined") + .shouldContain("Critical class java.lang.Class has been excluded. AOT configuration file cannot be written") + .shouldHaveExitValue(1); + } +} + +class RedefineCriticalClassesApp { + public static void main(String[] args) throws Exception { + // Use RedefineClassHelper (loaded from redefineagent.jar into the boot class loader) + // to redefine java/lang/Class, using the exact same bytecodes as from the JDK. + // The JVM will mark it as having been redefined by JVMTI and will exclude it from the + // AOT configuration file. + + URL url = new URL("jrt:/java.base/java/lang/Class.class"); + try (InputStream in = url.openConnection().getInputStream()) { + byte[] b = in.readAllBytes(); + System.out.println("Length = " + b.length); + RedefineClassHelper.redefineClass(Class.class, b); + System.out.println("Redefined: " + Class.class); + } + } +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/TransformCriticalClasses.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/TransformCriticalClasses.java new file mode 100644 index 00000000000..9f25d58e01f --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/TransformCriticalClasses.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 AOT training run should fail if critical classes have been transformed by JVMTI + * with ClassFileLoadHook + * @bug 8380409 + * @requires vm.cds.supports.aot.class.linking + * @library /test/lib + * @build TransformCriticalClasses + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app.jar TransformCriticalClassesApp + * @run main/othervm/native TransformCriticalClasses + */ + +import java.util.ArrayList; +import jdk.test.lib.cds.CDSTestUtils; +import jdk.test.lib.helpers.ClassFileInstaller; +import jdk.test.lib.process.ProcessTools; + +public class TransformCriticalClasses { + public static void main(String... args) throws Exception { + ArrayList processArgs = new ArrayList<>(); + + // Tell the native agent SimpleClassFileLoadHook to do an dummy transformation + // of java/lang/Class. This class will be defined using the exact same bytecodes + // as from the JDK, but the JVM will mark it as having been transformed by JVMTI + // and will exclude it from the AOT configuration file. + processArgs.add("-agentlib:SimpleClassFileLoadHook=-early,java/lang/Class,xxxxxx,xxxxxx"); + + processArgs.add("-XX:AOTMode=record"); + processArgs.add("-XX:AOTConfiguration=app.aotconfig"); + processArgs.add("-Xlog:aot,cds"); + processArgs.add("-cp"); + processArgs.add("app.jar"); + processArgs.add("TransformCriticalClassesApp"); + + ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(processArgs); + CDSTestUtils.executeAndLog(pb, "train") + .shouldContain("Skipping java/lang/Class: From ClassFileLoadHook") + .shouldContain("Critical class java.lang.Class has been excluded. AOT configuration file cannot be written") + .shouldHaveExitValue(1); + } +} + +class TransformCriticalClassesApp { + public static void main(String[] args) { + System.out.println("HelloWorld"); + } +} From b3048bbed0ab050f139d117e11657a2eef081861 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20H=C3=BCbner?= Date: Thu, 26 Mar 2026 14:09:17 +0000 Subject: [PATCH 051/359] 8370504: InterpreterMacroAssembler::profile_virtual_call parameter 'receiver_can_be_null' is unused Reviewed-by: aseoane, azafari, mchevalier, fbredberg --- src/hotspot/cpu/aarch64/interp_masm_aarch64.cpp | 15 ++------------- src/hotspot/cpu/aarch64/interp_masm_aarch64.hpp | 5 ++--- src/hotspot/cpu/arm/interp_masm_arm.cpp | 15 ++------------- src/hotspot/cpu/arm/interp_masm_arm.hpp | 5 ++--- src/hotspot/cpu/ppc/interp_masm_ppc.hpp | 4 ++-- src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp | 17 ++--------------- src/hotspot/cpu/ppc/templateTable_ppc_64.cpp | 6 +++--- src/hotspot/cpu/riscv/interp_masm_riscv.cpp | 15 ++------------- src/hotspot/cpu/riscv/interp_masm_riscv.hpp | 5 ++--- src/hotspot/cpu/s390/interp_masm_s390.cpp | 16 ++-------------- src/hotspot/cpu/s390/interp_masm_s390.hpp | 5 ++--- src/hotspot/cpu/x86/interp_masm_x86.cpp | 17 ++--------------- src/hotspot/cpu/x86/interp_masm_x86.hpp | 5 ++--- 13 files changed, 27 insertions(+), 103 deletions(-) diff --git a/src/hotspot/cpu/aarch64/interp_masm_aarch64.cpp b/src/hotspot/cpu/aarch64/interp_masm_aarch64.cpp index 2b506b241e0..980fedb406d 100644 --- a/src/hotspot/cpu/aarch64/interp_masm_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/interp_masm_aarch64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -989,26 +989,15 @@ void InterpreterMacroAssembler::profile_final_call(Register mdp) { void InterpreterMacroAssembler::profile_virtual_call(Register receiver, - Register mdp, - bool receiver_can_be_null) { + Register mdp) { if (ProfileInterpreter) { Label profile_continue; // If no method data exists, go to profile_continue. test_method_data_pointer(mdp, profile_continue); - Label skip_receiver_profile; - if (receiver_can_be_null) { - Label not_null; - // We are making a call. Increment the count for null receiver. - increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); - b(skip_receiver_profile); - bind(not_null); - } - // Record the receiver type. profile_receiver_type(receiver, mdp, 0); - bind(skip_receiver_profile); // The method data pointer needs to be updated to reflect the new target. update_mdp_by_constant(mdp, in_bytes(VirtualCallData::virtual_call_data_size())); diff --git a/src/hotspot/cpu/aarch64/interp_masm_aarch64.hpp b/src/hotspot/cpu/aarch64/interp_masm_aarch64.hpp index 74d4430000d..9a074f1ce69 100644 --- a/src/hotspot/cpu/aarch64/interp_masm_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/interp_masm_aarch64.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2015, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -285,8 +285,7 @@ class InterpreterMacroAssembler: public MacroAssembler { void profile_not_taken_branch(Register mdp); void profile_call(Register mdp); void profile_final_call(Register mdp); - void profile_virtual_call(Register receiver, Register mdp, - bool receiver_can_be_null = false); + void profile_virtual_call(Register receiver, Register mdp); void profile_ret(Register return_bci, Register mdp); void profile_null_seen(Register mdp); void profile_typecheck(Register mdp, Register klass); diff --git a/src/hotspot/cpu/arm/interp_masm_arm.cpp b/src/hotspot/cpu/arm/interp_masm_arm.cpp index 23ecea24eb2..aee407864ee 100644 --- a/src/hotspot/cpu/arm/interp_masm_arm.cpp +++ b/src/hotspot/cpu/arm/interp_masm_arm.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1210,7 +1210,7 @@ void InterpreterMacroAssembler::profile_final_call(Register mdp) { // Sets mdp, blows Rtemp. -void InterpreterMacroAssembler::profile_virtual_call(Register mdp, Register receiver, bool receiver_can_be_null) { +void InterpreterMacroAssembler::profile_virtual_call(Register mdp, Register receiver) { assert_different_registers(mdp, receiver, Rtemp); if (ProfileInterpreter) { @@ -1219,19 +1219,8 @@ void InterpreterMacroAssembler::profile_virtual_call(Register mdp, Register rece // If no method data exists, go to profile_continue. test_method_data_pointer(mdp, profile_continue); - Label skip_receiver_profile; - if (receiver_can_be_null) { - Label not_null; - cbnz(receiver, not_null); - // We are making a call. Increment the count for null receiver. - increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset()), Rtemp); - b(skip_receiver_profile); - bind(not_null); - } - // Record the receiver type. record_klass_in_profile(receiver, mdp, Rtemp, true); - bind(skip_receiver_profile); // The method data pointer needs to be updated to reflect the new target. update_mdp_by_constant(mdp, in_bytes(VirtualCallData::virtual_call_data_size())); diff --git a/src/hotspot/cpu/arm/interp_masm_arm.hpp b/src/hotspot/cpu/arm/interp_masm_arm.hpp index 530be1c577e..147cd252b2c 100644 --- a/src/hotspot/cpu/arm/interp_masm_arm.hpp +++ b/src/hotspot/cpu/arm/interp_masm_arm.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -239,8 +239,7 @@ class InterpreterMacroAssembler: public MacroAssembler { void profile_call(Register mdp); // Sets mdp, blows Rtemp. void profile_final_call(Register mdp); // Sets mdp, blows Rtemp. - void profile_virtual_call(Register mdp, Register receiver, // Sets mdp, blows Rtemp. - bool receiver_can_be_null = false); + void profile_virtual_call(Register mdp, Register receiver); // Sets mdp, blows Rtemp. void profile_ret(Register mdp, Register return_bci); // Sets mdp, blows R0-R3/R0-R18, Rtemp, LR void profile_null_seen(Register mdp); // Sets mdp. void profile_typecheck(Register mdp, Register klass); // Sets mdp, blows Rtemp. diff --git a/src/hotspot/cpu/ppc/interp_masm_ppc.hpp b/src/hotspot/cpu/ppc/interp_masm_ppc.hpp index 4ea33ebaf63..275ff92c699 100644 --- a/src/hotspot/cpu/ppc/interp_masm_ppc.hpp +++ b/src/hotspot/cpu/ppc/interp_masm_ppc.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2025 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -258,7 +258,7 @@ class InterpreterMacroAssembler: public MacroAssembler { void profile_not_taken_branch(Register scratch1, Register scratch2); void profile_call(Register scratch1, Register scratch2); void profile_final_call(Register scratch1, Register scratch2); - void profile_virtual_call(Register Rreceiver, Register Rscratch1, Register Rscratch2, bool receiver_can_be_null); + void profile_virtual_call(Register Rreceiver, Register Rscratch1, Register Rscratch2); void profile_typecheck(Register Rklass, Register Rscratch1, Register Rscratch2); void profile_ret(TosState state, Register return_bci, Register scratch1, Register scratch2); void profile_switch_default(Register scratch1, Register scratch2); diff --git a/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp b/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp index f7bf457f72c..56eade8e533 100644 --- a/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp +++ b/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2025 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -1340,28 +1340,15 @@ void InterpreterMacroAssembler::profile_final_call(Register scratch1, Register s // Count a virtual call in the bytecodes. void InterpreterMacroAssembler::profile_virtual_call(Register Rreceiver, Register Rscratch1, - Register Rscratch2, - bool receiver_can_be_null) { + Register Rscratch2) { if (!ProfileInterpreter) { return; } Label profile_continue; // If no method data exists, go to profile_continue. test_method_data_pointer(profile_continue); - Label skip_receiver_profile; - if (receiver_can_be_null) { - Label not_null; - cmpdi(CR0, Rreceiver, 0); - bne(CR0, not_null); - // We are making a call. Increment the count for null receiver. - increment_mdp_data_at(in_bytes(CounterData::count_offset()), Rscratch1, Rscratch2); - b(skip_receiver_profile); - bind(not_null); - } - // Record the receiver type. record_klass_in_profile(Rreceiver, Rscratch1, Rscratch2); - bind(skip_receiver_profile); // The method data pointer needs to be updated to reflect the new target. update_mdp_by_constant(in_bytes(VirtualCallData::virtual_call_data_size())); diff --git a/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp b/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp index 8a3af748fa1..37f780535b4 100644 --- a/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp +++ b/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp @@ -3489,7 +3489,7 @@ void TemplateTable::invokevirtual(int byte_no) { // Get receiver klass. __ load_klass_check_null_throw(Rrecv_klass, Rrecv, R11_scratch1); __ verify_klass_ptr(Rrecv_klass); - __ profile_virtual_call(Rrecv_klass, R11_scratch1, R12_scratch2, false); + __ profile_virtual_call(Rrecv_klass, R11_scratch1, R12_scratch2); generate_vtable_call(Rrecv_klass, Rvtableindex_or_method, Rret_addr, R11_scratch1); } @@ -3596,7 +3596,7 @@ void TemplateTable::invokeinterface_object_method(Register Rrecv_klass, // Non-final callc case. __ bind(LnotFinal); __ lhz(Rindex, in_bytes(ResolvedMethodEntry::table_index_offset()), Rcache); - __ profile_virtual_call(Rrecv_klass, Rtemp1, Rscratch, false); + __ profile_virtual_call(Rrecv_klass, Rtemp1, Rscratch); generate_vtable_call(Rrecv_klass, Rindex, Rret, Rscratch); } @@ -3664,7 +3664,7 @@ void TemplateTable::invokeinterface(int byte_no) { __ lookup_interface_method(Rrecv_klass, Rinterface_klass, noreg, noreg, Rscratch1, Rscratch2, L_no_such_interface, /*return_method=*/false); - __ profile_virtual_call(Rrecv_klass, Rscratch1, Rscratch2, false); + __ profile_virtual_call(Rrecv_klass, Rscratch1, Rscratch2); // Find entry point to call. diff --git a/src/hotspot/cpu/riscv/interp_masm_riscv.cpp b/src/hotspot/cpu/riscv/interp_masm_riscv.cpp index 744590bec2b..804c2072ba5 100644 --- a/src/hotspot/cpu/riscv/interp_masm_riscv.cpp +++ b/src/hotspot/cpu/riscv/interp_masm_riscv.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved. * Copyright (c) 2020, 2023, Huawei Technologies Co., Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -1040,26 +1040,15 @@ void InterpreterMacroAssembler::profile_final_call(Register mdp) { void InterpreterMacroAssembler::profile_virtual_call(Register receiver, - Register mdp, - bool receiver_can_be_null) { + Register mdp) { if (ProfileInterpreter) { Label profile_continue; // If no method data exists, go to profile_continue. test_method_data_pointer(mdp, profile_continue); - Label skip_receiver_profile; - if (receiver_can_be_null) { - Label not_null; - // We are making a call. Increment the count for null receiver. - increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); - j(skip_receiver_profile); - bind(not_null); - } - // Record the receiver type. profile_receiver_type(receiver, mdp, 0); - bind(skip_receiver_profile); // The method data pointer needs to be updated to reflect the new target. diff --git a/src/hotspot/cpu/riscv/interp_masm_riscv.hpp b/src/hotspot/cpu/riscv/interp_masm_riscv.hpp index 59cc76b022f..df86f0dc532 100644 --- a/src/hotspot/cpu/riscv/interp_masm_riscv.hpp +++ b/src/hotspot/cpu/riscv/interp_masm_riscv.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2015, Red Hat Inc. 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. @@ -274,8 +274,7 @@ class InterpreterMacroAssembler: public MacroAssembler { void profile_not_taken_branch(Register mdp); void profile_call(Register mdp); void profile_final_call(Register mdp); - void profile_virtual_call(Register receiver, Register mdp, - bool receiver_can_be_null = false); + void profile_virtual_call(Register receiver, Register mdp); void profile_ret(Register return_bci, Register mdp); void profile_null_seen(Register mdp); void profile_typecheck(Register mdp, Register klass); diff --git a/src/hotspot/cpu/s390/interp_masm_s390.cpp b/src/hotspot/cpu/s390/interp_masm_s390.cpp index a80ca26239b..d5239898dd7 100644 --- a/src/hotspot/cpu/s390/interp_masm_s390.cpp +++ b/src/hotspot/cpu/s390/interp_masm_s390.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2016, 2024 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -1259,27 +1259,15 @@ void InterpreterMacroAssembler::profile_final_call(Register mdp) { void InterpreterMacroAssembler::profile_virtual_call(Register receiver, Register mdp, - Register reg2, - bool receiver_can_be_null) { + Register reg2) { if (ProfileInterpreter) { NearLabel profile_continue; // If no method data exists, go to profile_continue. test_method_data_pointer(mdp, profile_continue); - NearLabel skip_receiver_profile; - if (receiver_can_be_null) { - NearLabel not_null; - compareU64_and_branch(receiver, (intptr_t)0L, bcondNotEqual, not_null); - // We are making a call. Increment the count for null receiver. - increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); - z_bru(skip_receiver_profile); - bind(not_null); - } - // Record the receiver type. record_klass_in_profile(receiver, mdp, reg2); - bind(skip_receiver_profile); // The method data pointer needs to be updated to reflect the new target. update_mdp_by_constant(mdp, in_bytes(VirtualCallData::virtual_call_data_size())); diff --git a/src/hotspot/cpu/s390/interp_masm_s390.hpp b/src/hotspot/cpu/s390/interp_masm_s390.hpp index d981f9ea01e..b816185b065 100644 --- a/src/hotspot/cpu/s390/interp_masm_s390.hpp +++ b/src/hotspot/cpu/s390/interp_masm_s390.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2016, 2024 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -296,8 +296,7 @@ class InterpreterMacroAssembler: public MacroAssembler { void profile_call(Register mdp); void profile_final_call(Register mdp); void profile_virtual_call(Register receiver, Register mdp, - Register scratch2, - bool receiver_can_be_null = false); + Register scratch2); void profile_ret(Register return_bci, Register mdp); void profile_null_seen(Register mdp); void profile_typecheck(Register mdp, Register klass, Register scratch); diff --git a/src/hotspot/cpu/x86/interp_masm_x86.cpp b/src/hotspot/cpu/x86/interp_masm_x86.cpp index b2ea4143ac4..a38971c86fb 100644 --- a/src/hotspot/cpu/x86/interp_masm_x86.cpp +++ b/src/hotspot/cpu/x86/interp_masm_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1392,28 +1392,15 @@ void InterpreterMacroAssembler::profile_final_call(Register mdp) { void InterpreterMacroAssembler::profile_virtual_call(Register receiver, - Register mdp, - bool receiver_can_be_null) { + Register mdp) { if (ProfileInterpreter) { Label profile_continue; // If no method data exists, go to profile_continue. test_method_data_pointer(mdp, profile_continue); - Label skip_receiver_profile; - if (receiver_can_be_null) { - Label not_null; - testptr(receiver, receiver); - jccb(Assembler::notZero, not_null); - // We are making a call. Increment the count for null receiver. - increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); - jmp(skip_receiver_profile); - bind(not_null); - } - // Record the receiver type. profile_receiver_type(receiver, mdp, 0); - bind(skip_receiver_profile); // The method data pointer needs to be updated to reflect the new target. update_mdp_by_constant(mdp, in_bytes(VirtualCallData::virtual_call_data_size())); diff --git a/src/hotspot/cpu/x86/interp_masm_x86.hpp b/src/hotspot/cpu/x86/interp_masm_x86.hpp index 4114028f78e..dfbd7ab64e0 100644 --- a/src/hotspot/cpu/x86/interp_masm_x86.hpp +++ b/src/hotspot/cpu/x86/interp_masm_x86.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * 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,8 +243,7 @@ class InterpreterMacroAssembler: public MacroAssembler { void profile_not_taken_branch(Register mdp); void profile_call(Register mdp); void profile_final_call(Register mdp); - void profile_virtual_call(Register receiver, Register mdp, - bool receiver_can_be_null = false); + void profile_virtual_call(Register receiver, Register mdp); void profile_ret(Register return_bci, Register mdp); void profile_null_seen(Register mdp); void profile_typecheck(Register mdp, Register klass); From 22831cb0d8f828327b49f45e04f2a62ae33754ee Mon Sep 17 00:00:00 2001 From: Kerem Kat Date: Thu, 26 Mar 2026 14:15:11 +0000 Subject: [PATCH 052/359] 8378005: Exclude boxing calls from guaranteed safepoint check in loop opts Reviewed-by: mhaessig, chagedorn --- src/hotspot/share/opto/loopnode.cpp | 16 +++- .../TestBoxingInfiniteLoopBrokenIf.java | 88 +++++++++++++++++++ ...TestStressLongCountedLoopInfiniteLoop.java | 75 ++++++++++++++++ 3 files changed, 176 insertions(+), 3 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/loopopts/TestBoxingInfiniteLoopBrokenIf.java create mode 100644 test/hotspot/jtreg/compiler/loopopts/TestStressLongCountedLoopInfiniteLoop.java diff --git a/src/hotspot/share/opto/loopnode.cpp b/src/hotspot/share/opto/loopnode.cpp index 686a0a05f66..23186a25320 100644 --- a/src/hotspot/share/opto/loopnode.cpp +++ b/src/hotspot/share/opto/loopnode.cpp @@ -4345,8 +4345,13 @@ void IdealLoopTree::allpaths_check_safepts(VectorSet &visited, Node_List &stack) visited.set(_head->_idx); while (stack.size() > 0) { Node* n = stack.pop(); - if (n->is_Call() && n->as_Call()->guaranteed_safepoint()) { - // Terminate this path + if (n->is_Call() && n->as_Call()->guaranteed_safepoint() + && !(n->is_CallStaticJava() && n->as_CallStaticJava()->is_boxing_method())) { + // Terminate this path: guaranteed safepoint found. + // Boxing CallStaticJava calls are excluded as they may lack a safepoint on the fast path. This is + // not done via CallStaticJavaNode::guaranteed_safepoint() as that also controls PcDesc emission. + // In the future, guaranteed_safepoint() should be reworked to correctly handle boxing methods + // to avoid this additional check. } else if (n->Opcode() == Op_SafePoint) { if (_phase->get_loop(n) != this) { if (_required_safept == nullptr) _required_safept = new Node_List(); @@ -4444,7 +4449,12 @@ void IdealLoopTree::check_safepts(VectorSet &visited, Node_List &stack) { if (!_irreducible) { // Scan the dom-path nodes from tail to head for (Node* n = tail(); n != _head; n = _phase->idom(n)) { - if (n->is_Call() && n->as_Call()->guaranteed_safepoint()) { + // Boxing CallStaticJava calls are excluded as they may lack a safepoint on the fast path. This is + // not done via CallStaticJavaNode::guaranteed_safepoint() as that also controls PcDesc emission. + // In the future, guaranteed_safepoint() should be reworked to correctly handle boxing methods + // to avoid this additional check. + if (n->is_Call() && n->as_Call()->guaranteed_safepoint() + && !(n->is_CallStaticJava() && n->as_CallStaticJava()->is_boxing_method())) { has_call = true; _has_sfpt = 1; // Then no need for a safept! break; diff --git a/test/hotspot/jtreg/compiler/loopopts/TestBoxingInfiniteLoopBrokenIf.java b/test/hotspot/jtreg/compiler/loopopts/TestBoxingInfiniteLoopBrokenIf.java new file mode 100644 index 00000000000..18b4816445b --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/TestBoxingInfiniteLoopBrokenIf.java @@ -0,0 +1,88 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8378005 + * @summary Verify that an infinite loop with boxing does not crash when the containing If is broken + * @library /test/lib / + * @run driver ${test.main.class} + */ + +package compiler.loopopts; +import compiler.lib.ir_framework.*; +import jdk.test.lib.Utils; + +public class TestBoxingInfiniteLoopBrokenIf { + static boolean flag; + static volatile boolean testReturned; + + public static void main(String[] args) { + TestFramework framework = new TestFramework(); + framework.addScenarios( + new Scenario(0), + new Scenario(1, "-XX:PerMethodTrapLimit=0", "-XX:CompileCommand=dontinline,*::valueOf", "-XX:CompileCommand=dontinline,*::throwWrongPath"), + new Scenario(2, "-XX:PerMethodTrapLimit=0", "-XX:CompileCommand=dontinline,*::valueOf", "-XX:CompileCommand=dontinline,*::throwWrongPath", + "-XX:+IgnoreUnrecognizedVMOptions", "-XX:StressLongCountedLoop=1") + ); + framework.start(); + } + + @Test + static void test() { + new Integer(0); // Enable EA + Loop opts + + if (flag) { // Always false + throwWrongPath(); // Not inlined to simplify graph + } else { + // Infinite loop: j is always 0, Integer.valueOf(0) < 1 is always true. + for (int j = 0; Integer.valueOf(j) < 1;) { + j = 0; + } + } + } + + @Run(test = "test") + @Warmup(0) + static void runTest(RunInfo info) { + testReturned = false; + Thread thread = new Thread(() -> { + test(); + testReturned = true; + }); + thread.setDaemon(true); + thread.start(); + try { + Thread.sleep(Utils.adjustTimeout(500)); + } catch (InterruptedException e) { + } + if (testReturned) { + throw new RuntimeException("test() should not return: infinite loop was incorrectly optimized away"); + } + } + + static void throwWrongPath() { + throw new RuntimeException("Wrong path"); + } +} diff --git a/test/hotspot/jtreg/compiler/loopopts/TestStressLongCountedLoopInfiniteLoop.java b/test/hotspot/jtreg/compiler/loopopts/TestStressLongCountedLoopInfiniteLoop.java new file mode 100644 index 00000000000..81996018a2b --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/TestStressLongCountedLoopInfiniteLoop.java @@ -0,0 +1,75 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8378005 + * @summary assert in proj_out when StressLongCountedLoop converts infinite loop to long counted loop nest + * @run main ${test.main.class} + * @run main/othervm -Xbatch -XX:-TieredCompilation -XX:+IgnoreUnrecognizedVMOptions -XX:StressLongCountedLoop=1 + * -XX:CompileCommand=compileonly,${test.main.class}::test ${test.main.class} + */ + +package compiler.loopopts; + +public class TestStressLongCountedLoopInfiniteLoop { + static int RANGE; + + public static void main(String[] args) { + int[] a = new int[RANGE]; + for (int i = 0; i < 10000; i++) { + try { + test(a, 0); + } catch (ArrayIndexOutOfBoundsException e) { + } + } + } + + static void test(int[] a, int invar) { + // new Integer(0) works too, using MyInteger to avoid deprecation warnings. + a[new MyInteger(0).v()] = 0; + + Object o; + for (int i = 0; i < 1; i++) { + o = 1; + } + + // Infinite loop: j is always 0, 0 < 1 is always true. + for (int j = 0; Integer.valueOf(j) < 1;) { + j = 0; + } + } + + static class MyInteger { + int v; + + MyInteger(int v) { + this.v = v; + } + + int v() { + return Integer.valueOf(v); + } + } +} From 8ecb14cecf1f05ea7c65fcfb5bb05e1e3a895d72 Mon Sep 17 00:00:00 2001 From: Yasumasa Suenaga Date: Thu, 26 Mar 2026 14:50:56 +0000 Subject: [PATCH 053/359] 8379454: SA still calculates end address with incorrect alignment Reviewed-by: kevinw, cjplummer --- src/jdk.hotspot.agent/linux/native/libsaproc/libproc_impl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/libproc_impl.c b/src/jdk.hotspot.agent/linux/native/libsaproc/libproc_impl.c index e2681be73fe..029aac1f107 100644 --- a/src/jdk.hotspot.agent/linux/native/libsaproc/libproc_impl.c +++ b/src/jdk.hotspot.agent/linux/native/libsaproc/libproc_impl.c @@ -182,13 +182,14 @@ static bool fill_addr_info(lib_info* lib) { return false; } + long page_size = sysconf(_SC_PAGE_SIZE); lib->end = (uintptr_t)-1L; lib->exec_start = (uintptr_t)-1L; lib->exec_end = (uintptr_t)-1L; for (ph = phbuf, cnt = 0; cnt < ehdr.e_phnum; cnt++, ph++) { if (ph->p_type == PT_LOAD) { uintptr_t aligned_start = lib->base + align_down(ph->p_vaddr, ph->p_align); - uintptr_t aligned_end = aligned_start + align_up(ph->p_memsz, ph->p_align); + uintptr_t aligned_end = aligned_start + align_up(ph->p_memsz, page_size); if ((lib->end == (uintptr_t)-1L) || (lib->end < aligned_end)) { lib->end = aligned_end; } From 541557ad1d9dfacc63490b5bd30e20455b0332c4 Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Thu, 26 Mar 2026 17:19:50 +0000 Subject: [PATCH 054/359] 8380671: Refactor BasicFloat16ArithTests.java Reviewed-by: bpb --- .../vector/BasicFloat16ArithTests.java | 58 ++++++++++--------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/test/jdk/jdk/incubator/vector/BasicFloat16ArithTests.java b/test/jdk/jdk/incubator/vector/BasicFloat16ArithTests.java index 755745394fc..cdc7ce566f7 100644 --- a/test/jdk/jdk/incubator/vector/BasicFloat16ArithTests.java +++ b/test/jdk/jdk/incubator/vector/BasicFloat16ArithTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * 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,8 @@ public class BasicFloat16ArithTests { private static float NaNf = Float.NaN; private static final float MAX_VAL_FP16 = 0x1.ffcp15f; + private static final float MIN_NRM_FP16 = 0x1.0p-14f; + private static final float MIN_VAL_FP16 = 0x1.0p-24f; public static void main(String... args) { checkBitWise(); @@ -145,9 +147,9 @@ public class BasicFloat16ArithTests { checkInt(PRECISION, 11, "Float16.PRECISION"); checkInt(SIZE, 16, "Float16.SIZE"); - checkFloat16(MIN_VALUE, 0x1.0p-24f, "Float16.MIN_VALUE"); - checkFloat16(MIN_NORMAL, 0x1.0p-14f, "Float16.MIN_NORMAL"); - checkFloat16(MAX_VALUE, 65504.0f, "Float16.MAX_VALUE"); + checkFloat16(MIN_VALUE, MIN_VAL_FP16, "Float16.MIN_VALUE"); + checkFloat16(MIN_NORMAL, MIN_NRM_FP16, "Float16.MIN_NORMAL"); + checkFloat16(MAX_VALUE, 65504.0f, "Float16.MAX_VALUE"); checkFloat16(POSITIVE_INFINITY, InfinityF, "+infinity"); checkFloat16(NEGATIVE_INFINITY, -InfinityF, "-infinity"); @@ -389,12 +391,12 @@ public class BasicFloat16ArithTests { { NaNf, MAX_EXPONENT + 1}, // Subnormal and almost subnormal values - {-0.0f, MIN_EXPONENT - 1}, - {+0.0f, MIN_EXPONENT - 1}, - { 0x1.0p-24f, MIN_EXPONENT - 1}, // Float16.MIN_VALUE - {-0x1.0p-24f, MIN_EXPONENT - 1}, // Float16.MIN_VALUE - { 0x1.0p-14f, MIN_EXPONENT}, // Float16.MIN_NORMAL - {-0x1.0p-14f, MIN_EXPONENT}, // Float16.MIN_NORMAL + {-0.0f, MIN_EXPONENT - 1}, + {+0.0f, MIN_EXPONENT - 1}, + { MIN_VAL_FP16, MIN_EXPONENT - 1}, + {-MIN_VAL_FP16, MIN_EXPONENT - 1}, + { MIN_NRM_FP16, MIN_EXPONENT}, + {-MIN_NRM_FP16, MIN_EXPONENT}, // Normal values { 1.0f, 0}, @@ -424,17 +426,17 @@ public class BasicFloat16ArithTests { { NaNf, NaNf}, // Zeros, subnormals, and MIN_VALUE all have MIN_VALUE as an ulp. - {-0.0f, 0x1.0p-24f}, - {+0.0f, 0x1.0p-24f}, - { 0x1.0p-24f, 0x1.0p-24f}, - {-0x1.0p-24f, 0x1.0p-24f}, - { 0x1.0p-14f, 0x1.0p-24f}, - {-0x1.0p-14f, 0x1.0p-24f}, + {-0.0f, MIN_VAL_FP16}, + {+0.0f, MIN_VAL_FP16}, + { MIN_VAL_FP16, MIN_VAL_FP16}, + {-MIN_VAL_FP16, MIN_VAL_FP16}, + { MIN_NRM_FP16, MIN_VAL_FP16}, + {-MIN_NRM_FP16, MIN_VAL_FP16}, - // ulp is 10 bits away - {0x1.0p0f, 0x0.004p0f}, // 1.0f - {0x1.0p1f, 0x0.004p1f}, // 2.0f - {0x1.0p2f, 0x0.004p2f}, // 4.0f + // ulp is (PRECISION - 1) = 10 bits away + {0x1.0p0f, 0x1.0p-10f}, // 1.0f + {0x1.0p1f, 0x1.0p-9f}, // 2.0f + {0x1.0p2f, 0x1.0p-8f}, // 4.0f {MAX_VAL_FP16*0.5f, 0x0.004p14f}, {MAX_VAL_FP16, 0x0.004p15f}, @@ -507,12 +509,12 @@ public class BasicFloat16ArithTests { } private static void checkValueOfLong() { - checkFloat16(valueOf(-65_521), Float.NEGATIVE_INFINITY, "-infinity"); - checkFloat16(valueOf(-65_520), Float.NEGATIVE_INFINITY, "-infinity"); - checkFloat16(valueOf(-65_519), -MAX_VALUE.floatValue(), "-MAX_VALUE"); - checkFloat16(valueOf(65_519), MAX_VALUE.floatValue(), "MAX_VALUE"); - checkFloat16(valueOf(65_520), Float.POSITIVE_INFINITY, "+infinity"); - checkFloat16(valueOf(65_521), Float.POSITIVE_INFINITY, "+infinity"); + checkFloat16(valueOf(-65_521), Float.NEGATIVE_INFINITY, "-65_521"); + checkFloat16(valueOf(-65_520), Float.NEGATIVE_INFINITY, "-65_520"); + checkFloat16(valueOf(-65_519), -MAX_VALUE.floatValue(), "-65_519"); + checkFloat16(valueOf( 65_519), MAX_VALUE.floatValue(), "65_519"); + checkFloat16(valueOf( 65_520), Float.POSITIVE_INFINITY, "65_520"); + checkFloat16(valueOf( 65_521), Float.POSITIVE_INFINITY, "65_521"); } private static void checkValueOfString() { @@ -792,7 +794,7 @@ public class BasicFloat16ArithTests { // threshold; subtracting a non-zero finite value will // result in MAX_VALUE, adding zero or a positive // value will overflow. - {0x1.2p10f, 0x1.c7p5f, -0x1.0p-14f, + {0x1.2p10f, 0x1.c7p5f, -MIN_NRM_FP16, MAX_VAL_FP16}, {0x1.2p10f, 0x1.c7p5f, -0.0f, @@ -801,7 +803,7 @@ public class BasicFloat16ArithTests { {0x1.2p10f, 0x1.c7p5f, +0.0f, InfinityF}, - {0x1.2p10f, 0x1.c7p5f, +0x1.0p-14f, + {0x1.2p10f, 0x1.c7p5f, +MIN_NRM_FP16, InfinityF}, {0x1.2p10f, 0x1.c7p5f, InfinityF, From aecc16358f5f1f6fa5cb78522d6db70430b79987 Mon Sep 17 00:00:00 2001 From: Naoto Sato Date: Thu, 26 Mar 2026 17:53:53 +0000 Subject: [PATCH 055/359] 8230421: Java cannot handle Euro sign at the Simplified Chinese Windows Command Prompt Reviewed-by: sherman --- .../windows/native/libjava/java_props_md.c | 67 +++++++++---------- 1 file changed, 32 insertions(+), 35 deletions(-) diff --git a/src/java.base/windows/native/libjava/java_props_md.c b/src/java.base/windows/native/libjava/java_props_md.c index e152dbe9bef..6504891af34 100644 --- a/src/java.base/windows/native/libjava/java_props_md.c +++ b/src/java.base/windows/native/libjava/java_props_md.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -74,43 +74,32 @@ getEncodingInternal(LCID lcid) case 65001: strcpy(ret, "UTF-8"); break; - case 874: /* 9:Thai */ - case 932: /* 10:Japanese */ - case 949: /* 12:Korean Extended Wansung */ - case 950: /* 13:Chinese (Taiwan, Hongkong, Macau) */ - case 1361: /* 15:Korean Johab */ + case 874: /* Thai */ + case 932: /* Japanese */ + case 936: /* Chinese (Simplified) */ + case 949: /* Korean Extended Wansung */ + case 950: /* Chinese (Taiwan, Hongkong, Macau) */ + case 1361: /* Korean Johab */ ret[0] = 'M'; ret[1] = 'S'; - break; - case 936: - strcpy(ret, "GBK"); - break; - case 54936: - strcpy(ret, "GB18030"); - break; - default: - ret[0] = 'C'; - ret[1] = 'p'; - break; - } - //Traditional Chinese Windows should use MS950_HKSCS_XP as the - //default encoding, if HKSCS patch has been installed. - // "old" MS950 0xfa41 -> u+e001 - // "new" MS950 0xfa41 -> u+92db - if (strcmp(ret, "MS950") == 0) { - TCHAR mbChar[2] = {(char)0xfa, (char)0x41}; - WCHAR unicodeChar; - MultiByteToWideChar(CP_ACP, 0, mbChar, 2, &unicodeChar, 1); - if (unicodeChar == 0x92db) { - strcpy(ret, "MS950_HKSCS_XP"); - } - } else { - //SimpChinese Windows should use GB18030 as the default - //encoding, if gb18030 patch has been installed (on windows - //2000/XP, (1)Codepage 54936 will be available - //(2)simsun18030.ttc will exist under system fonts dir ) - if (strcmp(ret, "GBK") == 0 && IsValidCodePage(54936)) { + // Special handling for Chinese + if (codepage == 950) { + //Traditional Chinese Windows should use MS950_HKSCS_XP as the + //default encoding, if HKSCS patch has been installed. + // "old" MS950 0xfa41 -> u+e001 + // "new" MS950 0xfa41 -> u+92db + TCHAR mbChar[2] = {(char)0xfa, (char)0x41}; + WCHAR unicodeChar; + MultiByteToWideChar(CP_ACP, 0, mbChar, 2, &unicodeChar, 1); + if (unicodeChar == 0x92db) { + strcpy(ret, "MS950_HKSCS_XP"); + } + } else if (codepage == 936 && IsValidCodePage(54936)) { + //SimpChinese Windows should use GB18030 as the default + //encoding, if gb18030 patch has been installed (on windows + //2000/XP, (1)Codepage 54936 will be available + //(2)simsun18030.ttc will exist under system fonts dir ) char systemPath[MAX_PATH + 1]; char* gb18030Font = "\\FONTS\\SimSun18030.ttc"; FILE *f = NULL; @@ -123,6 +112,14 @@ getEncodingInternal(LCID lcid) } } } + break; + case 54936: + strcpy(ret, "GB18030"); + break; + default: + ret[0] = 'C'; + ret[1] = 'p'; + break; } return ret; From 72176305ae24e4e0c8f6541b229c16cae81e4775 Mon Sep 17 00:00:00 2001 From: Leo Korinth Date: Thu, 26 Mar 2026 18:16:17 +0000 Subject: [PATCH 056/359] 8379346: Cleanup casts and implicit conversions to boolean Reviewed-by: stefank, dholmes, ayang --- src/hotspot/os/linux/hugepages.cpp | 4 ++-- src/hotspot/os/linux/os_linux.cpp | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/hotspot/os/linux/hugepages.cpp b/src/hotspot/os/linux/hugepages.cpp index 1340c470dff..213845c7134 100644 --- a/src/hotspot/os/linux/hugepages.cpp +++ b/src/hotspot/os/linux/hugepages.cpp @@ -68,7 +68,7 @@ static size_t scan_default_hugepagesize() { // format has been changed), we'll set largest page size to 0 FILE *fp = os::fopen("/proc/meminfo", "r"); - if (fp) { + if (fp != nullptr) { while (!feof(fp)) { int x = 0; char buf[16]; @@ -81,7 +81,7 @@ static size_t scan_default_hugepagesize() { // skip to next line for (;;) { int ch = fgetc(fp); - if (ch == EOF || ch == (int)'\n') break; + if (ch == EOF || ch == '\n') break; } } } diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index c79b0ab9fb5..bf096897aa7 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -1313,7 +1313,7 @@ bool os::is_primordial_thread(void) { // Find the virtual memory area that contains addr static bool find_vma(address addr, address* vma_low, address* vma_high) { FILE *fp = os::fopen("/proc/self/maps", "r"); - if (fp) { + if (fp != nullptr) { address low, high; while (!feof(fp)) { if (fscanf(fp, "%p-%p", &low, &high) == 2) { @@ -1326,7 +1326,7 @@ static bool find_vma(address addr, address* vma_low, address* vma_high) { } for (;;) { int ch = fgetc(fp); - if (ch == EOF || ch == (int)'\n') break; + if (ch == EOF || ch == '\n') break; } } fclose(fp); @@ -4384,7 +4384,7 @@ int os::Linux::get_namespace_pid(int vmid) { os::snprintf_checked(fname, sizeof(fname), "/proc/%d/status", vmid); FILE *fp = os::fopen(fname, "r"); - if (fp) { + if (fp != nullptr) { int pid, nspid; int ret; while (!feof(fp) && !ferror(fp)) { @@ -4398,7 +4398,7 @@ int os::Linux::get_namespace_pid(int vmid) { } for (;;) { int ch = fgetc(fp); - if (ch == EOF || ch == (int)'\n') break; + if (ch == EOF || ch == '\n') break; } } fclose(fp); From c5c5340b521151b9dac44cc72899ef31c2d812cb Mon Sep 17 00:00:00 2001 From: Leo Korinth Date: Thu, 26 Mar 2026 18:37:45 +0000 Subject: [PATCH 057/359] 8379224: Always use zero as invalid page size Reviewed-by: stefank, ayang --- src/hotspot/os/linux/hugepages.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/hotspot/os/linux/hugepages.cpp b/src/hotspot/os/linux/hugepages.cpp index 213845c7134..b065f7b1496 100644 --- a/src/hotspot/os/linux/hugepages.cpp +++ b/src/hotspot/os/linux/hugepages.cpp @@ -35,7 +35,7 @@ #include ExplicitHugePageSupport::ExplicitHugePageSupport() : - _initialized{false}, _os_supported{}, _pre_allocated{}, _default_hugepage_size{SIZE_MAX}, _inconsistent{false} {} + _initialized{false}, _os_supported{}, _pre_allocated{}, _default_hugepage_size{0}, _inconsistent{false} {} os::PageSizes ExplicitHugePageSupport::os_supported() const { assert(_initialized, "Not initialized"); @@ -187,7 +187,7 @@ void ExplicitHugePageSupport::scan_os() { } THPSupport::THPSupport() : - _initialized(false), _mode(THPMode::never), _pagesize(SIZE_MAX) {} + _initialized{false}, _mode{THPMode::never}, _pagesize{0} {} THPMode THPSupport::mode() const { @@ -221,7 +221,6 @@ void THPSupport::scan_os() { } // Scan large page size for THP from hpage_pmd_size - _pagesize = 0; if (read_number_file("/sys/kernel/mm/transparent_hugepage/hpage_pmd_size", &_pagesize)) { assert(_pagesize > 0, "Expected"); } From 40d65f1063a27b081b4c074b04192eb2fcf5dd6a Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Thu, 26 Mar 2026 18:38:04 +0000 Subject: [PATCH 058/359] 8379583: (fs) Files.copy use of posix_fadvise is problematic on Linux Reviewed-by: alanb --- .../classes/sun/nio/fs/LinuxFileSystem.java | 12 +--- .../sun/nio/fs/UnixConstants.java.template | 4 +- .../bench/java/nio/file/FilesCopy.java | 68 +++++++++++++++++++ 3 files changed, 72 insertions(+), 12 deletions(-) create mode 100644 test/micro/org/openjdk/bench/java/nio/file/FilesCopy.java diff --git a/src/java.base/linux/classes/sun/nio/fs/LinuxFileSystem.java b/src/java.base/linux/classes/sun/nio/fs/LinuxFileSystem.java index 44e957f54fb..ec3e135b8b1 100644 --- a/src/java.base/linux/classes/sun/nio/fs/LinuxFileSystem.java +++ b/src/java.base/linux/classes/sun/nio/fs/LinuxFileSystem.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -139,10 +139,7 @@ class LinuxFileSystem extends UnixFileSystem { int size, long addressToPollForCancel) throws UnixException { - int advice = POSIX_FADV_SEQUENTIAL | // sequential data access - POSIX_FADV_NOREUSE | // will access only once - POSIX_FADV_WILLNEED; // will access in near future - posix_fadvise(src, 0, 0, advice); + posix_fadvise(src, 0, 0, POSIX_FADV_SEQUENTIAL); super.bufferedCopy(dst, src, address, size, addressToPollForCancel); } @@ -151,10 +148,7 @@ class LinuxFileSystem extends UnixFileSystem { int directCopy(int dst, int src, long addressToPollForCancel) throws UnixException { - int advice = POSIX_FADV_SEQUENTIAL | // sequential data access - POSIX_FADV_NOREUSE | // will access only once - POSIX_FADV_WILLNEED; // will access in near future - posix_fadvise(src, 0, 0, advice); + posix_fadvise(src, 0, 0, POSIX_FADV_SEQUENTIAL); return directCopy0(dst, src, addressToPollForCancel); } diff --git a/src/java.base/unix/classes/sun/nio/fs/UnixConstants.java.template b/src/java.base/unix/classes/sun/nio/fs/UnixConstants.java.template index 6823833582f..7a9a22ac40d 100644 --- a/src/java.base/unix/classes/sun/nio/fs/UnixConstants.java.template +++ b/src/java.base/unix/classes/sun/nio/fs/UnixConstants.java.template @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -173,7 +173,5 @@ class UnixConstants { #ifdef __linux__ // advice flags used with posix_fadvise(2) static final int PREFIX_POSIX_FADV_SEQUENTIAL = POSIX_FADV_SEQUENTIAL; - static final int PREFIX_POSIX_FADV_NOREUSE = POSIX_FADV_NOREUSE; - static final int PREFIX_POSIX_FADV_WILLNEED = POSIX_FADV_WILLNEED; #endif } diff --git a/test/micro/org/openjdk/bench/java/nio/file/FilesCopy.java b/test/micro/org/openjdk/bench/java/nio/file/FilesCopy.java new file mode 100644 index 00000000000..9472920f071 --- /dev/null +++ b/test/micro/org/openjdk/bench/java/nio/file/FilesCopy.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.bench.java.nio.file; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.file.Files; +import java.nio.file.Path; +import static java.nio.file.StandardOpenOption.*; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.TearDown; + +@State(Scope.Benchmark) +public class FilesCopy { + + private static final int SIZE = Integer.MAX_VALUE; + private static final Path FILE = Path.of("file.dat"); + private static final Path COPY = Path.of("copy.dat"); + + @Setup + public void init() throws IOException { + Files.deleteIfExists(FILE); + Files.deleteIfExists(COPY); + try (FileChannel fc = FileChannel.open(FILE, CREATE_NEW, READ, WRITE)) { + fc.position(SIZE); + fc.write(ByteBuffer.wrap(new byte[] {(byte)27})); + } + } + + @TearDown + public void cleanup() throws IOException { + Files.deleteIfExists(FILE); + Files.deleteIfExists(COPY); + } + + @Benchmark + public void copyFile() throws IOException { + Files.copy(FILE, COPY); + Files.delete(COPY); + } + +} From 68c48290d63675d82f2e9e60241031de023c280f Mon Sep 17 00:00:00 2001 From: Kelvin Nilsen Date: Thu, 26 Mar 2026 20:04:13 +0000 Subject: [PATCH 059/359] 8380459: Shenandoah: Do not reset bytes-allocated-since-gc-start when degenerating Reviewed-by: wkemper --- src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp | 5 ++++- .../gc/shenandoah/shenandoahGenerationalControlThread.cpp | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp index 48183507124..4c6e82c86a5 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp @@ -138,7 +138,10 @@ void ShenandoahControlThread::run_service() { heuristics->cancel_trigger_request(); - heap->reset_bytes_allocated_since_gc_start(); + if (mode != stw_degenerated) { + // If mode is stw_degenerated, count bytes allocated from the start of the conc GC that experienced alloc failure. + heap->reset_bytes_allocated_since_gc_start(); + } MetaspaceCombinedStats meta_sizes = MetaspaceUtils::get_combined_statistics(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp index 67cc4d2f703..ec33e671053 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp @@ -255,7 +255,8 @@ void ShenandoahGenerationalControlThread::run_gc_cycle(const ShenandoahGCRequest GCIdMark gc_id_mark; - if (gc_mode() != servicing_old) { + if ((gc_mode() != servicing_old) && (gc_mode() != stw_degenerated)) { + // If mode is stw_degenerated, count bytes allocated from the start of the conc GC that experienced alloc failure. _heap->reset_bytes_allocated_since_gc_start(); } From 91892948ee0ac3c62bbddbbf9e6f99e746f3d72f Mon Sep 17 00:00:00 2001 From: Damon Nguyen Date: Thu, 26 Mar 2026 20:21:19 +0000 Subject: [PATCH 060/359] 8380229: 2 Impossible or redundant condition defect groups in 2 files Reviewed-by: honkar, prr --- .../share/native/libharfbuzz/hb-aat-layout-common.hh | 3 +-- .../share/native/libharfbuzz/hb-ot-layout-common.hh | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-common.hh b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-common.hh index d2ce32616be..4bb41fd0189 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-common.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-common.hh @@ -1266,8 +1266,7 @@ struct StateTableDriver next_state == StateTableT::STATE_START_OF_TEXT && start_state_safe_to_break_eot && is_not_actionable && - is_not_epsilon_transition && - !last_range; + is_not_epsilon_transition; if (is_null_transition) { diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-common.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-common.hh index dcacc9cb86c..6b62732bf54 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-common.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-common.hh @@ -2480,7 +2480,7 @@ struct VarRegionAxis /* TODO Move these to sanitize(). */ if (unlikely (start > peak || peak > end)) return 1.f; - if (unlikely (start < 0 && end > 0 && peak != 0)) + if (unlikely (start < 0 && end > 0)) return 1.f; if (coord <= start || end <= coord) From 4d2623757fbe8c9fa8c22817a993ca85a2403873 Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Thu, 26 Mar 2026 20:59:45 +0000 Subject: [PATCH 061/359] 8359433: The final modifier on Windows L&F internal UI classes prevents extending them in apps Reviewed-by: prr, aivanov --- .../java/swing/plaf/windows/WindowsBorders.java | 8 ++++---- .../java/swing/plaf/windows/WindowsButtonUI.java | 2 +- .../plaf/windows/WindowsCheckBoxMenuItemUI.java | 4 ++-- .../java/swing/plaf/windows/WindowsCheckBoxUI.java | 2 +- .../plaf/windows/WindowsClassicLookAndFeel.java | 4 ++-- .../java/swing/plaf/windows/WindowsComboBoxUI.java | 10 +++++----- .../swing/plaf/windows/WindowsDesktopIconUI.java | 4 ++-- .../swing/plaf/windows/WindowsDesktopManager.java | 4 ++-- .../swing/plaf/windows/WindowsDesktopPaneUI.java | 4 ++-- .../swing/plaf/windows/WindowsEditorPaneUI.java | 4 ++-- .../swing/plaf/windows/WindowsFileChooserUI.java | 14 +++++++------- .../windows/WindowsInternalFrameTitlePane.java | 8 ++++---- .../swing/plaf/windows/WindowsInternalFrameUI.java | 4 ++-- .../java/swing/plaf/windows/WindowsLabelUI.java | 2 +- .../java/swing/plaf/windows/WindowsMenuBarUI.java | 4 ++-- .../java/swing/plaf/windows/WindowsMenuItemUI.java | 2 +- .../sun/java/swing/plaf/windows/WindowsMenuUI.java | 6 +++--- .../swing/plaf/windows/WindowsOptionPaneUI.java | 4 ++-- .../swing/plaf/windows/WindowsPasswordFieldUI.java | 4 ++-- .../plaf/windows/WindowsPopupMenuSeparatorUI.java | 4 ++-- .../swing/plaf/windows/WindowsPopupMenuUI.java | 4 ++-- .../swing/plaf/windows/WindowsProgressBarUI.java | 4 ++-- .../plaf/windows/WindowsRadioButtonMenuItemUI.java | 4 ++-- .../java/swing/plaf/windows/WindowsRootPaneUI.java | 4 ++-- .../swing/plaf/windows/WindowsScrollBarUI.java | 4 ++-- .../swing/plaf/windows/WindowsScrollPaneUI.java | 4 ++-- .../swing/plaf/windows/WindowsSeparatorUI.java | 4 ++-- .../java/swing/plaf/windows/WindowsSliderUI.java | 4 ++-- .../java/swing/plaf/windows/WindowsSpinnerUI.java | 4 ++-- .../plaf/windows/WindowsSplitPaneDivider.java | 4 ++-- .../swing/plaf/windows/WindowsSplitPaneUI.java | 4 ++-- .../swing/plaf/windows/WindowsTabbedPaneUI.java | 4 ++-- .../swing/plaf/windows/WindowsTableHeaderUI.java | 4 ++-- .../java/swing/plaf/windows/WindowsTextAreaUI.java | 4 ++-- .../swing/plaf/windows/WindowsTextFieldUI.java | 4 ++-- .../java/swing/plaf/windows/WindowsTextPaneUI.java | 4 ++-- .../swing/plaf/windows/WindowsToggleButtonUI.java | 2 +- .../plaf/windows/WindowsToolBarSeparatorUI.java | 4 ++-- .../java/swing/plaf/windows/WindowsToolBarUI.java | 4 ++-- .../sun/java/swing/plaf/windows/WindowsTreeUI.java | 6 +++--- test/jdk/javax/swing/plaf/windows/bug4991587.java | 4 ++-- 41 files changed, 91 insertions(+), 91 deletions(-) diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsBorders.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsBorders.java index 81766db8116..572e9e8c117 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsBorders.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsBorders.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2026, Oracle and/or its affiliates. All rights reserved. * 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 WindowsBorders { } @SuppressWarnings("serial") // Superclass is not serializable across versions - public static final class ProgressBarBorder extends AbstractBorder implements UIResource { + public static class ProgressBarBorder extends AbstractBorder implements UIResource { protected Color shadow; protected Color highlight; @@ -148,7 +148,7 @@ public final class WindowsBorders { * @since 1.4 */ @SuppressWarnings("serial") // Superclass is not serializable across versions - public static final class ToolBarBorder extends AbstractBorder implements UIResource, SwingConstants { + public static class ToolBarBorder extends AbstractBorder implements UIResource, SwingConstants { protected Color shadow; protected Color highlight; @@ -308,7 +308,7 @@ public final class WindowsBorders { * @since 1.4 */ @SuppressWarnings("serial") // Superclass is not serializable across versions - public static final class InternalFrameLineBorder extends LineBorder implements + public static class InternalFrameLineBorder extends LineBorder implements UIResource { protected Color activeColor; protected Color inactiveColor; diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsButtonUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsButtonUI.java index ee07276aa30..63e99e0804a 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsButtonUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsButtonUI.java @@ -56,7 +56,7 @@ import static com.sun.java.swing.plaf.windows.XPStyle.Skin; * * @author Jeff Dinkins */ -public final class WindowsButtonUI extends BasicButtonUI +public class WindowsButtonUI extends BasicButtonUI { protected int dashedRectGapX; protected int dashedRectGapY; diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxMenuItemUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxMenuItemUI.java index 3a2578b3e0b..47e311486ba 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxMenuItemUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxMenuItemUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,7 +42,7 @@ import com.sun.java.swing.plaf.windows.TMSchema.State; /** * Windows check box menu item. */ -public final class WindowsCheckBoxMenuItemUI extends BasicCheckBoxMenuItemUI { +public class WindowsCheckBoxMenuItemUI extends BasicCheckBoxMenuItemUI { final WindowsMenuItemUIAccessor accessor = new WindowsMenuItemUIAccessor() { diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxUI.java index 7cb2490fd76..d264393f4d8 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxUI.java @@ -35,7 +35,7 @@ import javax.swing.plaf.ComponentUI; * * @author Jeff Dinkins */ -public final class WindowsCheckBoxUI extends WindowsRadioButtonUI +public class WindowsCheckBoxUI extends WindowsRadioButtonUI { // NOTE: WindowsCheckBoxUI inherits from WindowsRadioButtonUI instead // of BasicCheckBoxUI because we want to pick up all the diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsClassicLookAndFeel.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsClassicLookAndFeel.java index 5716a875cd7..802b5f66888 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsClassicLookAndFeel.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsClassicLookAndFeel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,7 @@ package com.sun.java.swing.plaf.windows; * @since 1.5 */ @SuppressWarnings("serial") // Superclass is not serializable across versions -public final class WindowsClassicLookAndFeel extends WindowsLookAndFeel { +public class WindowsClassicLookAndFeel extends WindowsLookAndFeel { @Override public String getName() { return "Windows Classic"; diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsComboBoxUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsComboBoxUI.java index fdc9b03ae7d..8717fd715ea 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsComboBoxUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsComboBoxUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * 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,7 +75,7 @@ import static com.sun.java.swing.plaf.windows.XPStyle.Skin; * @author Tom Santos * @author Igor Kushnirskiy */ -public final class WindowsComboBoxUI extends BasicComboBoxUI { +public class WindowsComboBoxUI extends BasicComboBoxUI { private static final MouseListener rolloverListener = new MouseAdapter() { @@ -532,7 +532,7 @@ public final class WindowsComboBoxUI extends BasicComboBoxUI { } @SuppressWarnings("serial") // Same-version serialization only - protected final class WinComboPopUp extends BasicComboPopup { + protected class WinComboPopUp extends BasicComboPopup { private Skin listBoxBorder = null; private XPStyle xp; @@ -550,7 +550,7 @@ public final class WindowsComboBoxUI extends BasicComboBoxUI { return new InvocationKeyHandler(); } - protected final class InvocationKeyHandler extends BasicComboPopup.InvocationKeyHandler { + protected class InvocationKeyHandler extends BasicComboPopup.InvocationKeyHandler { protected InvocationKeyHandler() { WinComboPopUp.this.super(); } @@ -570,7 +570,7 @@ public final class WindowsComboBoxUI extends BasicComboBoxUI { /** * Subclassed to highlight selected item in an editable combo box. */ - public static final class WindowsComboBoxEditor + public static class WindowsComboBoxEditor extends BasicComboBoxEditor.UIResource { /** diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsDesktopIconUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsDesktopIconUI.java index 47ecdf5747b..2cebb050396 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsDesktopIconUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsDesktopIconUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * 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 javax.swing.plaf.basic.BasicDesktopIconUI; /** * Windows icon for a minimized window on the desktop. */ -public final class WindowsDesktopIconUI extends BasicDesktopIconUI { +public class WindowsDesktopIconUI extends BasicDesktopIconUI { private int width; public static ComponentUI createUI(JComponent c) { diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsDesktopManager.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsDesktopManager.java index 79d81bad089..ae081a7690c 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsDesktopManager.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsDesktopManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,7 +52,7 @@ import java.lang.ref.WeakReference; * @author Thomas Ball */ @SuppressWarnings("serial") // JDK-implementation class -public final class WindowsDesktopManager extends DefaultDesktopManager +public class WindowsDesktopManager extends DefaultDesktopManager implements java.io.Serializable, javax.swing.plaf.UIResource { /* The frame which is currently selected/activated. diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsDesktopPaneUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsDesktopPaneUI.java index dabbe3fb992..4a3f0ec38b1 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsDesktopPaneUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsDesktopPaneUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,7 @@ import javax.swing.plaf.basic.BasicDesktopPaneUI; * * @author David Kloba */ -public final class WindowsDesktopPaneUI extends BasicDesktopPaneUI +public class WindowsDesktopPaneUI extends BasicDesktopPaneUI { public static ComponentUI createUI(JComponent c) { return new WindowsDesktopPaneUI(); diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsEditorPaneUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsEditorPaneUI.java index 44cb0e9634c..ea21b41c619 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsEditorPaneUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsEditorPaneUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * 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 javax.swing.text.Caret; /** * Windows rendition of the component. */ -public final class WindowsEditorPaneUI extends BasicEditorPaneUI +public class WindowsEditorPaneUI extends BasicEditorPaneUI { /** diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsFileChooserUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsFileChooserUI.java index 08c01760be9..86c40ea70d6 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsFileChooserUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsFileChooserUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * 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,7 +101,7 @@ import sun.swing.WindowsPlacesBar; * * @author Jeff Dinkins */ -public final class WindowsFileChooserUI extends BasicFileChooserUI { +public class WindowsFileChooserUI extends BasicFileChooserUI { // The following are private because the implementation of the // Windows FileChooser L&F is not complete yet. @@ -1122,7 +1122,7 @@ public final class WindowsFileChooserUI extends BasicFileChooserUI { * Data model for a type-face selection combo-box. */ @SuppressWarnings("serial") // Superclass is not serializable across versions - protected final class DirectoryComboBoxModel extends AbstractListModel implements ComboBoxModel { + protected class DirectoryComboBoxModel extends AbstractListModel implements ComboBoxModel { Vector directories = new Vector(); int[] depths = null; File selectedDirectory = null; @@ -1252,7 +1252,7 @@ public final class WindowsFileChooserUI extends BasicFileChooserUI { * Render different type sizes and styles. */ @SuppressWarnings("serial") // Superclass is not serializable across versions - public final class FilterComboBoxRenderer extends DefaultListCellRenderer { + public class FilterComboBoxRenderer extends DefaultListCellRenderer { @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, @@ -1279,7 +1279,7 @@ public final class WindowsFileChooserUI extends BasicFileChooserUI { * Data model for a type-face selection combo-box. */ @SuppressWarnings("serial") // Superclass is not serializable across versions - protected final class FilterComboBoxModel extends AbstractListModel implements ComboBoxModel, + protected class FilterComboBoxModel extends AbstractListModel implements ComboBoxModel, PropertyChangeListener { protected FileFilter[] filters; protected FilterComboBoxModel() { @@ -1362,7 +1362,7 @@ public final class WindowsFileChooserUI extends BasicFileChooserUI { /** * Acts when DirectoryComboBox has changed the selected item. */ - protected final class DirectoryComboBoxAction implements ActionListener { + protected class DirectoryComboBoxAction implements ActionListener { @@ -1387,7 +1387,7 @@ public final class WindowsFileChooserUI extends BasicFileChooserUI { // *********************** // * FileView operations * // *********************** - protected final class WindowsFileView extends BasicFileView { + protected class WindowsFileView extends BasicFileView { /* FileView type descriptions */ @Override diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsInternalFrameTitlePane.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsInternalFrameTitlePane.java index ba4bde12122..029e139fe8f 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsInternalFrameTitlePane.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsInternalFrameTitlePane.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -418,7 +418,7 @@ public class WindowsInternalFrameTitlePane extends BasicInternalFrameTitlePane { return new WindowsTitlePaneLayout(); } - public final class WindowsTitlePaneLayout extends BasicInternalFrameTitlePane.TitlePaneLayout { + public class WindowsTitlePaneLayout extends BasicInternalFrameTitlePane.TitlePaneLayout { private Insets captionMargin = null; private Insets contentMargin = null; private XPStyle xp = XPStyle.getXP(); @@ -506,7 +506,7 @@ public class WindowsInternalFrameTitlePane extends BasicInternalFrameTitlePane { } } // end WindowsTitlePaneLayout - public final class WindowsPropertyChangeHandler extends PropertyChangeHandler { + public class WindowsPropertyChangeHandler extends PropertyChangeHandler { @Override public void propertyChange(PropertyChangeEvent evt) { String prop = evt.getPropertyName(); @@ -530,7 +530,7 @@ public class WindowsInternalFrameTitlePane extends BasicInternalFrameTitlePane { *

* Note: We assume here that icons are square. */ - public static final class ScalableIconUIResource implements Icon, UIResource { + public static class ScalableIconUIResource implements Icon, UIResource { // We can use an arbitrary size here because we scale to it in paintIcon() private static final int SIZE = 16; diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsInternalFrameUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsInternalFrameUI.java index 9db31ba38f9..6e76ac6a5b4 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsInternalFrameUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsInternalFrameUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,7 +45,7 @@ import static com.sun.java.swing.plaf.windows.XPStyle.Skin; /** * Windows rendition of the component. */ -public final class WindowsInternalFrameUI extends BasicInternalFrameUI +public class WindowsInternalFrameUI extends BasicInternalFrameUI { XPStyle xp = XPStyle.getXP(); diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsLabelUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsLabelUI.java index 4283f743b97..c910b635491 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsLabelUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsLabelUI.java @@ -40,7 +40,7 @@ import sun.swing.SwingUtilities2; /** * Windows rendition of the component. */ -public final class WindowsLabelUI extends BasicLabelUI { +public class WindowsLabelUI extends BasicLabelUI { private static final ComponentUI UI = new WindowsLabelUI(); diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuBarUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuBarUI.java index 3d3cf5feee7..ac26dcbf425 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuBarUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuBarUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -57,7 +57,7 @@ import sun.swing.MnemonicHandler; /** * Windows rendition of the component. */ -public final class WindowsMenuBarUI extends BasicMenuBarUI +public class WindowsMenuBarUI extends BasicMenuBarUI { /* to be accessed on the EDT only */ private WindowListener windowListener = null; diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuItemUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuItemUI.java index d15bc93a628..d50540588fb 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuItemUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuItemUI.java @@ -58,7 +58,7 @@ import sun.swing.SwingUtilities2; * * @author Igor Kushnirskiy */ -public final class WindowsMenuItemUI extends BasicMenuItemUI { +public class WindowsMenuItemUI extends BasicMenuItemUI { /** * The instance of {@code PropertyChangeListener}. */ diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuUI.java index 259c32c74f4..78028db7c00 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,7 +50,7 @@ import com.sun.java.swing.plaf.windows.TMSchema.State; /** * Windows rendition of the component. */ -public final class WindowsMenuUI extends BasicMenuUI { +public class WindowsMenuUI extends BasicMenuUI { protected Integer menuBarHeight; protected boolean hotTrackingOn; @@ -283,7 +283,7 @@ public final class WindowsMenuUI extends BasicMenuUI { * true when the mouse enters the menu and false when it exits. * @since 1.4 */ - protected final class WindowsMouseInputHandler extends BasicMenuUI.MouseInputHandler { + protected class WindowsMouseInputHandler extends BasicMenuUI.MouseInputHandler { @Override public void mouseEntered(MouseEvent evt) { super.mouseEntered(evt); diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsOptionPaneUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsOptionPaneUI.java index 05c1b177705..3bed1856a55 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsOptionPaneUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsOptionPaneUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * 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,5 +30,5 @@ import javax.swing.plaf.basic.BasicOptionPaneUI; /** * Windows rendition of the component. */ -public final class WindowsOptionPaneUI extends BasicOptionPaneUI { +public class WindowsOptionPaneUI extends BasicOptionPaneUI { } diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsPasswordFieldUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsPasswordFieldUI.java index 6adf6e402ec..0c30b291648 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsPasswordFieldUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsPasswordFieldUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * 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 javax.swing.text.Caret; /** * Windows rendition of the component. */ -public final class WindowsPasswordFieldUI extends BasicPasswordFieldUI { +public class WindowsPasswordFieldUI extends BasicPasswordFieldUI { /** * Creates a UI for a JPasswordField diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsPopupMenuSeparatorUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsPopupMenuSeparatorUI.java index 576549ae482..f236c6b14fc 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsPopupMenuSeparatorUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsPopupMenuSeparatorUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,7 +42,7 @@ import com.sun.java.swing.plaf.windows.XPStyle.Skin; * @author Igor Kushnirskiy */ -public final class WindowsPopupMenuSeparatorUI extends BasicPopupMenuSeparatorUI { +public class WindowsPopupMenuSeparatorUI extends BasicPopupMenuSeparatorUI { public static ComponentUI createUI(JComponent c) { return new WindowsPopupMenuSeparatorUI(); diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsPopupMenuUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsPopupMenuUI.java index 1361286df4a..1c85cfebd94 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsPopupMenuUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsPopupMenuUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -57,7 +57,7 @@ import static sun.swing.SwingUtilities2.BASICMENUITEMUI_MAX_TEXT_OFFSET; * * @author Igor Kushnirskiy */ -public final class WindowsPopupMenuUI extends BasicPopupMenuUI { +public class WindowsPopupMenuUI extends BasicPopupMenuUI { static MnemonicListener mnemonicListener = null; static final Object GUTTER_OFFSET_KEY = diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsProgressBarUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsProgressBarUI.java index 9cc7d277ff1..5440b98cd1b 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsProgressBarUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsProgressBarUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,7 +51,7 @@ import static com.sun.java.swing.plaf.windows.XPStyle.Skin; * * @author Michael C. Albers */ -public final class WindowsProgressBarUI extends BasicProgressBarUI +public class WindowsProgressBarUI extends BasicProgressBarUI { private Rectangle previousFullBox; diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsRadioButtonMenuItemUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsRadioButtonMenuItemUI.java index 78768c29ab3..2ec78341c2a 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsRadioButtonMenuItemUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsRadioButtonMenuItemUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,7 +42,7 @@ import com.sun.java.swing.plaf.windows.TMSchema.State; /** * Windows rendition of the component. */ -public final class WindowsRadioButtonMenuItemUI extends BasicRadioButtonMenuItemUI { +public class WindowsRadioButtonMenuItemUI extends BasicRadioButtonMenuItemUI { final WindowsMenuItemUIAccessor accessor = new WindowsMenuItemUIAccessor() { diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsRootPaneUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsRootPaneUI.java index 5e08dcf5605..d41fd9421e4 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsRootPaneUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsRootPaneUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ import sun.swing.MnemonicHandler; * @author Mark Davidson * @since 1.4 */ -public final class WindowsRootPaneUI extends BasicRootPaneUI { +public class WindowsRootPaneUI extends BasicRootPaneUI { private static final WindowsRootPaneUI windowsRootPaneUI = new WindowsRootPaneUI(); static final AltProcessor altProcessor = new AltProcessor(); diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsScrollBarUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsScrollBarUI.java index 04a9f2e97cf..2755f3543f1 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsScrollBarUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsScrollBarUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,7 +55,7 @@ import static com.sun.java.swing.plaf.windows.XPStyle.Skin; /** * Windows rendition of the component. */ -public final class WindowsScrollBarUI extends BasicScrollBarUI { +public class WindowsScrollBarUI extends BasicScrollBarUI { private Grid thumbGrid; private Grid highlightGrid; private Dimension horizontalThumbSize; diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsScrollPaneUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsScrollPaneUI.java index 48e7a8c02fb..56b8eb1004e 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsScrollPaneUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsScrollPaneUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * 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,5 +30,5 @@ import javax.swing.plaf.basic.BasicScrollPaneUI; /** * Windows rendition of the component. */ -public final class WindowsScrollPaneUI extends BasicScrollPaneUI +public class WindowsScrollPaneUI extends BasicScrollPaneUI {} diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsSeparatorUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsSeparatorUI.java index 2a2caef60d2..12eaa33872c 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsSeparatorUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsSeparatorUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2026, Oracle and/or its affiliates. All rights reserved. * 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,4 +30,4 @@ import javax.swing.plaf.basic.*; /** * Windows Separator. */ -public final class WindowsSeparatorUI extends BasicSeparatorUI { } +public class WindowsSeparatorUI extends BasicSeparatorUI { } diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsSliderUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsSliderUI.java index 731775a2575..cfc509babf4 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsSliderUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsSliderUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,7 +44,7 @@ import static com.sun.java.swing.plaf.windows.XPStyle.Skin; /** * Windows rendition of the component. */ -public final class WindowsSliderUI extends BasicSliderUI +public class WindowsSliderUI extends BasicSliderUI { private boolean rollover = false; private boolean pressed = false; diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsSpinnerUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsSpinnerUI.java index a8e2a2ddcf1..8934bf9ff21 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsSpinnerUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsSpinnerUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ import static com.sun.java.swing.plaf.windows.TMSchema.State; import static com.sun.java.swing.plaf.windows.XPStyle.Skin; -public final class WindowsSpinnerUI extends BasicSpinnerUI { +public class WindowsSpinnerUI extends BasicSpinnerUI { public static ComponentUI createUI(JComponent c) { return new WindowsSpinnerUI(); } diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsSplitPaneDivider.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsSplitPaneDivider.java index a132756bbee..26cd1bd8c2d 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsSplitPaneDivider.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsSplitPaneDivider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2026, Oracle and/or its affiliates. All rights reserved. * 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 javax.swing.plaf.basic.BasicSplitPaneUI; * @author Jeff Dinkins */ @SuppressWarnings("serial") // Superclass is not serializable across versions -public final class WindowsSplitPaneDivider extends BasicSplitPaneDivider +public class WindowsSplitPaneDivider extends BasicSplitPaneDivider { /** diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsSplitPaneUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsSplitPaneUI.java index 481fa466a5b..b67ab22f48f 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsSplitPaneUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsSplitPaneUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * 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 javax.swing.plaf.basic.BasicSplitPaneUI; /** * Windows rendition of the component. */ -public final class WindowsSplitPaneUI extends BasicSplitPaneUI +public class WindowsSplitPaneUI extends BasicSplitPaneUI { public WindowsSplitPaneUI() { diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTabbedPaneUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTabbedPaneUI.java index 874b5c65c6e..da8e8b9d385 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTabbedPaneUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTabbedPaneUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * 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 static com.sun.java.swing.plaf.windows.XPStyle.Skin; /** * Windows rendition of the component. */ -public final class WindowsTabbedPaneUI extends BasicTabbedPaneUI { +public class WindowsTabbedPaneUI extends BasicTabbedPaneUI { /** * Keys to use for forward focus traversal when the JComponent is * managing focus. diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTableHeaderUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTableHeaderUI.java index de8f18b4ea1..1db0050f162 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTableHeaderUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTableHeaderUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,7 +50,7 @@ import static com.sun.java.swing.plaf.windows.TMSchema.Part; import static com.sun.java.swing.plaf.windows.TMSchema.State; import static com.sun.java.swing.plaf.windows.XPStyle.Skin; -public final class WindowsTableHeaderUI extends BasicTableHeaderUI { +public class WindowsTableHeaderUI extends BasicTableHeaderUI { private TableCellRenderer originalHeaderRenderer; public static ComponentUI createUI(JComponent h) { diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTextAreaUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTextAreaUI.java index 78cceff2a0c..7c9abb12e05 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTextAreaUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTextAreaUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * 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 javax.swing.text.Caret; /** * Windows rendition of the component. */ -public final class WindowsTextAreaUI extends BasicTextAreaUI { +public class WindowsTextAreaUI extends BasicTextAreaUI { /** * Creates the object to use for a caret. By default an * instance of WindowsCaret is created. This method diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTextFieldUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTextFieldUI.java index 5846dcb9f09..9920ed371d8 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTextFieldUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTextFieldUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -62,7 +62,7 @@ import javax.swing.text.Position; * * @author Timothy Prinzing */ -public final class WindowsTextFieldUI extends BasicTextFieldUI +public class WindowsTextFieldUI extends BasicTextFieldUI { /** * Creates a UI for a JTextField. diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTextPaneUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTextPaneUI.java index 2c645903e51..d1418205385 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTextPaneUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTextPaneUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * 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 javax.swing.text.Caret; /** * Windows rendition of the component. */ -public final class WindowsTextPaneUI extends BasicTextPaneUI +public class WindowsTextPaneUI extends BasicTextPaneUI { /** * Creates a UI for a JTextPane. diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsToggleButtonUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsToggleButtonUI.java index 67eb5c1d6a0..a612b3f392e 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsToggleButtonUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsToggleButtonUI.java @@ -43,7 +43,7 @@ import javax.swing.plaf.basic.BasicToggleButtonUI; * * @author Jeff Dinkins */ -public final class WindowsToggleButtonUI extends BasicToggleButtonUI +public class WindowsToggleButtonUI extends BasicToggleButtonUI { protected int dashedRectGapX; protected int dashedRectGapY; diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsToolBarSeparatorUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsToolBarSeparatorUI.java index 47175b83d30..1707ce5a80c 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsToolBarSeparatorUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsToolBarSeparatorUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,7 +40,7 @@ import static com.sun.java.swing.plaf.windows.XPStyle.Skin; * * @author Mark Davidson */ -public final class WindowsToolBarSeparatorUI extends BasicToolBarSeparatorUI { +public class WindowsToolBarSeparatorUI extends BasicToolBarSeparatorUI { public static ComponentUI createUI( JComponent c ) { return new WindowsToolBarSeparatorUI(); diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsToolBarUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsToolBarUI.java index 025c30c5c96..4e2cf42bf5d 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsToolBarUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsToolBarUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,7 +45,7 @@ import javax.swing.plaf.basic.BasicToolBarUI; import static com.sun.java.swing.plaf.windows.TMSchema.Part; -public final class WindowsToolBarUI extends BasicToolBarUI { +public class WindowsToolBarUI extends BasicToolBarUI { public static ComponentUI createUI(JComponent c) { return new WindowsToolBarUI(); diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTreeUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTreeUI.java index 78384bbd18a..26edfb978bd 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTreeUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTreeUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -167,7 +167,7 @@ public class WindowsTreeUI extends BasicTreeUI { * The plus sign button icon */ @SuppressWarnings("serial") // Superclass is not serializable across versions - public static final class CollapsedIcon extends ExpandedIcon { + public static class CollapsedIcon extends ExpandedIcon { public static Icon createCollapsedIcon() { return new CollapsedIcon(); } @@ -185,7 +185,7 @@ public class WindowsTreeUI extends BasicTreeUI { } @SuppressWarnings("serial") // Superclass is not serializable across versions - public final class WindowsTreeCellRenderer extends DefaultTreeCellRenderer { + public class WindowsTreeCellRenderer extends DefaultTreeCellRenderer { /** * Configures the renderer based on the passed in components. diff --git a/test/jdk/javax/swing/plaf/windows/bug4991587.java b/test/jdk/javax/swing/plaf/windows/bug4991587.java index e4e4fde2b86..439bdd4cc61 100644 --- a/test/jdk/javax/swing/plaf/windows/bug4991587.java +++ b/test/jdk/javax/swing/plaf/windows/bug4991587.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2026, Oracle and/or its affiliates. All rights reserved. * 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 4991587 + * @bug 4991587 8359433 * @requires (os.family == "windows") * @summary Tests that disabled JButton text is positioned properly in Windows L&F * @modules java.desktop/com.sun.java.swing.plaf.windows From 062d89bff59e09850d335e8de682c9711f28966b Mon Sep 17 00:00:00 2001 From: Phil Race Date: Thu, 26 Mar 2026 21:23:04 +0000 Subject: [PATCH 062/359] 8380804: Remove remaining AppContext usage from the Swing implementation Reviewed-by: dnguyen, serb --- .../classes/javax/swing/RepaintManager.java | 22 +++---- .../classes/javax/swing/SwingUtilities.java | 21 ------- .../classes/javax/swing/SwingWorker.java | 63 +++++++------------ .../share/classes/javax/swing/Timer.java | 5 +- .../share/classes/javax/swing/UIManager.java | 34 ++-------- 5 files changed, 36 insertions(+), 109 deletions(-) diff --git a/src/java.desktop/share/classes/javax/swing/RepaintManager.java b/src/java.desktop/share/classes/javax/swing/RepaintManager.java index db8b13afa22..b587cf2da84 100644 --- a/src/java.desktop/share/classes/javax/swing/RepaintManager.java +++ b/src/java.desktop/share/classes/javax/swing/RepaintManager.java @@ -32,7 +32,6 @@ import java.util.*; import java.util.concurrent.atomic.AtomicInteger; import sun.awt.AWTAccessor; -import sun.awt.AppContext; import sun.awt.DisplayChangedListener; import sun.awt.SunToolkit; import sun.java2d.SunGraphicsEnvironment; @@ -1733,21 +1732,14 @@ public class RepaintManager } private static void scheduleDisplayChanges() { - // To avoid threading problems, we notify each RepaintManager + // To avoid threading problems, we notify the RepaintManager // on the thread it was created on. - for (AppContext context : AppContext.getAppContexts()) { - synchronized(context) { - if (!context.isDisposed()) { - EventQueue eventQueue = (EventQueue)context.get( - AppContext.EVENT_QUEUE_KEY); - if (eventQueue != null) { - eventQueue.postEvent(new InvocationEvent( - Toolkit.getDefaultToolkit(), - new DisplayChangedRunnable())); - } - } - } - } + EventQueue eventQueue = Toolkit.getDefaultToolkit().getSystemEventQueue(); + eventQueue.postEvent( + new InvocationEvent( + Toolkit.getDefaultToolkit(), + new DisplayChangedRunnable()) + ); } } diff --git a/src/java.desktop/share/classes/javax/swing/SwingUtilities.java b/src/java.desktop/share/classes/javax/swing/SwingUtilities.java index ae5faf64f3b..3603292b0ca 100644 --- a/src/java.desktop/share/classes/javax/swing/SwingUtilities.java +++ b/src/java.desktop/share/classes/javax/swing/SwingUtilities.java @@ -38,7 +38,6 @@ import javax.swing.event.MenuDragMouseEvent; import javax.swing.plaf.UIResource; import javax.swing.text.View; -import sun.awt.AppContext; import sun.awt.AWTAccessor; import sun.awt.AWTAccessor.MouseEventAccessor; @@ -1986,26 +1985,6 @@ public class SwingUtilities implements SwingConstants return (WindowListener)sharedOwnerFrame; } - /* Don't make these AppContext accessors public or protected -- - * since AppContext is in sun.awt in 1.2, we shouldn't expose it - * even indirectly with a public API. - */ - // REMIND(aim): phase out use of 4 methods below since they - // are just private covers for AWT methods (?) - - static Object appContextGet(Object key) { - return AppContext.getAppContext().get(key); - } - - static void appContextPut(Object key, Object value) { - AppContext.getAppContext().put(key, value); - } - - static void appContextRemove(Object key) { - AppContext.getAppContext().remove(key); - } - - static Class loadSystemClass(String className) throws ClassNotFoundException { return Class.forName(className, true, Thread.currentThread(). getContextClassLoader()); diff --git a/src/java.desktop/share/classes/javax/swing/SwingWorker.java b/src/java.desktop/share/classes/javax/swing/SwingWorker.java index 75f1700bded..dae695b4868 100644 --- a/src/java.desktop/share/classes/javax/swing/SwingWorker.java +++ b/src/java.desktop/share/classes/javax/swing/SwingWorker.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,7 +45,8 @@ import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -import sun.awt.AppContext; +import sun.awt.util.ThreadGroupUtils; + import sun.swing.AccumulativeRunnable; /** @@ -266,7 +267,7 @@ public abstract class SwingWorker implements RunnableFuture { */ private AccumulativeRunnable doNotifyProgressChange; - private final AccumulativeRunnable doSubmit = getDoSubmit(); + private final AccumulativeRunnable doSubmit = new DoSubmitAccumulativeRunnable(); /** * Values for the {@code state} bound property. @@ -755,18 +756,16 @@ public abstract class SwingWorker implements RunnableFuture { } + private static ExecutorService executorService; + /** * returns workersExecutorService. * - * returns the service stored in the appContext or creates it if - * necessary. + * returns the service and creates it if necessary. * * @return ExecutorService for the {@code SwingWorkers} */ private static synchronized ExecutorService getWorkersExecutorService() { - final AppContext appContext = AppContext.getAppContext(); - ExecutorService executorService = - (ExecutorService) appContext.get(SwingWorker.class); if (executorService == null) { //this creates daemon threads. ThreadFactory threadFactory = @@ -788,46 +787,26 @@ public abstract class SwingWorker implements RunnableFuture { 10L, TimeUnit.MINUTES, new LinkedBlockingQueue(), threadFactory); - appContext.put(SwingWorker.class, executorService); - // Don't use ShutdownHook here as it's not enough. We should track - // AppContext disposal instead of JVM shutdown, see 6799345 for details - final ExecutorService es = executorService; - appContext.addPropertyChangeListener(AppContext.DISPOSED_PROPERTY_NAME, - new PropertyChangeListener() { - @Override - public void propertyChange(PropertyChangeEvent pce) { - boolean disposed = (Boolean)pce.getNewValue(); - if (disposed) { - final WeakReference executorServiceRef = - new WeakReference(es); - final ExecutorService executorService = - executorServiceRef.get(); - if (executorService != null) { - executorService.shutdown(); - } - } - } + final Runnable shutdownHook = new Runnable() { + final WeakReference executorServiceRef = + new WeakReference(executorService); + public void run() { + final ExecutorService executorService = executorServiceRef.get(); + if (executorService != null) { + executorService.shutdown(); + } } - ); + }; + ThreadGroup rootTG = ThreadGroupUtils.getRootThreadGroup(); + Thread t = new Thread(rootTG, shutdownHook, + "SwingWorker ES", 0, false); + t.setContextClassLoader(null); + Runtime.getRuntime().addShutdownHook(t); } return executorService; } - private static final Object DO_SUBMIT_KEY = new StringBuilder("doSubmit"); - private static AccumulativeRunnable getDoSubmit() { - synchronized (DO_SUBMIT_KEY) { - final AppContext appContext = AppContext.getAppContext(); - Object doSubmit = appContext.get(DO_SUBMIT_KEY); - if (doSubmit == null) { - doSubmit = new DoSubmitAccumulativeRunnable(); - appContext.put(DO_SUBMIT_KEY, doSubmit); - } - @SuppressWarnings("unchecked") - AccumulativeRunnable tmp = (AccumulativeRunnable) doSubmit; - return tmp; - } - } private static class DoSubmitAccumulativeRunnable extends AccumulativeRunnable implements ActionListener { private static final int DELAY = 1000 / 30; diff --git a/src/java.desktop/share/classes/javax/swing/Timer.java b/src/java.desktop/share/classes/javax/swing/Timer.java index 2cb8381d7d3..1063532715c 100644 --- a/src/java.desktop/share/classes/javax/swing/Timer.java +++ b/src/java.desktop/share/classes/javax/swing/Timer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -173,8 +173,7 @@ public class Timer implements Serializable private final transient Lock lock = new ReentrantLock(); // This field is maintained by TimerQueue. - // eventQueued can also be reset by the TimerQueue, but will only ever - // happen in an AppContext case when TimerQueues thread is destroyed. + // eventQueued can also be reset by the TimerQueue // access to this field is synchronized on getLock() lock. transient TimerQueue.DelayedTimer delayedTimer = null; diff --git a/src/java.desktop/share/classes/javax/swing/UIManager.java b/src/java.desktop/share/classes/javax/swing/UIManager.java index 69063c562e6..f323842ae49 100644 --- a/src/java.desktop/share/classes/javax/swing/UIManager.java +++ b/src/java.desktop/share/classes/javax/swing/UIManager.java @@ -56,7 +56,6 @@ import sun.awt.OSInfo; import sun.swing.SwingUtilities2; import java.util.HashMap; import java.util.Objects; -import sun.awt.AppContext; import sun.awt.AWTAccessor; import sun.swing.SwingAccessor; @@ -179,10 +178,7 @@ public class UIManager implements Serializable /** * This class defines the state managed by the UIManager. For * Swing applications the fields in this class could just as well - * be static members of UIManager however we give them - * "AppContext" - * scope instead so that potentially multiple lightweight - * applications running in a single VM have their own state. + * be static members of UIManager. */ private static class LAFState { @@ -206,8 +202,8 @@ public class UIManager implements Serializable void setSystemDefaults(UIDefaults x) { tables[1] = x; } /** - * Returns the SwingPropertyChangeSupport for the current - * AppContext. If create is a true, a non-null + * Returns the SwingPropertyChangeSupport instance. + * If create is a true, a non-null * SwingPropertyChangeSupport will be returned, if * create is false and this has not been invoked * with true, null will be returned. @@ -1366,18 +1362,7 @@ public class UIManager implements Serializable return; } - // Try to get default LAF from system property, then from AppContext - // (6653395), then use cross-platform one by default. - String lafName = null; - @SuppressWarnings("unchecked") - HashMap lafData = - (HashMap) AppContext.getAppContext().remove("swing.lafdata"); - if (lafData != null) { - lafName = lafData.remove("defaultlaf"); - } - if (lafName == null) { - lafName = getCrossPlatformLookAndFeelClassName(); - } + String lafName = getCrossPlatformLookAndFeelClassName(); lafName = swingProps.getProperty(defaultLAFKey, lafName); try { @@ -1385,13 +1370,6 @@ public class UIManager implements Serializable } catch (Exception e) { throw new Error("Cannot load " + lafName); } - - // Set any properties passed through AppContext (6653395). - if (lafData != null) { - for (Object key: lafData.keySet()) { - UIManager.put(key, lafData.get(key)); - } - } } @@ -1451,8 +1429,8 @@ public class UIManager implements Serializable /* * This method is called before any code that depends on the - * AppContext specific LAFState object runs. - * In some AppContext cases, it's possible for this method + * LAFState object runs. + * In some cases, it's possible for this method * to be re-entered, which is why we grab a lock before calling * initialize(). */ From 6a92c5314464f62889a4042a98b7a14c247ac889 Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Thu, 26 Mar 2026 22:52:44 +0000 Subject: [PATCH 063/359] 8380915: Cleanup some Java declarations of the Vector API Reviewed-by: psandoz --- .../jdk/incubator/vector/AbstractMask.java | 14 ++-- .../jdk/incubator/vector/AbstractShuffle.java | 9 ++- .../jdk/incubator/vector/AbstractSpecies.java | 26 +++--- .../jdk/incubator/vector/AbstractVector.java | 13 +-- .../jdk/incubator/vector/ByteVector.java | 3 +- .../jdk/incubator/vector/ByteVector128.java | 28 +++---- .../jdk/incubator/vector/ByteVector256.java | 28 +++---- .../jdk/incubator/vector/ByteVector512.java | 28 +++---- .../jdk/incubator/vector/ByteVector64.java | 28 +++---- .../jdk/incubator/vector/ByteVectorMax.java | 28 +++---- .../jdk/incubator/vector/CPUFeatures.java | 4 +- .../jdk/incubator/vector/DoubleVector.java | 3 +- .../jdk/incubator/vector/DoubleVector128.java | 29 ++++--- .../jdk/incubator/vector/DoubleVector256.java | 29 ++++--- .../jdk/incubator/vector/DoubleVector512.java | 29 ++++--- .../jdk/incubator/vector/DoubleVector64.java | 29 ++++--- .../jdk/incubator/vector/DoubleVectorMax.java | 29 ++++--- .../jdk/incubator/vector/Float16Consts.java | 4 +- .../jdk/incubator/vector/FloatVector.java | 3 +- .../jdk/incubator/vector/FloatVector128.java | 30 ++++--- .../jdk/incubator/vector/FloatVector256.java | 30 ++++--- .../jdk/incubator/vector/FloatVector512.java | 30 ++++--- .../jdk/incubator/vector/FloatVector64.java | 30 ++++--- .../jdk/incubator/vector/FloatVectorMax.java | 30 ++++--- .../jdk/incubator/vector/IntVector.java | 3 +- .../jdk/incubator/vector/IntVector128.java | 28 +++---- .../jdk/incubator/vector/IntVector256.java | 28 +++---- .../jdk/incubator/vector/IntVector512.java | 28 +++---- .../jdk/incubator/vector/IntVector64.java | 28 +++---- .../jdk/incubator/vector/IntVectorMax.java | 28 +++---- .../jdk/incubator/vector/LongVector.java | 3 +- .../jdk/incubator/vector/LongVector128.java | 27 +++---- .../jdk/incubator/vector/LongVector256.java | 27 +++---- .../jdk/incubator/vector/LongVector512.java | 27 +++---- .../jdk/incubator/vector/LongVector64.java | 27 +++---- .../jdk/incubator/vector/LongVectorMax.java | 27 +++---- .../jdk/incubator/vector/ShortVector.java | 3 +- .../jdk/incubator/vector/ShortVector128.java | 28 +++---- .../jdk/incubator/vector/ShortVector256.java | 28 +++---- .../jdk/incubator/vector/ShortVector512.java | 28 +++---- .../jdk/incubator/vector/ShortVector64.java | 28 +++---- .../jdk/incubator/vector/ShortVectorMax.java | 28 +++---- .../classes/jdk/incubator/vector/Util.java | 4 +- .../classes/jdk/incubator/vector/Vector.java | 5 +- .../incubator/vector/VectorIntrinsics.java | 4 +- .../jdk/incubator/vector/VectorMask.java | 2 +- .../incubator/vector/VectorMathLibrary.java | 2 +- .../jdk/incubator/vector/VectorOperators.java | 79 +++++-------------- .../jdk/incubator/vector/VectorShuffle.java | 4 +- .../jdk/incubator/vector/VectorSpecies.java | 9 +-- .../incubator/vector/X-Vector.java.template | 3 +- .../vector/X-VectorBits.java.template | 33 ++++---- 52 files changed, 498 insertions(+), 585 deletions(-) diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/AbstractMask.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/AbstractMask.java index 5b762edfd3b..9ac90c08c27 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/AbstractMask.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/AbstractMask.java @@ -24,17 +24,19 @@ */ package jdk.incubator.vector; -import java.util.Objects; - -import jdk.internal.vm.annotation.ForceInline; - import jdk.internal.misc.Unsafe; - +import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.vector.VectorSupport; import static jdk.incubator.vector.VectorOperators.*; -abstract class AbstractMask extends VectorMask { +abstract sealed class AbstractMask extends VectorMask + permits ByteVector64.ByteMask64, ByteVector128.ByteMask128, ByteVector256.ByteMask256, ByteVector512.ByteMask512, ByteVectorMax.ByteMaskMax, + DoubleVector64.DoubleMask64, DoubleVector128.DoubleMask128, DoubleVector256.DoubleMask256, DoubleVector512.DoubleMask512, DoubleVectorMax.DoubleMaskMax, + FloatVector64.FloatMask64, FloatVector128.FloatMask128, FloatVector256.FloatMask256, FloatVector512.FloatMask512, FloatVectorMax.FloatMaskMax, + IntVector64.IntMask64, IntVector128.IntMask128, IntVector256.IntMask256, IntVector512.IntMask512, IntVectorMax.IntMaskMax, + LongVector64.LongMask64, LongVector128.LongMask128, LongVector256.LongMask256, LongVector512.LongMask512, LongVectorMax.LongMaskMax, + ShortVector64.ShortMask64, ShortVector128.ShortMask128, ShortVector256.ShortMask256, ShortVector512.ShortMask512, ShortVectorMax.ShortMaskMax { AbstractMask(boolean[] bits) { super(bits); } diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/AbstractShuffle.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/AbstractShuffle.java index 075400a0d4a..bea495f74fc 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/AbstractShuffle.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/AbstractShuffle.java @@ -25,10 +25,17 @@ package jdk.incubator.vector; import java.util.function.IntUnaryOperator; + import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.vector.VectorSupport; -abstract class AbstractShuffle extends VectorShuffle { +abstract sealed class AbstractShuffle extends VectorShuffle + permits ByteVector64.ByteShuffle64, ByteVector128.ByteShuffle128, ByteVector256.ByteShuffle256, ByteVector512.ByteShuffle512, ByteVectorMax.ByteShuffleMax, + DoubleVector64.DoubleShuffle64, DoubleVector128.DoubleShuffle128, DoubleVector256.DoubleShuffle256, DoubleVector512.DoubleShuffle512, DoubleVectorMax.DoubleShuffleMax, + FloatVector64.FloatShuffle64, FloatVector128.FloatShuffle128, FloatVector256.FloatShuffle256, FloatVector512.FloatShuffle512, FloatVectorMax.FloatShuffleMax, + IntVector64.IntShuffle64, IntVector128.IntShuffle128, IntVector256.IntShuffle256, IntVector512.IntShuffle512, IntVectorMax.IntShuffleMax, + LongVector64.LongShuffle64, LongVector128.LongShuffle128, LongVector256.LongShuffle256, LongVector512.LongShuffle512, LongVectorMax.LongShuffleMax, + ShortVector64.ShortShuffle64, ShortVector128.ShortShuffle128, ShortVector256.ShortShuffle256, ShortVector512.ShortShuffle512, ShortVectorMax.ShortShuffleMax { static final IntUnaryOperator IDENTITY = i -> i; // Internal representation allows for a maximum index of E.MAX_VALUE - 1 diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/AbstractSpecies.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/AbstractSpecies.java index 6c834077387..3fd2be34346 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/AbstractSpecies.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/AbstractSpecies.java @@ -24,39 +24,31 @@ */ package jdk.incubator.vector; -import java.lang.foreign.MemorySegment; -import jdk.internal.vm.annotation.ForceInline; -import jdk.internal.vm.annotation.Stable; import java.lang.reflect.Array; -import java.nio.ByteOrder; import java.util.Arrays; import java.util.function.Function; import java.util.function.IntUnaryOperator; -abstract class AbstractSpecies extends jdk.internal.vm.vector.VectorSupport.VectorSpecies - implements VectorSpecies { - @Stable +import jdk.internal.vm.annotation.ForceInline; +import jdk.internal.vm.annotation.Stable; +import jdk.internal.vm.annotation.TrustFinalFields; + +@TrustFinalFields +abstract sealed class AbstractSpecies extends jdk.internal.vm.vector.VectorSupport.VectorSpecies + implements VectorSpecies + permits ByteVector.ByteSpecies, DoubleVector.DoubleSpecies, FloatVector.FloatSpecies, + IntVector.IntSpecies, LongVector.LongSpecies, ShortVector.ShortSpecies { final VectorShape vectorShape; - @Stable final LaneType laneType; - @Stable final int laneCount; - @Stable final int laneCountLog2P1; - @Stable final Class> vectorType; - @Stable final Class> maskType; - @Stable final Class> shuffleType; - @Stable final Function> vectorFactory; - @Stable final VectorShape indexShape; - @Stable final int maxScale, minScale; - @Stable final int vectorBitSize, vectorByteSize; AbstractSpecies(VectorShape vectorShape, diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/AbstractVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/AbstractVector.java index 80260c2bd30..ea8112cc2ae 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/AbstractVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/AbstractVector.java @@ -25,22 +25,17 @@ package jdk.incubator.vector; import java.lang.foreign.MemorySegment; +import java.nio.ByteOrder; +import java.util.function.IntUnaryOperator; -import jdk.internal.foreign.AbstractMemorySegmentImpl; -import jdk.internal.foreign.Utils; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.vector.VectorSupport; -import java.lang.foreign.ValueLayout; -import java.lang.reflect.Array; -import java.nio.ByteOrder; -import java.util.Objects; -import java.util.function.IntUnaryOperator; - import static jdk.incubator.vector.VectorOperators.*; @SuppressWarnings("cast") -abstract class AbstractVector extends Vector { +abstract sealed class AbstractVector extends Vector + permits ByteVector, DoubleVector, FloatVector, IntVector, LongVector, ShortVector { /** * The order of vector bytes when stored in natural, * array elements of the same lane type. 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 846032cb5c6..7231ada3273 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 @@ -49,7 +49,8 @@ import static jdk.incubator.vector.VectorOperators.*; * {@code byte} values. */ @SuppressWarnings("cast") // warning: redundant cast -public abstract class ByteVector extends AbstractVector { +public abstract sealed class ByteVector extends AbstractVector + permits ByteVector64, ByteVector128, ByteVector256, ByteVector512, ByteVectorMax { ByteVector(byte[] vec) { super(vec); diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector128.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector128.java index 360afedbbbb..36ea8d081a8 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector128.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector128.java @@ -25,7 +25,6 @@ package jdk.incubator.vector; import java.lang.foreign.MemorySegment; -import java.lang.foreign.ValueLayout; import java.nio.ByteOrder; import java.util.Arrays; import java.util.Objects; @@ -35,9 +34,8 @@ import jdk.internal.ValueBased; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.vector.VectorSupport; -import static jdk.internal.vm.vector.VectorSupport.*; - import static jdk.incubator.vector.VectorOperators.*; +import static jdk.internal.vm.vector.VectorSupport.*; // -- This file was mechanically generated: Do not edit! -- // @@ -373,7 +371,7 @@ final class ByteVector128 extends ByteVector { @Override @ForceInline public final ByteShuffle128 toShuffle() { - return (ByteShuffle128) toShuffle(vspecies(), false); + return (ByteShuffle128) toShuffle(VSPECIES, false); } // Specialized unary testing @@ -648,7 +646,7 @@ final class ByteVector128 extends ByteVector { @Override ByteMask128 uOp(MUnOp f) { - boolean[] res = new boolean[vspecies().laneCount()]; + boolean[] res = new boolean[VSPECIES.laneCount()]; boolean[] bits = getBits(); for (int i = 0; i < res.length; i++) { res[i] = f.apply(i, bits[i]); @@ -658,7 +656,7 @@ final class ByteVector128 extends ByteVector { @Override ByteMask128 bOp(VectorMask m, MBinOp f) { - boolean[] res = new boolean[vspecies().laneCount()]; + boolean[] res = new boolean[VSPECIES.laneCount()]; boolean[] bits = getBits(); boolean[] mbits = ((ByteMask128)m).getBits(); for (int i = 0; i < res.length; i++) { @@ -808,16 +806,16 @@ final class ByteVector128 extends ByteVector { @ForceInline public boolean anyTrue() { return VectorSupport.test(BT_ne, ByteMask128.class, LANEBITS_TYPE_ORDINAL, VLENGTH, - this, vspecies().maskAll(true), - (m, __) -> anyTrueHelper(((ByteMask128)m).getBits())); + this, VSPECIES.maskAll(true), + (m, _) -> anyTrueHelper(((ByteMask128)m).getBits())); } @Override @ForceInline public boolean allTrue() { return VectorSupport.test(BT_overflow, ByteMask128.class, LANEBITS_TYPE_ORDINAL, VLENGTH, - this, vspecies().maskAll(true), - (m, __) -> allTrueHelper(((ByteMask128)m).getBits())); + this, VSPECIES.maskAll(true), + (m, _) -> allTrueHelper(((ByteMask128)m).getBits())); } @ForceInline @@ -825,7 +823,7 @@ final class ByteVector128 extends ByteVector { static ByteMask128 maskAll(boolean bit) { return VectorSupport.fromBitsCoerced(ByteMask128.class, LANEBITS_TYPE_ORDINAL, VLENGTH, (bit ? -1 : 0), MODE_BROADCAST, null, - (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); + (v, _) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); } private static final ByteMask128 TRUE_MASK = new ByteMask128(true); private static final ByteMask128 FALSE_MASK = new ByteMask128(false); @@ -885,7 +883,7 @@ final class ByteVector128 extends ByteVector { @Override ByteVector128 toBitsVector0() { - return ((ByteVector128) vspecies().asIntegral().dummyVector()).vectorFactory(indices()); + return ((ByteVector128) VSPECIES.asIntegral().dummyVector()).vectorFactory(indices()); } @Override @@ -936,7 +934,7 @@ final class ByteVector128 extends ByteVector { @ForceInline public final ByteMask128 laneIsValid() { return (ByteMask128) toBitsVector().compare(VectorOperators.GE, 0) - .cast(vspecies()); + .cast(VSPECIES); } @ForceInline @@ -944,7 +942,7 @@ final class ByteVector128 extends ByteVector { public final ByteShuffle128 rearrange(VectorShuffle shuffle) { ByteShuffle128 concreteShuffle = (ByteShuffle128) shuffle; return (ByteShuffle128) toBitsVector().rearrange(concreteShuffle) - .toShuffle(vspecies(), false); + .toShuffle(VSPECIES, false); } @ForceInline @@ -957,7 +955,7 @@ final class ByteVector128 extends ByteVector { v = (ByteVector128) v.blend(v.lanewise(VectorOperators.ADD, length()), v.compare(VectorOperators.LT, 0)); } - return (ByteShuffle128) v.toShuffle(vspecies(), false); + return (ByteShuffle128) v.toShuffle(VSPECIES, false); } private static byte[] prepare(int[] indices, int offset) { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector256.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector256.java index ca0c59dd49e..a11268ea40d 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector256.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector256.java @@ -25,7 +25,6 @@ package jdk.incubator.vector; import java.lang.foreign.MemorySegment; -import java.lang.foreign.ValueLayout; import java.nio.ByteOrder; import java.util.Arrays; import java.util.Objects; @@ -35,9 +34,8 @@ import jdk.internal.ValueBased; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.vector.VectorSupport; -import static jdk.internal.vm.vector.VectorSupport.*; - import static jdk.incubator.vector.VectorOperators.*; +import static jdk.internal.vm.vector.VectorSupport.*; // -- This file was mechanically generated: Do not edit! -- // @@ -373,7 +371,7 @@ final class ByteVector256 extends ByteVector { @Override @ForceInline public final ByteShuffle256 toShuffle() { - return (ByteShuffle256) toShuffle(vspecies(), false); + return (ByteShuffle256) toShuffle(VSPECIES, false); } // Specialized unary testing @@ -680,7 +678,7 @@ final class ByteVector256 extends ByteVector { @Override ByteMask256 uOp(MUnOp f) { - boolean[] res = new boolean[vspecies().laneCount()]; + boolean[] res = new boolean[VSPECIES.laneCount()]; boolean[] bits = getBits(); for (int i = 0; i < res.length; i++) { res[i] = f.apply(i, bits[i]); @@ -690,7 +688,7 @@ final class ByteVector256 extends ByteVector { @Override ByteMask256 bOp(VectorMask m, MBinOp f) { - boolean[] res = new boolean[vspecies().laneCount()]; + boolean[] res = new boolean[VSPECIES.laneCount()]; boolean[] bits = getBits(); boolean[] mbits = ((ByteMask256)m).getBits(); for (int i = 0; i < res.length; i++) { @@ -840,16 +838,16 @@ final class ByteVector256 extends ByteVector { @ForceInline public boolean anyTrue() { return VectorSupport.test(BT_ne, ByteMask256.class, LANEBITS_TYPE_ORDINAL, VLENGTH, - this, vspecies().maskAll(true), - (m, __) -> anyTrueHelper(((ByteMask256)m).getBits())); + this, VSPECIES.maskAll(true), + (m, _) -> anyTrueHelper(((ByteMask256)m).getBits())); } @Override @ForceInline public boolean allTrue() { return VectorSupport.test(BT_overflow, ByteMask256.class, LANEBITS_TYPE_ORDINAL, VLENGTH, - this, vspecies().maskAll(true), - (m, __) -> allTrueHelper(((ByteMask256)m).getBits())); + this, VSPECIES.maskAll(true), + (m, _) -> allTrueHelper(((ByteMask256)m).getBits())); } @ForceInline @@ -857,7 +855,7 @@ final class ByteVector256 extends ByteVector { static ByteMask256 maskAll(boolean bit) { return VectorSupport.fromBitsCoerced(ByteMask256.class, LANEBITS_TYPE_ORDINAL, VLENGTH, (bit ? -1 : 0), MODE_BROADCAST, null, - (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); + (v, _) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); } private static final ByteMask256 TRUE_MASK = new ByteMask256(true); private static final ByteMask256 FALSE_MASK = new ByteMask256(false); @@ -917,7 +915,7 @@ final class ByteVector256 extends ByteVector { @Override ByteVector256 toBitsVector0() { - return ((ByteVector256) vspecies().asIntegral().dummyVector()).vectorFactory(indices()); + return ((ByteVector256) VSPECIES.asIntegral().dummyVector()).vectorFactory(indices()); } @Override @@ -968,7 +966,7 @@ final class ByteVector256 extends ByteVector { @ForceInline public final ByteMask256 laneIsValid() { return (ByteMask256) toBitsVector().compare(VectorOperators.GE, 0) - .cast(vspecies()); + .cast(VSPECIES); } @ForceInline @@ -976,7 +974,7 @@ final class ByteVector256 extends ByteVector { public final ByteShuffle256 rearrange(VectorShuffle shuffle) { ByteShuffle256 concreteShuffle = (ByteShuffle256) shuffle; return (ByteShuffle256) toBitsVector().rearrange(concreteShuffle) - .toShuffle(vspecies(), false); + .toShuffle(VSPECIES, false); } @ForceInline @@ -989,7 +987,7 @@ final class ByteVector256 extends ByteVector { v = (ByteVector256) v.blend(v.lanewise(VectorOperators.ADD, length()), v.compare(VectorOperators.LT, 0)); } - return (ByteShuffle256) v.toShuffle(vspecies(), false); + return (ByteShuffle256) v.toShuffle(VSPECIES, false); } private static byte[] prepare(int[] indices, int offset) { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector512.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector512.java index 1a0c69153bc..707254e034e 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector512.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector512.java @@ -25,7 +25,6 @@ package jdk.incubator.vector; import java.lang.foreign.MemorySegment; -import java.lang.foreign.ValueLayout; import java.nio.ByteOrder; import java.util.Arrays; import java.util.Objects; @@ -35,9 +34,8 @@ import jdk.internal.ValueBased; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.vector.VectorSupport; -import static jdk.internal.vm.vector.VectorSupport.*; - import static jdk.incubator.vector.VectorOperators.*; +import static jdk.internal.vm.vector.VectorSupport.*; // -- This file was mechanically generated: Do not edit! -- // @@ -373,7 +371,7 @@ final class ByteVector512 extends ByteVector { @Override @ForceInline public final ByteShuffle512 toShuffle() { - return (ByteShuffle512) toShuffle(vspecies(), false); + return (ByteShuffle512) toShuffle(VSPECIES, false); } // Specialized unary testing @@ -744,7 +742,7 @@ final class ByteVector512 extends ByteVector { @Override ByteMask512 uOp(MUnOp f) { - boolean[] res = new boolean[vspecies().laneCount()]; + boolean[] res = new boolean[VSPECIES.laneCount()]; boolean[] bits = getBits(); for (int i = 0; i < res.length; i++) { res[i] = f.apply(i, bits[i]); @@ -754,7 +752,7 @@ final class ByteVector512 extends ByteVector { @Override ByteMask512 bOp(VectorMask m, MBinOp f) { - boolean[] res = new boolean[vspecies().laneCount()]; + boolean[] res = new boolean[VSPECIES.laneCount()]; boolean[] bits = getBits(); boolean[] mbits = ((ByteMask512)m).getBits(); for (int i = 0; i < res.length; i++) { @@ -904,16 +902,16 @@ final class ByteVector512 extends ByteVector { @ForceInline public boolean anyTrue() { return VectorSupport.test(BT_ne, ByteMask512.class, LANEBITS_TYPE_ORDINAL, VLENGTH, - this, vspecies().maskAll(true), - (m, __) -> anyTrueHelper(((ByteMask512)m).getBits())); + this, VSPECIES.maskAll(true), + (m, _) -> anyTrueHelper(((ByteMask512)m).getBits())); } @Override @ForceInline public boolean allTrue() { return VectorSupport.test(BT_overflow, ByteMask512.class, LANEBITS_TYPE_ORDINAL, VLENGTH, - this, vspecies().maskAll(true), - (m, __) -> allTrueHelper(((ByteMask512)m).getBits())); + this, VSPECIES.maskAll(true), + (m, _) -> allTrueHelper(((ByteMask512)m).getBits())); } @ForceInline @@ -921,7 +919,7 @@ final class ByteVector512 extends ByteVector { static ByteMask512 maskAll(boolean bit) { return VectorSupport.fromBitsCoerced(ByteMask512.class, LANEBITS_TYPE_ORDINAL, VLENGTH, (bit ? -1 : 0), MODE_BROADCAST, null, - (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); + (v, _) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); } private static final ByteMask512 TRUE_MASK = new ByteMask512(true); private static final ByteMask512 FALSE_MASK = new ByteMask512(false); @@ -981,7 +979,7 @@ final class ByteVector512 extends ByteVector { @Override ByteVector512 toBitsVector0() { - return ((ByteVector512) vspecies().asIntegral().dummyVector()).vectorFactory(indices()); + return ((ByteVector512) VSPECIES.asIntegral().dummyVector()).vectorFactory(indices()); } @Override @@ -1032,7 +1030,7 @@ final class ByteVector512 extends ByteVector { @ForceInline public final ByteMask512 laneIsValid() { return (ByteMask512) toBitsVector().compare(VectorOperators.GE, 0) - .cast(vspecies()); + .cast(VSPECIES); } @ForceInline @@ -1040,7 +1038,7 @@ final class ByteVector512 extends ByteVector { public final ByteShuffle512 rearrange(VectorShuffle shuffle) { ByteShuffle512 concreteShuffle = (ByteShuffle512) shuffle; return (ByteShuffle512) toBitsVector().rearrange(concreteShuffle) - .toShuffle(vspecies(), false); + .toShuffle(VSPECIES, false); } @ForceInline @@ -1053,7 +1051,7 @@ final class ByteVector512 extends ByteVector { v = (ByteVector512) v.blend(v.lanewise(VectorOperators.ADD, length()), v.compare(VectorOperators.LT, 0)); } - return (ByteShuffle512) v.toShuffle(vspecies(), false); + return (ByteShuffle512) v.toShuffle(VSPECIES, false); } private static byte[] prepare(int[] indices, int offset) { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector64.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector64.java index 50561eca0f8..d304edfc0c7 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector64.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector64.java @@ -25,7 +25,6 @@ package jdk.incubator.vector; import java.lang.foreign.MemorySegment; -import java.lang.foreign.ValueLayout; import java.nio.ByteOrder; import java.util.Arrays; import java.util.Objects; @@ -35,9 +34,8 @@ import jdk.internal.ValueBased; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.vector.VectorSupport; -import static jdk.internal.vm.vector.VectorSupport.*; - import static jdk.incubator.vector.VectorOperators.*; +import static jdk.internal.vm.vector.VectorSupport.*; // -- This file was mechanically generated: Do not edit! -- // @@ -373,7 +371,7 @@ final class ByteVector64 extends ByteVector { @Override @ForceInline public final ByteShuffle64 toShuffle() { - return (ByteShuffle64) toShuffle(vspecies(), false); + return (ByteShuffle64) toShuffle(VSPECIES, false); } // Specialized unary testing @@ -632,7 +630,7 @@ final class ByteVector64 extends ByteVector { @Override ByteMask64 uOp(MUnOp f) { - boolean[] res = new boolean[vspecies().laneCount()]; + boolean[] res = new boolean[VSPECIES.laneCount()]; boolean[] bits = getBits(); for (int i = 0; i < res.length; i++) { res[i] = f.apply(i, bits[i]); @@ -642,7 +640,7 @@ final class ByteVector64 extends ByteVector { @Override ByteMask64 bOp(VectorMask m, MBinOp f) { - boolean[] res = new boolean[vspecies().laneCount()]; + boolean[] res = new boolean[VSPECIES.laneCount()]; boolean[] bits = getBits(); boolean[] mbits = ((ByteMask64)m).getBits(); for (int i = 0; i < res.length; i++) { @@ -792,16 +790,16 @@ final class ByteVector64 extends ByteVector { @ForceInline public boolean anyTrue() { return VectorSupport.test(BT_ne, ByteMask64.class, LANEBITS_TYPE_ORDINAL, VLENGTH, - this, vspecies().maskAll(true), - (m, __) -> anyTrueHelper(((ByteMask64)m).getBits())); + this, VSPECIES.maskAll(true), + (m, _) -> anyTrueHelper(((ByteMask64)m).getBits())); } @Override @ForceInline public boolean allTrue() { return VectorSupport.test(BT_overflow, ByteMask64.class, LANEBITS_TYPE_ORDINAL, VLENGTH, - this, vspecies().maskAll(true), - (m, __) -> allTrueHelper(((ByteMask64)m).getBits())); + this, VSPECIES.maskAll(true), + (m, _) -> allTrueHelper(((ByteMask64)m).getBits())); } @ForceInline @@ -809,7 +807,7 @@ final class ByteVector64 extends ByteVector { static ByteMask64 maskAll(boolean bit) { return VectorSupport.fromBitsCoerced(ByteMask64.class, LANEBITS_TYPE_ORDINAL, VLENGTH, (bit ? -1 : 0), MODE_BROADCAST, null, - (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); + (v, _) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); } private static final ByteMask64 TRUE_MASK = new ByteMask64(true); private static final ByteMask64 FALSE_MASK = new ByteMask64(false); @@ -869,7 +867,7 @@ final class ByteVector64 extends ByteVector { @Override ByteVector64 toBitsVector0() { - return ((ByteVector64) vspecies().asIntegral().dummyVector()).vectorFactory(indices()); + return ((ByteVector64) VSPECIES.asIntegral().dummyVector()).vectorFactory(indices()); } @Override @@ -920,7 +918,7 @@ final class ByteVector64 extends ByteVector { @ForceInline public final ByteMask64 laneIsValid() { return (ByteMask64) toBitsVector().compare(VectorOperators.GE, 0) - .cast(vspecies()); + .cast(VSPECIES); } @ForceInline @@ -928,7 +926,7 @@ final class ByteVector64 extends ByteVector { public final ByteShuffle64 rearrange(VectorShuffle shuffle) { ByteShuffle64 concreteShuffle = (ByteShuffle64) shuffle; return (ByteShuffle64) toBitsVector().rearrange(concreteShuffle) - .toShuffle(vspecies(), false); + .toShuffle(VSPECIES, false); } @ForceInline @@ -941,7 +939,7 @@ final class ByteVector64 extends ByteVector { v = (ByteVector64) v.blend(v.lanewise(VectorOperators.ADD, length()), v.compare(VectorOperators.LT, 0)); } - return (ByteShuffle64) v.toShuffle(vspecies(), false); + return (ByteShuffle64) v.toShuffle(VSPECIES, false); } private static byte[] prepare(int[] indices, int offset) { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVectorMax.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVectorMax.java index ee931bbc077..0084995346b 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVectorMax.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVectorMax.java @@ -25,7 +25,6 @@ package jdk.incubator.vector; import java.lang.foreign.MemorySegment; -import java.lang.foreign.ValueLayout; import java.nio.ByteOrder; import java.util.Arrays; import java.util.Objects; @@ -35,9 +34,8 @@ import jdk.internal.ValueBased; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.vector.VectorSupport; -import static jdk.internal.vm.vector.VectorSupport.*; - import static jdk.incubator.vector.VectorOperators.*; +import static jdk.internal.vm.vector.VectorSupport.*; // -- This file was mechanically generated: Do not edit! -- // @@ -373,7 +371,7 @@ final class ByteVectorMax extends ByteVector { @Override @ForceInline public final ByteShuffleMax toShuffle() { - return (ByteShuffleMax) toShuffle(vspecies(), false); + return (ByteShuffleMax) toShuffle(VSPECIES, false); } // Specialized unary testing @@ -618,7 +616,7 @@ final class ByteVectorMax extends ByteVector { @Override ByteMaskMax uOp(MUnOp f) { - boolean[] res = new boolean[vspecies().laneCount()]; + boolean[] res = new boolean[VSPECIES.laneCount()]; boolean[] bits = getBits(); for (int i = 0; i < res.length; i++) { res[i] = f.apply(i, bits[i]); @@ -628,7 +626,7 @@ final class ByteVectorMax extends ByteVector { @Override ByteMaskMax bOp(VectorMask m, MBinOp f) { - boolean[] res = new boolean[vspecies().laneCount()]; + boolean[] res = new boolean[VSPECIES.laneCount()]; boolean[] bits = getBits(); boolean[] mbits = ((ByteMaskMax)m).getBits(); for (int i = 0; i < res.length; i++) { @@ -778,16 +776,16 @@ final class ByteVectorMax extends ByteVector { @ForceInline public boolean anyTrue() { return VectorSupport.test(BT_ne, ByteMaskMax.class, LANEBITS_TYPE_ORDINAL, VLENGTH, - this, vspecies().maskAll(true), - (m, __) -> anyTrueHelper(((ByteMaskMax)m).getBits())); + this, VSPECIES.maskAll(true), + (m, _) -> anyTrueHelper(((ByteMaskMax)m).getBits())); } @Override @ForceInline public boolean allTrue() { return VectorSupport.test(BT_overflow, ByteMaskMax.class, LANEBITS_TYPE_ORDINAL, VLENGTH, - this, vspecies().maskAll(true), - (m, __) -> allTrueHelper(((ByteMaskMax)m).getBits())); + this, VSPECIES.maskAll(true), + (m, _) -> allTrueHelper(((ByteMaskMax)m).getBits())); } @ForceInline @@ -795,7 +793,7 @@ final class ByteVectorMax extends ByteVector { static ByteMaskMax maskAll(boolean bit) { return VectorSupport.fromBitsCoerced(ByteMaskMax.class, LANEBITS_TYPE_ORDINAL, VLENGTH, (bit ? -1 : 0), MODE_BROADCAST, null, - (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); + (v, _) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); } private static final ByteMaskMax TRUE_MASK = new ByteMaskMax(true); private static final ByteMaskMax FALSE_MASK = new ByteMaskMax(false); @@ -855,7 +853,7 @@ final class ByteVectorMax extends ByteVector { @Override ByteVectorMax toBitsVector0() { - return ((ByteVectorMax) vspecies().asIntegral().dummyVector()).vectorFactory(indices()); + return ((ByteVectorMax) VSPECIES.asIntegral().dummyVector()).vectorFactory(indices()); } @Override @@ -906,7 +904,7 @@ final class ByteVectorMax extends ByteVector { @ForceInline public final ByteMaskMax laneIsValid() { return (ByteMaskMax) toBitsVector().compare(VectorOperators.GE, 0) - .cast(vspecies()); + .cast(VSPECIES); } @ForceInline @@ -914,7 +912,7 @@ final class ByteVectorMax extends ByteVector { public final ByteShuffleMax rearrange(VectorShuffle shuffle) { ByteShuffleMax concreteShuffle = (ByteShuffleMax) shuffle; return (ByteShuffleMax) toBitsVector().rearrange(concreteShuffle) - .toShuffle(vspecies(), false); + .toShuffle(VSPECIES, false); } @ForceInline @@ -927,7 +925,7 @@ final class ByteVectorMax extends ByteVector { v = (ByteVectorMax) v.blend(v.lanewise(VectorOperators.ADD, length()), v.compare(VectorOperators.LT, 0)); } - return (ByteShuffleMax) v.toShuffle(vspecies(), false); + return (ByteShuffleMax) v.toShuffle(VSPECIES, false); } private static byte[] prepare(int[] indices, int offset) { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/CPUFeatures.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/CPUFeatures.java index c0d8ef03ada..0ad7ba1651d 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/CPUFeatures.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/CPUFeatures.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * 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 static jdk.internal.vm.vector.Utils.debug; /** * Enumerates CPU ISA extensions supported by the JVM on the current hardware. */ -/*package-private*/ class CPUFeatures { +/*package-private*/ final class CPUFeatures { private static final Set features = getCPUFeatures(); private static Set getCPUFeatures() { 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 5e7c97dc56d..6f9b5e53ead 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 @@ -49,7 +49,8 @@ import static jdk.incubator.vector.VectorOperators.*; * {@code double} values. */ @SuppressWarnings("cast") // warning: redundant cast -public abstract class DoubleVector extends AbstractVector { +public abstract sealed class DoubleVector extends AbstractVector + permits DoubleVector64, DoubleVector128, DoubleVector256, DoubleVector512, DoubleVectorMax { DoubleVector(double[] vec) { super(vec); diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector128.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector128.java index 43c7e3f0c46..8d3ec21ec9b 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector128.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector128.java @@ -35,9 +35,8 @@ import jdk.internal.ValueBased; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.vector.VectorSupport; -import static jdk.internal.vm.vector.VectorSupport.*; - import static jdk.incubator.vector.VectorOperators.*; +import static jdk.internal.vm.vector.VectorSupport.*; // -- This file was mechanically generated: Do not edit! -- // @@ -360,7 +359,7 @@ final class DoubleVector128 extends DoubleVector { @Override @ForceInline public final DoubleShuffle128 toShuffle() { - return (DoubleShuffle128) toShuffle(vspecies(), false); + return (DoubleShuffle128) toShuffle(VSPECIES, false); } // Specialized unary testing @@ -609,7 +608,7 @@ final class DoubleVector128 extends DoubleVector { @Override DoubleMask128 uOp(MUnOp f) { - boolean[] res = new boolean[vspecies().laneCount()]; + boolean[] res = new boolean[VSPECIES.laneCount()]; boolean[] bits = getBits(); for (int i = 0; i < res.length; i++) { res[i] = f.apply(i, bits[i]); @@ -619,7 +618,7 @@ final class DoubleVector128 extends DoubleVector { @Override DoubleMask128 bOp(VectorMask m, MBinOp f) { - boolean[] res = new boolean[vspecies().laneCount()]; + boolean[] res = new boolean[VSPECIES.laneCount()]; boolean[] bits = getBits(); boolean[] mbits = ((DoubleMask128)m).getBits(); for (int i = 0; i < res.length; i++) { @@ -769,16 +768,16 @@ final class DoubleVector128 extends DoubleVector { @ForceInline public boolean anyTrue() { return VectorSupport.test(BT_ne, DoubleMask128.class, LANEBITS_TYPE_ORDINAL, VLENGTH, - this, vspecies().maskAll(true), - (m, __) -> anyTrueHelper(((DoubleMask128)m).getBits())); + this, VSPECIES.maskAll(true), + (m, _) -> anyTrueHelper(((DoubleMask128)m).getBits())); } @Override @ForceInline public boolean allTrue() { return VectorSupport.test(BT_overflow, DoubleMask128.class, LANEBITS_TYPE_ORDINAL, VLENGTH, - this, vspecies().maskAll(true), - (m, __) -> allTrueHelper(((DoubleMask128)m).getBits())); + this, VSPECIES.maskAll(true), + (m, _) -> allTrueHelper(((DoubleMask128)m).getBits())); } @ForceInline @@ -786,7 +785,7 @@ final class DoubleVector128 extends DoubleVector { static DoubleMask128 maskAll(boolean bit) { return VectorSupport.fromBitsCoerced(DoubleMask128.class, LANEBITS_TYPE_ORDINAL, VLENGTH, (bit ? -1 : 0), MODE_BROADCAST, null, - (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); + (v, _) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); } private static final DoubleMask128 TRUE_MASK = new DoubleMask128(true); private static final DoubleMask128 FALSE_MASK = new DoubleMask128(false); @@ -835,7 +834,7 @@ final class DoubleVector128 extends DoubleVector { @Override @ForceInline public DoubleVector128 toVector() { - return (DoubleVector128) toBitsVector().castShape(vspecies(), 0); + return (DoubleVector128) toBitsVector().castShape(VSPECIES, 0); } @Override @@ -846,7 +845,7 @@ final class DoubleVector128 extends DoubleVector { @Override LongVector128 toBitsVector0() { - return ((LongVector128) vspecies().asIntegral().dummyVector()).vectorFactory(indices()); + return ((LongVector128) VSPECIES.asIntegral().dummyVector()).vectorFactory(indices()); } @Override @@ -920,7 +919,7 @@ final class DoubleVector128 extends DoubleVector { @ForceInline public final DoubleMask128 laneIsValid() { return (DoubleMask128) toBitsVector().compare(VectorOperators.GE, 0) - .cast(vspecies()); + .cast(VSPECIES); } @ForceInline @@ -928,7 +927,7 @@ final class DoubleVector128 extends DoubleVector { public final DoubleShuffle128 rearrange(VectorShuffle shuffle) { DoubleShuffle128 concreteShuffle = (DoubleShuffle128) shuffle; return (DoubleShuffle128) toBitsVector().rearrange(concreteShuffle.cast(LongVector.SPECIES_128)) - .toShuffle(vspecies(), false); + .toShuffle(VSPECIES, false); } @ForceInline @@ -941,7 +940,7 @@ final class DoubleVector128 extends DoubleVector { v = (LongVector128) v.blend(v.lanewise(VectorOperators.ADD, length()), v.compare(VectorOperators.LT, 0)); } - return (DoubleShuffle128) v.toShuffle(vspecies(), false); + return (DoubleShuffle128) v.toShuffle(VSPECIES, false); } private static long[] prepare(int[] indices, int offset) { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector256.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector256.java index 5f176854dbd..c6bb4b7e3d3 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector256.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector256.java @@ -35,9 +35,8 @@ import jdk.internal.ValueBased; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.vector.VectorSupport; -import static jdk.internal.vm.vector.VectorSupport.*; - import static jdk.incubator.vector.VectorOperators.*; +import static jdk.internal.vm.vector.VectorSupport.*; // -- This file was mechanically generated: Do not edit! -- // @@ -360,7 +359,7 @@ final class DoubleVector256 extends DoubleVector { @Override @ForceInline public final DoubleShuffle256 toShuffle() { - return (DoubleShuffle256) toShuffle(vspecies(), false); + return (DoubleShuffle256) toShuffle(VSPECIES, false); } // Specialized unary testing @@ -613,7 +612,7 @@ final class DoubleVector256 extends DoubleVector { @Override DoubleMask256 uOp(MUnOp f) { - boolean[] res = new boolean[vspecies().laneCount()]; + boolean[] res = new boolean[VSPECIES.laneCount()]; boolean[] bits = getBits(); for (int i = 0; i < res.length; i++) { res[i] = f.apply(i, bits[i]); @@ -623,7 +622,7 @@ final class DoubleVector256 extends DoubleVector { @Override DoubleMask256 bOp(VectorMask m, MBinOp f) { - boolean[] res = new boolean[vspecies().laneCount()]; + boolean[] res = new boolean[VSPECIES.laneCount()]; boolean[] bits = getBits(); boolean[] mbits = ((DoubleMask256)m).getBits(); for (int i = 0; i < res.length; i++) { @@ -773,16 +772,16 @@ final class DoubleVector256 extends DoubleVector { @ForceInline public boolean anyTrue() { return VectorSupport.test(BT_ne, DoubleMask256.class, LANEBITS_TYPE_ORDINAL, VLENGTH, - this, vspecies().maskAll(true), - (m, __) -> anyTrueHelper(((DoubleMask256)m).getBits())); + this, VSPECIES.maskAll(true), + (m, _) -> anyTrueHelper(((DoubleMask256)m).getBits())); } @Override @ForceInline public boolean allTrue() { return VectorSupport.test(BT_overflow, DoubleMask256.class, LANEBITS_TYPE_ORDINAL, VLENGTH, - this, vspecies().maskAll(true), - (m, __) -> allTrueHelper(((DoubleMask256)m).getBits())); + this, VSPECIES.maskAll(true), + (m, _) -> allTrueHelper(((DoubleMask256)m).getBits())); } @ForceInline @@ -790,7 +789,7 @@ final class DoubleVector256 extends DoubleVector { static DoubleMask256 maskAll(boolean bit) { return VectorSupport.fromBitsCoerced(DoubleMask256.class, LANEBITS_TYPE_ORDINAL, VLENGTH, (bit ? -1 : 0), MODE_BROADCAST, null, - (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); + (v, _) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); } private static final DoubleMask256 TRUE_MASK = new DoubleMask256(true); private static final DoubleMask256 FALSE_MASK = new DoubleMask256(false); @@ -839,7 +838,7 @@ final class DoubleVector256 extends DoubleVector { @Override @ForceInline public DoubleVector256 toVector() { - return (DoubleVector256) toBitsVector().castShape(vspecies(), 0); + return (DoubleVector256) toBitsVector().castShape(VSPECIES, 0); } @Override @@ -850,7 +849,7 @@ final class DoubleVector256 extends DoubleVector { @Override LongVector256 toBitsVector0() { - return ((LongVector256) vspecies().asIntegral().dummyVector()).vectorFactory(indices()); + return ((LongVector256) VSPECIES.asIntegral().dummyVector()).vectorFactory(indices()); } @Override @@ -924,7 +923,7 @@ final class DoubleVector256 extends DoubleVector { @ForceInline public final DoubleMask256 laneIsValid() { return (DoubleMask256) toBitsVector().compare(VectorOperators.GE, 0) - .cast(vspecies()); + .cast(VSPECIES); } @ForceInline @@ -932,7 +931,7 @@ final class DoubleVector256 extends DoubleVector { public final DoubleShuffle256 rearrange(VectorShuffle shuffle) { DoubleShuffle256 concreteShuffle = (DoubleShuffle256) shuffle; return (DoubleShuffle256) toBitsVector().rearrange(concreteShuffle.cast(LongVector.SPECIES_256)) - .toShuffle(vspecies(), false); + .toShuffle(VSPECIES, false); } @ForceInline @@ -945,7 +944,7 @@ final class DoubleVector256 extends DoubleVector { v = (LongVector256) v.blend(v.lanewise(VectorOperators.ADD, length()), v.compare(VectorOperators.LT, 0)); } - return (DoubleShuffle256) v.toShuffle(vspecies(), false); + return (DoubleShuffle256) v.toShuffle(VSPECIES, false); } private static long[] prepare(int[] indices, int offset) { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector512.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector512.java index 0696f48163d..fb1441efc63 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector512.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector512.java @@ -35,9 +35,8 @@ import jdk.internal.ValueBased; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.vector.VectorSupport; -import static jdk.internal.vm.vector.VectorSupport.*; - import static jdk.incubator.vector.VectorOperators.*; +import static jdk.internal.vm.vector.VectorSupport.*; // -- This file was mechanically generated: Do not edit! -- // @@ -360,7 +359,7 @@ final class DoubleVector512 extends DoubleVector { @Override @ForceInline public final DoubleShuffle512 toShuffle() { - return (DoubleShuffle512) toShuffle(vspecies(), false); + return (DoubleShuffle512) toShuffle(VSPECIES, false); } // Specialized unary testing @@ -621,7 +620,7 @@ final class DoubleVector512 extends DoubleVector { @Override DoubleMask512 uOp(MUnOp f) { - boolean[] res = new boolean[vspecies().laneCount()]; + boolean[] res = new boolean[VSPECIES.laneCount()]; boolean[] bits = getBits(); for (int i = 0; i < res.length; i++) { res[i] = f.apply(i, bits[i]); @@ -631,7 +630,7 @@ final class DoubleVector512 extends DoubleVector { @Override DoubleMask512 bOp(VectorMask m, MBinOp f) { - boolean[] res = new boolean[vspecies().laneCount()]; + boolean[] res = new boolean[VSPECIES.laneCount()]; boolean[] bits = getBits(); boolean[] mbits = ((DoubleMask512)m).getBits(); for (int i = 0; i < res.length; i++) { @@ -781,16 +780,16 @@ final class DoubleVector512 extends DoubleVector { @ForceInline public boolean anyTrue() { return VectorSupport.test(BT_ne, DoubleMask512.class, LANEBITS_TYPE_ORDINAL, VLENGTH, - this, vspecies().maskAll(true), - (m, __) -> anyTrueHelper(((DoubleMask512)m).getBits())); + this, VSPECIES.maskAll(true), + (m, _) -> anyTrueHelper(((DoubleMask512)m).getBits())); } @Override @ForceInline public boolean allTrue() { return VectorSupport.test(BT_overflow, DoubleMask512.class, LANEBITS_TYPE_ORDINAL, VLENGTH, - this, vspecies().maskAll(true), - (m, __) -> allTrueHelper(((DoubleMask512)m).getBits())); + this, VSPECIES.maskAll(true), + (m, _) -> allTrueHelper(((DoubleMask512)m).getBits())); } @ForceInline @@ -798,7 +797,7 @@ final class DoubleVector512 extends DoubleVector { static DoubleMask512 maskAll(boolean bit) { return VectorSupport.fromBitsCoerced(DoubleMask512.class, LANEBITS_TYPE_ORDINAL, VLENGTH, (bit ? -1 : 0), MODE_BROADCAST, null, - (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); + (v, _) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); } private static final DoubleMask512 TRUE_MASK = new DoubleMask512(true); private static final DoubleMask512 FALSE_MASK = new DoubleMask512(false); @@ -847,7 +846,7 @@ final class DoubleVector512 extends DoubleVector { @Override @ForceInline public DoubleVector512 toVector() { - return (DoubleVector512) toBitsVector().castShape(vspecies(), 0); + return (DoubleVector512) toBitsVector().castShape(VSPECIES, 0); } @Override @@ -858,7 +857,7 @@ final class DoubleVector512 extends DoubleVector { @Override LongVector512 toBitsVector0() { - return ((LongVector512) vspecies().asIntegral().dummyVector()).vectorFactory(indices()); + return ((LongVector512) VSPECIES.asIntegral().dummyVector()).vectorFactory(indices()); } @Override @@ -932,7 +931,7 @@ final class DoubleVector512 extends DoubleVector { @ForceInline public final DoubleMask512 laneIsValid() { return (DoubleMask512) toBitsVector().compare(VectorOperators.GE, 0) - .cast(vspecies()); + .cast(VSPECIES); } @ForceInline @@ -940,7 +939,7 @@ final class DoubleVector512 extends DoubleVector { public final DoubleShuffle512 rearrange(VectorShuffle shuffle) { DoubleShuffle512 concreteShuffle = (DoubleShuffle512) shuffle; return (DoubleShuffle512) toBitsVector().rearrange(concreteShuffle.cast(LongVector.SPECIES_512)) - .toShuffle(vspecies(), false); + .toShuffle(VSPECIES, false); } @ForceInline @@ -953,7 +952,7 @@ final class DoubleVector512 extends DoubleVector { v = (LongVector512) v.blend(v.lanewise(VectorOperators.ADD, length()), v.compare(VectorOperators.LT, 0)); } - return (DoubleShuffle512) v.toShuffle(vspecies(), false); + return (DoubleShuffle512) v.toShuffle(VSPECIES, false); } private static long[] prepare(int[] indices, int offset) { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector64.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector64.java index 5b74c2c4619..5583cff80e1 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector64.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector64.java @@ -35,9 +35,8 @@ import jdk.internal.ValueBased; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.vector.VectorSupport; -import static jdk.internal.vm.vector.VectorSupport.*; - import static jdk.incubator.vector.VectorOperators.*; +import static jdk.internal.vm.vector.VectorSupport.*; // -- This file was mechanically generated: Do not edit! -- // @@ -360,7 +359,7 @@ final class DoubleVector64 extends DoubleVector { @Override @ForceInline public final DoubleShuffle64 toShuffle() { - return (DoubleShuffle64) toShuffle(vspecies(), false); + return (DoubleShuffle64) toShuffle(VSPECIES, false); } // Specialized unary testing @@ -607,7 +606,7 @@ final class DoubleVector64 extends DoubleVector { @Override DoubleMask64 uOp(MUnOp f) { - boolean[] res = new boolean[vspecies().laneCount()]; + boolean[] res = new boolean[VSPECIES.laneCount()]; boolean[] bits = getBits(); for (int i = 0; i < res.length; i++) { res[i] = f.apply(i, bits[i]); @@ -617,7 +616,7 @@ final class DoubleVector64 extends DoubleVector { @Override DoubleMask64 bOp(VectorMask m, MBinOp f) { - boolean[] res = new boolean[vspecies().laneCount()]; + boolean[] res = new boolean[VSPECIES.laneCount()]; boolean[] bits = getBits(); boolean[] mbits = ((DoubleMask64)m).getBits(); for (int i = 0; i < res.length; i++) { @@ -767,16 +766,16 @@ final class DoubleVector64 extends DoubleVector { @ForceInline public boolean anyTrue() { return VectorSupport.test(BT_ne, DoubleMask64.class, LANEBITS_TYPE_ORDINAL, VLENGTH, - this, vspecies().maskAll(true), - (m, __) -> anyTrueHelper(((DoubleMask64)m).getBits())); + this, VSPECIES.maskAll(true), + (m, _) -> anyTrueHelper(((DoubleMask64)m).getBits())); } @Override @ForceInline public boolean allTrue() { return VectorSupport.test(BT_overflow, DoubleMask64.class, LANEBITS_TYPE_ORDINAL, VLENGTH, - this, vspecies().maskAll(true), - (m, __) -> allTrueHelper(((DoubleMask64)m).getBits())); + this, VSPECIES.maskAll(true), + (m, _) -> allTrueHelper(((DoubleMask64)m).getBits())); } @ForceInline @@ -784,7 +783,7 @@ final class DoubleVector64 extends DoubleVector { static DoubleMask64 maskAll(boolean bit) { return VectorSupport.fromBitsCoerced(DoubleMask64.class, LANEBITS_TYPE_ORDINAL, VLENGTH, (bit ? -1 : 0), MODE_BROADCAST, null, - (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); + (v, _) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); } private static final DoubleMask64 TRUE_MASK = new DoubleMask64(true); private static final DoubleMask64 FALSE_MASK = new DoubleMask64(false); @@ -833,7 +832,7 @@ final class DoubleVector64 extends DoubleVector { @Override @ForceInline public DoubleVector64 toVector() { - return (DoubleVector64) toBitsVector().castShape(vspecies(), 0); + return (DoubleVector64) toBitsVector().castShape(VSPECIES, 0); } @Override @@ -844,7 +843,7 @@ final class DoubleVector64 extends DoubleVector { @Override LongVector64 toBitsVector0() { - return ((LongVector64) vspecies().asIntegral().dummyVector()).vectorFactory(indices()); + return ((LongVector64) VSPECIES.asIntegral().dummyVector()).vectorFactory(indices()); } @Override @@ -918,7 +917,7 @@ final class DoubleVector64 extends DoubleVector { @ForceInline public final DoubleMask64 laneIsValid() { return (DoubleMask64) toBitsVector().compare(VectorOperators.GE, 0) - .cast(vspecies()); + .cast(VSPECIES); } @ForceInline @@ -926,7 +925,7 @@ final class DoubleVector64 extends DoubleVector { public final DoubleShuffle64 rearrange(VectorShuffle shuffle) { DoubleShuffle64 concreteShuffle = (DoubleShuffle64) shuffle; return (DoubleShuffle64) toBitsVector().rearrange(concreteShuffle.cast(LongVector.SPECIES_64)) - .toShuffle(vspecies(), false); + .toShuffle(VSPECIES, false); } @ForceInline @@ -939,7 +938,7 @@ final class DoubleVector64 extends DoubleVector { v = (LongVector64) v.blend(v.lanewise(VectorOperators.ADD, length()), v.compare(VectorOperators.LT, 0)); } - return (DoubleShuffle64) v.toShuffle(vspecies(), false); + return (DoubleShuffle64) v.toShuffle(VSPECIES, false); } private static long[] prepare(int[] indices, int offset) { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVectorMax.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVectorMax.java index 07d227d641a..41272a5a5e5 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVectorMax.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVectorMax.java @@ -35,9 +35,8 @@ import jdk.internal.ValueBased; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.vector.VectorSupport; -import static jdk.internal.vm.vector.VectorSupport.*; - import static jdk.incubator.vector.VectorOperators.*; +import static jdk.internal.vm.vector.VectorSupport.*; // -- This file was mechanically generated: Do not edit! -- // @@ -360,7 +359,7 @@ final class DoubleVectorMax extends DoubleVector { @Override @ForceInline public final DoubleShuffleMax toShuffle() { - return (DoubleShuffleMax) toShuffle(vspecies(), false); + return (DoubleShuffleMax) toShuffle(VSPECIES, false); } // Specialized unary testing @@ -606,7 +605,7 @@ final class DoubleVectorMax extends DoubleVector { @Override DoubleMaskMax uOp(MUnOp f) { - boolean[] res = new boolean[vspecies().laneCount()]; + boolean[] res = new boolean[VSPECIES.laneCount()]; boolean[] bits = getBits(); for (int i = 0; i < res.length; i++) { res[i] = f.apply(i, bits[i]); @@ -616,7 +615,7 @@ final class DoubleVectorMax extends DoubleVector { @Override DoubleMaskMax bOp(VectorMask m, MBinOp f) { - boolean[] res = new boolean[vspecies().laneCount()]; + boolean[] res = new boolean[VSPECIES.laneCount()]; boolean[] bits = getBits(); boolean[] mbits = ((DoubleMaskMax)m).getBits(); for (int i = 0; i < res.length; i++) { @@ -766,16 +765,16 @@ final class DoubleVectorMax extends DoubleVector { @ForceInline public boolean anyTrue() { return VectorSupport.test(BT_ne, DoubleMaskMax.class, LANEBITS_TYPE_ORDINAL, VLENGTH, - this, vspecies().maskAll(true), - (m, __) -> anyTrueHelper(((DoubleMaskMax)m).getBits())); + this, VSPECIES.maskAll(true), + (m, _) -> anyTrueHelper(((DoubleMaskMax)m).getBits())); } @Override @ForceInline public boolean allTrue() { return VectorSupport.test(BT_overflow, DoubleMaskMax.class, LANEBITS_TYPE_ORDINAL, VLENGTH, - this, vspecies().maskAll(true), - (m, __) -> allTrueHelper(((DoubleMaskMax)m).getBits())); + this, VSPECIES.maskAll(true), + (m, _) -> allTrueHelper(((DoubleMaskMax)m).getBits())); } @ForceInline @@ -783,7 +782,7 @@ final class DoubleVectorMax extends DoubleVector { static DoubleMaskMax maskAll(boolean bit) { return VectorSupport.fromBitsCoerced(DoubleMaskMax.class, LANEBITS_TYPE_ORDINAL, VLENGTH, (bit ? -1 : 0), MODE_BROADCAST, null, - (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); + (v, _) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); } private static final DoubleMaskMax TRUE_MASK = new DoubleMaskMax(true); private static final DoubleMaskMax FALSE_MASK = new DoubleMaskMax(false); @@ -832,7 +831,7 @@ final class DoubleVectorMax extends DoubleVector { @Override @ForceInline public DoubleVectorMax toVector() { - return (DoubleVectorMax) toBitsVector().castShape(vspecies(), 0); + return (DoubleVectorMax) toBitsVector().castShape(VSPECIES, 0); } @Override @@ -843,7 +842,7 @@ final class DoubleVectorMax extends DoubleVector { @Override LongVectorMax toBitsVector0() { - return ((LongVectorMax) vspecies().asIntegral().dummyVector()).vectorFactory(indices()); + return ((LongVectorMax) VSPECIES.asIntegral().dummyVector()).vectorFactory(indices()); } @Override @@ -917,7 +916,7 @@ final class DoubleVectorMax extends DoubleVector { @ForceInline public final DoubleMaskMax laneIsValid() { return (DoubleMaskMax) toBitsVector().compare(VectorOperators.GE, 0) - .cast(vspecies()); + .cast(VSPECIES); } @ForceInline @@ -925,7 +924,7 @@ final class DoubleVectorMax extends DoubleVector { public final DoubleShuffleMax rearrange(VectorShuffle shuffle) { DoubleShuffleMax concreteShuffle = (DoubleShuffleMax) shuffle; return (DoubleShuffleMax) toBitsVector().rearrange(concreteShuffle.cast(LongVector.SPECIES_MAX)) - .toShuffle(vspecies(), false); + .toShuffle(VSPECIES, false); } @ForceInline @@ -938,7 +937,7 @@ final class DoubleVectorMax extends DoubleVector { v = (LongVectorMax) v.blend(v.lanewise(VectorOperators.ADD, length()), v.compare(VectorOperators.LT, 0)); } - return (DoubleShuffleMax) v.toShuffle(vspecies(), false); + return (DoubleShuffleMax) v.toShuffle(VSPECIES, false); } private static long[] prepare(int[] indices, int offset) { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float16Consts.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float16Consts.java index 48c4d2199b1..b70b11b0a49 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float16Consts.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float16Consts.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,7 @@ import static jdk.incubator.vector.Float16.SIZE; * {@code Float16} type. */ -class Float16Consts { +final class Float16Consts { /** * Don't let anyone instantiate this class. */ 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 5862a295fa3..cdf2532e4d9 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 @@ -49,7 +49,8 @@ import static jdk.incubator.vector.VectorOperators.*; * {@code float} values. */ @SuppressWarnings("cast") // warning: redundant cast -public abstract class FloatVector extends AbstractVector { +public abstract sealed class FloatVector extends AbstractVector + permits FloatVector64, FloatVector128, FloatVector256, FloatVector512, FloatVectorMax { FloatVector(float[] vec) { super(vec); diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector128.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector128.java index 17c1fdba4fc..24888e966da 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector128.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector128.java @@ -25,7 +25,6 @@ package jdk.incubator.vector; import java.lang.foreign.MemorySegment; -import java.lang.foreign.ValueLayout; import java.nio.ByteOrder; import java.util.Arrays; import java.util.Objects; @@ -35,9 +34,8 @@ import jdk.internal.ValueBased; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.vector.VectorSupport; -import static jdk.internal.vm.vector.VectorSupport.*; - import static jdk.incubator.vector.VectorOperators.*; +import static jdk.internal.vm.vector.VectorSupport.*; // -- This file was mechanically generated: Do not edit! -- // @@ -360,7 +358,7 @@ final class FloatVector128 extends FloatVector { @Override @ForceInline public final FloatShuffle128 toShuffle() { - return (FloatShuffle128) toShuffle(vspecies(), false); + return (FloatShuffle128) toShuffle(VSPECIES, false); } // Specialized unary testing @@ -613,7 +611,7 @@ final class FloatVector128 extends FloatVector { @Override FloatMask128 uOp(MUnOp f) { - boolean[] res = new boolean[vspecies().laneCount()]; + boolean[] res = new boolean[VSPECIES.laneCount()]; boolean[] bits = getBits(); for (int i = 0; i < res.length; i++) { res[i] = f.apply(i, bits[i]); @@ -623,7 +621,7 @@ final class FloatVector128 extends FloatVector { @Override FloatMask128 bOp(VectorMask m, MBinOp f) { - boolean[] res = new boolean[vspecies().laneCount()]; + boolean[] res = new boolean[VSPECIES.laneCount()]; boolean[] bits = getBits(); boolean[] mbits = ((FloatMask128)m).getBits(); for (int i = 0; i < res.length; i++) { @@ -773,16 +771,16 @@ final class FloatVector128 extends FloatVector { @ForceInline public boolean anyTrue() { return VectorSupport.test(BT_ne, FloatMask128.class, LANEBITS_TYPE_ORDINAL, VLENGTH, - this, vspecies().maskAll(true), - (m, __) -> anyTrueHelper(((FloatMask128)m).getBits())); + this, VSPECIES.maskAll(true), + (m, _) -> anyTrueHelper(((FloatMask128)m).getBits())); } @Override @ForceInline public boolean allTrue() { return VectorSupport.test(BT_overflow, FloatMask128.class, LANEBITS_TYPE_ORDINAL, VLENGTH, - this, vspecies().maskAll(true), - (m, __) -> allTrueHelper(((FloatMask128)m).getBits())); + this, VSPECIES.maskAll(true), + (m, _) -> allTrueHelper(((FloatMask128)m).getBits())); } @ForceInline @@ -790,7 +788,7 @@ final class FloatVector128 extends FloatVector { static FloatMask128 maskAll(boolean bit) { return VectorSupport.fromBitsCoerced(FloatMask128.class, LANEBITS_TYPE_ORDINAL, VLENGTH, (bit ? -1 : 0), MODE_BROADCAST, null, - (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); + (v, _) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); } private static final FloatMask128 TRUE_MASK = new FloatMask128(true); private static final FloatMask128 FALSE_MASK = new FloatMask128(false); @@ -839,7 +837,7 @@ final class FloatVector128 extends FloatVector { @Override @ForceInline public FloatVector128 toVector() { - return (FloatVector128) toBitsVector().castShape(vspecies(), 0); + return (FloatVector128) toBitsVector().castShape(VSPECIES, 0); } @Override @@ -850,7 +848,7 @@ final class FloatVector128 extends FloatVector { @Override IntVector128 toBitsVector0() { - return ((IntVector128) vspecies().asIntegral().dummyVector()).vectorFactory(indices()); + return ((IntVector128) VSPECIES.asIntegral().dummyVector()).vectorFactory(indices()); } @Override @@ -875,7 +873,7 @@ final class FloatVector128 extends FloatVector { @ForceInline public final FloatMask128 laneIsValid() { return (FloatMask128) toBitsVector().compare(VectorOperators.GE, 0) - .cast(vspecies()); + .cast(VSPECIES); } @ForceInline @@ -883,7 +881,7 @@ final class FloatVector128 extends FloatVector { public final FloatShuffle128 rearrange(VectorShuffle shuffle) { FloatShuffle128 concreteShuffle = (FloatShuffle128) shuffle; return (FloatShuffle128) toBitsVector().rearrange(concreteShuffle.cast(IntVector.SPECIES_128)) - .toShuffle(vspecies(), false); + .toShuffle(VSPECIES, false); } @ForceInline @@ -896,7 +894,7 @@ final class FloatVector128 extends FloatVector { v = (IntVector128) v.blend(v.lanewise(VectorOperators.ADD, length()), v.compare(VectorOperators.LT, 0)); } - return (FloatShuffle128) v.toShuffle(vspecies(), false); + return (FloatShuffle128) v.toShuffle(VSPECIES, false); } private static int[] prepare(int[] indices, int offset) { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector256.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector256.java index 7badb71415e..ecbd80046f4 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector256.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector256.java @@ -25,7 +25,6 @@ package jdk.incubator.vector; import java.lang.foreign.MemorySegment; -import java.lang.foreign.ValueLayout; import java.nio.ByteOrder; import java.util.Arrays; import java.util.Objects; @@ -35,9 +34,8 @@ import jdk.internal.ValueBased; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.vector.VectorSupport; -import static jdk.internal.vm.vector.VectorSupport.*; - import static jdk.incubator.vector.VectorOperators.*; +import static jdk.internal.vm.vector.VectorSupport.*; // -- This file was mechanically generated: Do not edit! -- // @@ -360,7 +358,7 @@ final class FloatVector256 extends FloatVector { @Override @ForceInline public final FloatShuffle256 toShuffle() { - return (FloatShuffle256) toShuffle(vspecies(), false); + return (FloatShuffle256) toShuffle(VSPECIES, false); } // Specialized unary testing @@ -621,7 +619,7 @@ final class FloatVector256 extends FloatVector { @Override FloatMask256 uOp(MUnOp f) { - boolean[] res = new boolean[vspecies().laneCount()]; + boolean[] res = new boolean[VSPECIES.laneCount()]; boolean[] bits = getBits(); for (int i = 0; i < res.length; i++) { res[i] = f.apply(i, bits[i]); @@ -631,7 +629,7 @@ final class FloatVector256 extends FloatVector { @Override FloatMask256 bOp(VectorMask m, MBinOp f) { - boolean[] res = new boolean[vspecies().laneCount()]; + boolean[] res = new boolean[VSPECIES.laneCount()]; boolean[] bits = getBits(); boolean[] mbits = ((FloatMask256)m).getBits(); for (int i = 0; i < res.length; i++) { @@ -781,16 +779,16 @@ final class FloatVector256 extends FloatVector { @ForceInline public boolean anyTrue() { return VectorSupport.test(BT_ne, FloatMask256.class, LANEBITS_TYPE_ORDINAL, VLENGTH, - this, vspecies().maskAll(true), - (m, __) -> anyTrueHelper(((FloatMask256)m).getBits())); + this, VSPECIES.maskAll(true), + (m, _) -> anyTrueHelper(((FloatMask256)m).getBits())); } @Override @ForceInline public boolean allTrue() { return VectorSupport.test(BT_overflow, FloatMask256.class, LANEBITS_TYPE_ORDINAL, VLENGTH, - this, vspecies().maskAll(true), - (m, __) -> allTrueHelper(((FloatMask256)m).getBits())); + this, VSPECIES.maskAll(true), + (m, _) -> allTrueHelper(((FloatMask256)m).getBits())); } @ForceInline @@ -798,7 +796,7 @@ final class FloatVector256 extends FloatVector { static FloatMask256 maskAll(boolean bit) { return VectorSupport.fromBitsCoerced(FloatMask256.class, LANEBITS_TYPE_ORDINAL, VLENGTH, (bit ? -1 : 0), MODE_BROADCAST, null, - (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); + (v, _) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); } private static final FloatMask256 TRUE_MASK = new FloatMask256(true); private static final FloatMask256 FALSE_MASK = new FloatMask256(false); @@ -847,7 +845,7 @@ final class FloatVector256 extends FloatVector { @Override @ForceInline public FloatVector256 toVector() { - return (FloatVector256) toBitsVector().castShape(vspecies(), 0); + return (FloatVector256) toBitsVector().castShape(VSPECIES, 0); } @Override @@ -858,7 +856,7 @@ final class FloatVector256 extends FloatVector { @Override IntVector256 toBitsVector0() { - return ((IntVector256) vspecies().asIntegral().dummyVector()).vectorFactory(indices()); + return ((IntVector256) VSPECIES.asIntegral().dummyVector()).vectorFactory(indices()); } @Override @@ -883,7 +881,7 @@ final class FloatVector256 extends FloatVector { @ForceInline public final FloatMask256 laneIsValid() { return (FloatMask256) toBitsVector().compare(VectorOperators.GE, 0) - .cast(vspecies()); + .cast(VSPECIES); } @ForceInline @@ -891,7 +889,7 @@ final class FloatVector256 extends FloatVector { public final FloatShuffle256 rearrange(VectorShuffle shuffle) { FloatShuffle256 concreteShuffle = (FloatShuffle256) shuffle; return (FloatShuffle256) toBitsVector().rearrange(concreteShuffle.cast(IntVector.SPECIES_256)) - .toShuffle(vspecies(), false); + .toShuffle(VSPECIES, false); } @ForceInline @@ -904,7 +902,7 @@ final class FloatVector256 extends FloatVector { v = (IntVector256) v.blend(v.lanewise(VectorOperators.ADD, length()), v.compare(VectorOperators.LT, 0)); } - return (FloatShuffle256) v.toShuffle(vspecies(), false); + return (FloatShuffle256) v.toShuffle(VSPECIES, false); } private static int[] prepare(int[] indices, int offset) { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector512.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector512.java index 7c0786b7fcd..b5a934dd90c 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector512.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector512.java @@ -25,7 +25,6 @@ package jdk.incubator.vector; import java.lang.foreign.MemorySegment; -import java.lang.foreign.ValueLayout; import java.nio.ByteOrder; import java.util.Arrays; import java.util.Objects; @@ -35,9 +34,8 @@ import jdk.internal.ValueBased; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.vector.VectorSupport; -import static jdk.internal.vm.vector.VectorSupport.*; - import static jdk.incubator.vector.VectorOperators.*; +import static jdk.internal.vm.vector.VectorSupport.*; // -- This file was mechanically generated: Do not edit! -- // @@ -360,7 +358,7 @@ final class FloatVector512 extends FloatVector { @Override @ForceInline public final FloatShuffle512 toShuffle() { - return (FloatShuffle512) toShuffle(vspecies(), false); + return (FloatShuffle512) toShuffle(VSPECIES, false); } // Specialized unary testing @@ -637,7 +635,7 @@ final class FloatVector512 extends FloatVector { @Override FloatMask512 uOp(MUnOp f) { - boolean[] res = new boolean[vspecies().laneCount()]; + boolean[] res = new boolean[VSPECIES.laneCount()]; boolean[] bits = getBits(); for (int i = 0; i < res.length; i++) { res[i] = f.apply(i, bits[i]); @@ -647,7 +645,7 @@ final class FloatVector512 extends FloatVector { @Override FloatMask512 bOp(VectorMask m, MBinOp f) { - boolean[] res = new boolean[vspecies().laneCount()]; + boolean[] res = new boolean[VSPECIES.laneCount()]; boolean[] bits = getBits(); boolean[] mbits = ((FloatMask512)m).getBits(); for (int i = 0; i < res.length; i++) { @@ -797,16 +795,16 @@ final class FloatVector512 extends FloatVector { @ForceInline public boolean anyTrue() { return VectorSupport.test(BT_ne, FloatMask512.class, LANEBITS_TYPE_ORDINAL, VLENGTH, - this, vspecies().maskAll(true), - (m, __) -> anyTrueHelper(((FloatMask512)m).getBits())); + this, VSPECIES.maskAll(true), + (m, _) -> anyTrueHelper(((FloatMask512)m).getBits())); } @Override @ForceInline public boolean allTrue() { return VectorSupport.test(BT_overflow, FloatMask512.class, LANEBITS_TYPE_ORDINAL, VLENGTH, - this, vspecies().maskAll(true), - (m, __) -> allTrueHelper(((FloatMask512)m).getBits())); + this, VSPECIES.maskAll(true), + (m, _) -> allTrueHelper(((FloatMask512)m).getBits())); } @ForceInline @@ -814,7 +812,7 @@ final class FloatVector512 extends FloatVector { static FloatMask512 maskAll(boolean bit) { return VectorSupport.fromBitsCoerced(FloatMask512.class, LANEBITS_TYPE_ORDINAL, VLENGTH, (bit ? -1 : 0), MODE_BROADCAST, null, - (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); + (v, _) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); } private static final FloatMask512 TRUE_MASK = new FloatMask512(true); private static final FloatMask512 FALSE_MASK = new FloatMask512(false); @@ -863,7 +861,7 @@ final class FloatVector512 extends FloatVector { @Override @ForceInline public FloatVector512 toVector() { - return (FloatVector512) toBitsVector().castShape(vspecies(), 0); + return (FloatVector512) toBitsVector().castShape(VSPECIES, 0); } @Override @@ -874,7 +872,7 @@ final class FloatVector512 extends FloatVector { @Override IntVector512 toBitsVector0() { - return ((IntVector512) vspecies().asIntegral().dummyVector()).vectorFactory(indices()); + return ((IntVector512) VSPECIES.asIntegral().dummyVector()).vectorFactory(indices()); } @Override @@ -899,7 +897,7 @@ final class FloatVector512 extends FloatVector { @ForceInline public final FloatMask512 laneIsValid() { return (FloatMask512) toBitsVector().compare(VectorOperators.GE, 0) - .cast(vspecies()); + .cast(VSPECIES); } @ForceInline @@ -907,7 +905,7 @@ final class FloatVector512 extends FloatVector { public final FloatShuffle512 rearrange(VectorShuffle shuffle) { FloatShuffle512 concreteShuffle = (FloatShuffle512) shuffle; return (FloatShuffle512) toBitsVector().rearrange(concreteShuffle.cast(IntVector.SPECIES_512)) - .toShuffle(vspecies(), false); + .toShuffle(VSPECIES, false); } @ForceInline @@ -920,7 +918,7 @@ final class FloatVector512 extends FloatVector { v = (IntVector512) v.blend(v.lanewise(VectorOperators.ADD, length()), v.compare(VectorOperators.LT, 0)); } - return (FloatShuffle512) v.toShuffle(vspecies(), false); + return (FloatShuffle512) v.toShuffle(VSPECIES, false); } private static int[] prepare(int[] indices, int offset) { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector64.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector64.java index fc4877e5ae8..4d3118739ea 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector64.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector64.java @@ -25,7 +25,6 @@ package jdk.incubator.vector; import java.lang.foreign.MemorySegment; -import java.lang.foreign.ValueLayout; import java.nio.ByteOrder; import java.util.Arrays; import java.util.Objects; @@ -35,9 +34,8 @@ import jdk.internal.ValueBased; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.vector.VectorSupport; -import static jdk.internal.vm.vector.VectorSupport.*; - import static jdk.incubator.vector.VectorOperators.*; +import static jdk.internal.vm.vector.VectorSupport.*; // -- This file was mechanically generated: Do not edit! -- // @@ -360,7 +358,7 @@ final class FloatVector64 extends FloatVector { @Override @ForceInline public final FloatShuffle64 toShuffle() { - return (FloatShuffle64) toShuffle(vspecies(), false); + return (FloatShuffle64) toShuffle(VSPECIES, false); } // Specialized unary testing @@ -609,7 +607,7 @@ final class FloatVector64 extends FloatVector { @Override FloatMask64 uOp(MUnOp f) { - boolean[] res = new boolean[vspecies().laneCount()]; + boolean[] res = new boolean[VSPECIES.laneCount()]; boolean[] bits = getBits(); for (int i = 0; i < res.length; i++) { res[i] = f.apply(i, bits[i]); @@ -619,7 +617,7 @@ final class FloatVector64 extends FloatVector { @Override FloatMask64 bOp(VectorMask m, MBinOp f) { - boolean[] res = new boolean[vspecies().laneCount()]; + boolean[] res = new boolean[VSPECIES.laneCount()]; boolean[] bits = getBits(); boolean[] mbits = ((FloatMask64)m).getBits(); for (int i = 0; i < res.length; i++) { @@ -769,16 +767,16 @@ final class FloatVector64 extends FloatVector { @ForceInline public boolean anyTrue() { return VectorSupport.test(BT_ne, FloatMask64.class, LANEBITS_TYPE_ORDINAL, VLENGTH, - this, vspecies().maskAll(true), - (m, __) -> anyTrueHelper(((FloatMask64)m).getBits())); + this, VSPECIES.maskAll(true), + (m, _) -> anyTrueHelper(((FloatMask64)m).getBits())); } @Override @ForceInline public boolean allTrue() { return VectorSupport.test(BT_overflow, FloatMask64.class, LANEBITS_TYPE_ORDINAL, VLENGTH, - this, vspecies().maskAll(true), - (m, __) -> allTrueHelper(((FloatMask64)m).getBits())); + this, VSPECIES.maskAll(true), + (m, _) -> allTrueHelper(((FloatMask64)m).getBits())); } @ForceInline @@ -786,7 +784,7 @@ final class FloatVector64 extends FloatVector { static FloatMask64 maskAll(boolean bit) { return VectorSupport.fromBitsCoerced(FloatMask64.class, LANEBITS_TYPE_ORDINAL, VLENGTH, (bit ? -1 : 0), MODE_BROADCAST, null, - (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); + (v, _) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); } private static final FloatMask64 TRUE_MASK = new FloatMask64(true); private static final FloatMask64 FALSE_MASK = new FloatMask64(false); @@ -835,7 +833,7 @@ final class FloatVector64 extends FloatVector { @Override @ForceInline public FloatVector64 toVector() { - return (FloatVector64) toBitsVector().castShape(vspecies(), 0); + return (FloatVector64) toBitsVector().castShape(VSPECIES, 0); } @Override @@ -846,7 +844,7 @@ final class FloatVector64 extends FloatVector { @Override IntVector64 toBitsVector0() { - return ((IntVector64) vspecies().asIntegral().dummyVector()).vectorFactory(indices()); + return ((IntVector64) VSPECIES.asIntegral().dummyVector()).vectorFactory(indices()); } @Override @@ -871,7 +869,7 @@ final class FloatVector64 extends FloatVector { @ForceInline public final FloatMask64 laneIsValid() { return (FloatMask64) toBitsVector().compare(VectorOperators.GE, 0) - .cast(vspecies()); + .cast(VSPECIES); } @ForceInline @@ -879,7 +877,7 @@ final class FloatVector64 extends FloatVector { public final FloatShuffle64 rearrange(VectorShuffle shuffle) { FloatShuffle64 concreteShuffle = (FloatShuffle64) shuffle; return (FloatShuffle64) toBitsVector().rearrange(concreteShuffle.cast(IntVector.SPECIES_64)) - .toShuffle(vspecies(), false); + .toShuffle(VSPECIES, false); } @ForceInline @@ -892,7 +890,7 @@ final class FloatVector64 extends FloatVector { v = (IntVector64) v.blend(v.lanewise(VectorOperators.ADD, length()), v.compare(VectorOperators.LT, 0)); } - return (FloatShuffle64) v.toShuffle(vspecies(), false); + return (FloatShuffle64) v.toShuffle(VSPECIES, false); } private static int[] prepare(int[] indices, int offset) { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVectorMax.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVectorMax.java index 5cfafecdb58..f115a1c79b8 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVectorMax.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVectorMax.java @@ -25,7 +25,6 @@ package jdk.incubator.vector; import java.lang.foreign.MemorySegment; -import java.lang.foreign.ValueLayout; import java.nio.ByteOrder; import java.util.Arrays; import java.util.Objects; @@ -35,9 +34,8 @@ import jdk.internal.ValueBased; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.vector.VectorSupport; -import static jdk.internal.vm.vector.VectorSupport.*; - import static jdk.incubator.vector.VectorOperators.*; +import static jdk.internal.vm.vector.VectorSupport.*; // -- This file was mechanically generated: Do not edit! -- // @@ -360,7 +358,7 @@ final class FloatVectorMax extends FloatVector { @Override @ForceInline public final FloatShuffleMax toShuffle() { - return (FloatShuffleMax) toShuffle(vspecies(), false); + return (FloatShuffleMax) toShuffle(VSPECIES, false); } // Specialized unary testing @@ -606,7 +604,7 @@ final class FloatVectorMax extends FloatVector { @Override FloatMaskMax uOp(MUnOp f) { - boolean[] res = new boolean[vspecies().laneCount()]; + boolean[] res = new boolean[VSPECIES.laneCount()]; boolean[] bits = getBits(); for (int i = 0; i < res.length; i++) { res[i] = f.apply(i, bits[i]); @@ -616,7 +614,7 @@ final class FloatVectorMax extends FloatVector { @Override FloatMaskMax bOp(VectorMask m, MBinOp f) { - boolean[] res = new boolean[vspecies().laneCount()]; + boolean[] res = new boolean[VSPECIES.laneCount()]; boolean[] bits = getBits(); boolean[] mbits = ((FloatMaskMax)m).getBits(); for (int i = 0; i < res.length; i++) { @@ -766,16 +764,16 @@ final class FloatVectorMax extends FloatVector { @ForceInline public boolean anyTrue() { return VectorSupport.test(BT_ne, FloatMaskMax.class, LANEBITS_TYPE_ORDINAL, VLENGTH, - this, vspecies().maskAll(true), - (m, __) -> anyTrueHelper(((FloatMaskMax)m).getBits())); + this, VSPECIES.maskAll(true), + (m, _) -> anyTrueHelper(((FloatMaskMax)m).getBits())); } @Override @ForceInline public boolean allTrue() { return VectorSupport.test(BT_overflow, FloatMaskMax.class, LANEBITS_TYPE_ORDINAL, VLENGTH, - this, vspecies().maskAll(true), - (m, __) -> allTrueHelper(((FloatMaskMax)m).getBits())); + this, VSPECIES.maskAll(true), + (m, _) -> allTrueHelper(((FloatMaskMax)m).getBits())); } @ForceInline @@ -783,7 +781,7 @@ final class FloatVectorMax extends FloatVector { static FloatMaskMax maskAll(boolean bit) { return VectorSupport.fromBitsCoerced(FloatMaskMax.class, LANEBITS_TYPE_ORDINAL, VLENGTH, (bit ? -1 : 0), MODE_BROADCAST, null, - (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); + (v, _) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); } private static final FloatMaskMax TRUE_MASK = new FloatMaskMax(true); private static final FloatMaskMax FALSE_MASK = new FloatMaskMax(false); @@ -832,7 +830,7 @@ final class FloatVectorMax extends FloatVector { @Override @ForceInline public FloatVectorMax toVector() { - return (FloatVectorMax) toBitsVector().castShape(vspecies(), 0); + return (FloatVectorMax) toBitsVector().castShape(VSPECIES, 0); } @Override @@ -843,7 +841,7 @@ final class FloatVectorMax extends FloatVector { @Override IntVectorMax toBitsVector0() { - return ((IntVectorMax) vspecies().asIntegral().dummyVector()).vectorFactory(indices()); + return ((IntVectorMax) VSPECIES.asIntegral().dummyVector()).vectorFactory(indices()); } @Override @@ -868,7 +866,7 @@ final class FloatVectorMax extends FloatVector { @ForceInline public final FloatMaskMax laneIsValid() { return (FloatMaskMax) toBitsVector().compare(VectorOperators.GE, 0) - .cast(vspecies()); + .cast(VSPECIES); } @ForceInline @@ -876,7 +874,7 @@ final class FloatVectorMax extends FloatVector { public final FloatShuffleMax rearrange(VectorShuffle shuffle) { FloatShuffleMax concreteShuffle = (FloatShuffleMax) shuffle; return (FloatShuffleMax) toBitsVector().rearrange(concreteShuffle.cast(IntVector.SPECIES_MAX)) - .toShuffle(vspecies(), false); + .toShuffle(VSPECIES, false); } @ForceInline @@ -889,7 +887,7 @@ final class FloatVectorMax extends FloatVector { v = (IntVectorMax) v.blend(v.lanewise(VectorOperators.ADD, length()), v.compare(VectorOperators.LT, 0)); } - return (FloatShuffleMax) v.toShuffle(vspecies(), false); + return (FloatShuffleMax) v.toShuffle(VSPECIES, false); } private static int[] prepare(int[] indices, int offset) { 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 445c4dfb006..37b7e3eeae4 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 @@ -49,7 +49,8 @@ import static jdk.incubator.vector.VectorOperators.*; * {@code int} values. */ @SuppressWarnings("cast") // warning: redundant cast -public abstract class IntVector extends AbstractVector { +public abstract sealed class IntVector extends AbstractVector + permits IntVector64, IntVector128, IntVector256, IntVector512, IntVectorMax { IntVector(int[] vec) { super(vec); diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector128.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector128.java index 04b10386127..f64328e2a1e 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector128.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector128.java @@ -25,7 +25,6 @@ package jdk.incubator.vector; import java.lang.foreign.MemorySegment; -import java.lang.foreign.ValueLayout; import java.nio.ByteOrder; import java.util.Arrays; import java.util.Objects; @@ -35,9 +34,8 @@ import jdk.internal.ValueBased; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.vector.VectorSupport; -import static jdk.internal.vm.vector.VectorSupport.*; - import static jdk.incubator.vector.VectorOperators.*; +import static jdk.internal.vm.vector.VectorSupport.*; // -- This file was mechanically generated: Do not edit! -- // @@ -373,7 +371,7 @@ final class IntVector128 extends IntVector { @Override @ForceInline public final IntShuffle128 toShuffle() { - return (IntShuffle128) toShuffle(vspecies(), false); + return (IntShuffle128) toShuffle(VSPECIES, false); } // Specialized unary testing @@ -624,7 +622,7 @@ final class IntVector128 extends IntVector { @Override IntMask128 uOp(MUnOp f) { - boolean[] res = new boolean[vspecies().laneCount()]; + boolean[] res = new boolean[VSPECIES.laneCount()]; boolean[] bits = getBits(); for (int i = 0; i < res.length; i++) { res[i] = f.apply(i, bits[i]); @@ -634,7 +632,7 @@ final class IntVector128 extends IntVector { @Override IntMask128 bOp(VectorMask m, MBinOp f) { - boolean[] res = new boolean[vspecies().laneCount()]; + boolean[] res = new boolean[VSPECIES.laneCount()]; boolean[] bits = getBits(); boolean[] mbits = ((IntMask128)m).getBits(); for (int i = 0; i < res.length; i++) { @@ -784,16 +782,16 @@ final class IntVector128 extends IntVector { @ForceInline public boolean anyTrue() { return VectorSupport.test(BT_ne, IntMask128.class, LANEBITS_TYPE_ORDINAL, VLENGTH, - this, vspecies().maskAll(true), - (m, __) -> anyTrueHelper(((IntMask128)m).getBits())); + this, VSPECIES.maskAll(true), + (m, _) -> anyTrueHelper(((IntMask128)m).getBits())); } @Override @ForceInline public boolean allTrue() { return VectorSupport.test(BT_overflow, IntMask128.class, LANEBITS_TYPE_ORDINAL, VLENGTH, - this, vspecies().maskAll(true), - (m, __) -> allTrueHelper(((IntMask128)m).getBits())); + this, VSPECIES.maskAll(true), + (m, _) -> allTrueHelper(((IntMask128)m).getBits())); } @ForceInline @@ -801,7 +799,7 @@ final class IntVector128 extends IntVector { static IntMask128 maskAll(boolean bit) { return VectorSupport.fromBitsCoerced(IntMask128.class, LANEBITS_TYPE_ORDINAL, VLENGTH, (bit ? -1 : 0), MODE_BROADCAST, null, - (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); + (v, _) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); } private static final IntMask128 TRUE_MASK = new IntMask128(true); private static final IntMask128 FALSE_MASK = new IntMask128(false); @@ -861,7 +859,7 @@ final class IntVector128 extends IntVector { @Override IntVector128 toBitsVector0() { - return ((IntVector128) vspecies().asIntegral().dummyVector()).vectorFactory(indices()); + return ((IntVector128) VSPECIES.asIntegral().dummyVector()).vectorFactory(indices()); } @Override @@ -886,7 +884,7 @@ final class IntVector128 extends IntVector { @ForceInline public final IntMask128 laneIsValid() { return (IntMask128) toBitsVector().compare(VectorOperators.GE, 0) - .cast(vspecies()); + .cast(VSPECIES); } @ForceInline @@ -894,7 +892,7 @@ final class IntVector128 extends IntVector { public final IntShuffle128 rearrange(VectorShuffle shuffle) { IntShuffle128 concreteShuffle = (IntShuffle128) shuffle; return (IntShuffle128) toBitsVector().rearrange(concreteShuffle) - .toShuffle(vspecies(), false); + .toShuffle(VSPECIES, false); } @ForceInline @@ -907,7 +905,7 @@ final class IntVector128 extends IntVector { v = (IntVector128) v.blend(v.lanewise(VectorOperators.ADD, length()), v.compare(VectorOperators.LT, 0)); } - return (IntShuffle128) v.toShuffle(vspecies(), false); + return (IntShuffle128) v.toShuffle(VSPECIES, false); } private static int[] prepare(int[] indices, int offset) { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector256.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector256.java index 20d9df1cd60..58a1667d2ac 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector256.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector256.java @@ -25,7 +25,6 @@ package jdk.incubator.vector; import java.lang.foreign.MemorySegment; -import java.lang.foreign.ValueLayout; import java.nio.ByteOrder; import java.util.Arrays; import java.util.Objects; @@ -35,9 +34,8 @@ import jdk.internal.ValueBased; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.vector.VectorSupport; -import static jdk.internal.vm.vector.VectorSupport.*; - import static jdk.incubator.vector.VectorOperators.*; +import static jdk.internal.vm.vector.VectorSupport.*; // -- This file was mechanically generated: Do not edit! -- // @@ -373,7 +371,7 @@ final class IntVector256 extends IntVector { @Override @ForceInline public final IntShuffle256 toShuffle() { - return (IntShuffle256) toShuffle(vspecies(), false); + return (IntShuffle256) toShuffle(VSPECIES, false); } // Specialized unary testing @@ -632,7 +630,7 @@ final class IntVector256 extends IntVector { @Override IntMask256 uOp(MUnOp f) { - boolean[] res = new boolean[vspecies().laneCount()]; + boolean[] res = new boolean[VSPECIES.laneCount()]; boolean[] bits = getBits(); for (int i = 0; i < res.length; i++) { res[i] = f.apply(i, bits[i]); @@ -642,7 +640,7 @@ final class IntVector256 extends IntVector { @Override IntMask256 bOp(VectorMask m, MBinOp f) { - boolean[] res = new boolean[vspecies().laneCount()]; + boolean[] res = new boolean[VSPECIES.laneCount()]; boolean[] bits = getBits(); boolean[] mbits = ((IntMask256)m).getBits(); for (int i = 0; i < res.length; i++) { @@ -792,16 +790,16 @@ final class IntVector256 extends IntVector { @ForceInline public boolean anyTrue() { return VectorSupport.test(BT_ne, IntMask256.class, LANEBITS_TYPE_ORDINAL, VLENGTH, - this, vspecies().maskAll(true), - (m, __) -> anyTrueHelper(((IntMask256)m).getBits())); + this, VSPECIES.maskAll(true), + (m, _) -> anyTrueHelper(((IntMask256)m).getBits())); } @Override @ForceInline public boolean allTrue() { return VectorSupport.test(BT_overflow, IntMask256.class, LANEBITS_TYPE_ORDINAL, VLENGTH, - this, vspecies().maskAll(true), - (m, __) -> allTrueHelper(((IntMask256)m).getBits())); + this, VSPECIES.maskAll(true), + (m, _) -> allTrueHelper(((IntMask256)m).getBits())); } @ForceInline @@ -809,7 +807,7 @@ final class IntVector256 extends IntVector { static IntMask256 maskAll(boolean bit) { return VectorSupport.fromBitsCoerced(IntMask256.class, LANEBITS_TYPE_ORDINAL, VLENGTH, (bit ? -1 : 0), MODE_BROADCAST, null, - (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); + (v, _) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); } private static final IntMask256 TRUE_MASK = new IntMask256(true); private static final IntMask256 FALSE_MASK = new IntMask256(false); @@ -869,7 +867,7 @@ final class IntVector256 extends IntVector { @Override IntVector256 toBitsVector0() { - return ((IntVector256) vspecies().asIntegral().dummyVector()).vectorFactory(indices()); + return ((IntVector256) VSPECIES.asIntegral().dummyVector()).vectorFactory(indices()); } @Override @@ -894,7 +892,7 @@ final class IntVector256 extends IntVector { @ForceInline public final IntMask256 laneIsValid() { return (IntMask256) toBitsVector().compare(VectorOperators.GE, 0) - .cast(vspecies()); + .cast(VSPECIES); } @ForceInline @@ -902,7 +900,7 @@ final class IntVector256 extends IntVector { public final IntShuffle256 rearrange(VectorShuffle shuffle) { IntShuffle256 concreteShuffle = (IntShuffle256) shuffle; return (IntShuffle256) toBitsVector().rearrange(concreteShuffle) - .toShuffle(vspecies(), false); + .toShuffle(VSPECIES, false); } @ForceInline @@ -915,7 +913,7 @@ final class IntVector256 extends IntVector { v = (IntVector256) v.blend(v.lanewise(VectorOperators.ADD, length()), v.compare(VectorOperators.LT, 0)); } - return (IntShuffle256) v.toShuffle(vspecies(), false); + return (IntShuffle256) v.toShuffle(VSPECIES, false); } private static int[] prepare(int[] indices, int offset) { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector512.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector512.java index 4f3a16e2777..ac48e589a05 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector512.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector512.java @@ -25,7 +25,6 @@ package jdk.incubator.vector; import java.lang.foreign.MemorySegment; -import java.lang.foreign.ValueLayout; import java.nio.ByteOrder; import java.util.Arrays; import java.util.Objects; @@ -35,9 +34,8 @@ import jdk.internal.ValueBased; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.vector.VectorSupport; -import static jdk.internal.vm.vector.VectorSupport.*; - import static jdk.incubator.vector.VectorOperators.*; +import static jdk.internal.vm.vector.VectorSupport.*; // -- This file was mechanically generated: Do not edit! -- // @@ -373,7 +371,7 @@ final class IntVector512 extends IntVector { @Override @ForceInline public final IntShuffle512 toShuffle() { - return (IntShuffle512) toShuffle(vspecies(), false); + return (IntShuffle512) toShuffle(VSPECIES, false); } // Specialized unary testing @@ -648,7 +646,7 @@ final class IntVector512 extends IntVector { @Override IntMask512 uOp(MUnOp f) { - boolean[] res = new boolean[vspecies().laneCount()]; + boolean[] res = new boolean[VSPECIES.laneCount()]; boolean[] bits = getBits(); for (int i = 0; i < res.length; i++) { res[i] = f.apply(i, bits[i]); @@ -658,7 +656,7 @@ final class IntVector512 extends IntVector { @Override IntMask512 bOp(VectorMask m, MBinOp f) { - boolean[] res = new boolean[vspecies().laneCount()]; + boolean[] res = new boolean[VSPECIES.laneCount()]; boolean[] bits = getBits(); boolean[] mbits = ((IntMask512)m).getBits(); for (int i = 0; i < res.length; i++) { @@ -808,16 +806,16 @@ final class IntVector512 extends IntVector { @ForceInline public boolean anyTrue() { return VectorSupport.test(BT_ne, IntMask512.class, LANEBITS_TYPE_ORDINAL, VLENGTH, - this, vspecies().maskAll(true), - (m, __) -> anyTrueHelper(((IntMask512)m).getBits())); + this, VSPECIES.maskAll(true), + (m, _) -> anyTrueHelper(((IntMask512)m).getBits())); } @Override @ForceInline public boolean allTrue() { return VectorSupport.test(BT_overflow, IntMask512.class, LANEBITS_TYPE_ORDINAL, VLENGTH, - this, vspecies().maskAll(true), - (m, __) -> allTrueHelper(((IntMask512)m).getBits())); + this, VSPECIES.maskAll(true), + (m, _) -> allTrueHelper(((IntMask512)m).getBits())); } @ForceInline @@ -825,7 +823,7 @@ final class IntVector512 extends IntVector { static IntMask512 maskAll(boolean bit) { return VectorSupport.fromBitsCoerced(IntMask512.class, LANEBITS_TYPE_ORDINAL, VLENGTH, (bit ? -1 : 0), MODE_BROADCAST, null, - (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); + (v, _) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); } private static final IntMask512 TRUE_MASK = new IntMask512(true); private static final IntMask512 FALSE_MASK = new IntMask512(false); @@ -885,7 +883,7 @@ final class IntVector512 extends IntVector { @Override IntVector512 toBitsVector0() { - return ((IntVector512) vspecies().asIntegral().dummyVector()).vectorFactory(indices()); + return ((IntVector512) VSPECIES.asIntegral().dummyVector()).vectorFactory(indices()); } @Override @@ -910,7 +908,7 @@ final class IntVector512 extends IntVector { @ForceInline public final IntMask512 laneIsValid() { return (IntMask512) toBitsVector().compare(VectorOperators.GE, 0) - .cast(vspecies()); + .cast(VSPECIES); } @ForceInline @@ -918,7 +916,7 @@ final class IntVector512 extends IntVector { public final IntShuffle512 rearrange(VectorShuffle shuffle) { IntShuffle512 concreteShuffle = (IntShuffle512) shuffle; return (IntShuffle512) toBitsVector().rearrange(concreteShuffle) - .toShuffle(vspecies(), false); + .toShuffle(VSPECIES, false); } @ForceInline @@ -931,7 +929,7 @@ final class IntVector512 extends IntVector { v = (IntVector512) v.blend(v.lanewise(VectorOperators.ADD, length()), v.compare(VectorOperators.LT, 0)); } - return (IntShuffle512) v.toShuffle(vspecies(), false); + return (IntShuffle512) v.toShuffle(VSPECIES, false); } private static int[] prepare(int[] indices, int offset) { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector64.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector64.java index dd51669943b..25329aa81aa 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector64.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector64.java @@ -25,7 +25,6 @@ package jdk.incubator.vector; import java.lang.foreign.MemorySegment; -import java.lang.foreign.ValueLayout; import java.nio.ByteOrder; import java.util.Arrays; import java.util.Objects; @@ -35,9 +34,8 @@ import jdk.internal.ValueBased; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.vector.VectorSupport; -import static jdk.internal.vm.vector.VectorSupport.*; - import static jdk.incubator.vector.VectorOperators.*; +import static jdk.internal.vm.vector.VectorSupport.*; // -- This file was mechanically generated: Do not edit! -- // @@ -373,7 +371,7 @@ final class IntVector64 extends IntVector { @Override @ForceInline public final IntShuffle64 toShuffle() { - return (IntShuffle64) toShuffle(vspecies(), false); + return (IntShuffle64) toShuffle(VSPECIES, false); } // Specialized unary testing @@ -620,7 +618,7 @@ final class IntVector64 extends IntVector { @Override IntMask64 uOp(MUnOp f) { - boolean[] res = new boolean[vspecies().laneCount()]; + boolean[] res = new boolean[VSPECIES.laneCount()]; boolean[] bits = getBits(); for (int i = 0; i < res.length; i++) { res[i] = f.apply(i, bits[i]); @@ -630,7 +628,7 @@ final class IntVector64 extends IntVector { @Override IntMask64 bOp(VectorMask m, MBinOp f) { - boolean[] res = new boolean[vspecies().laneCount()]; + boolean[] res = new boolean[VSPECIES.laneCount()]; boolean[] bits = getBits(); boolean[] mbits = ((IntMask64)m).getBits(); for (int i = 0; i < res.length; i++) { @@ -780,16 +778,16 @@ final class IntVector64 extends IntVector { @ForceInline public boolean anyTrue() { return VectorSupport.test(BT_ne, IntMask64.class, LANEBITS_TYPE_ORDINAL, VLENGTH, - this, vspecies().maskAll(true), - (m, __) -> anyTrueHelper(((IntMask64)m).getBits())); + this, VSPECIES.maskAll(true), + (m, _) -> anyTrueHelper(((IntMask64)m).getBits())); } @Override @ForceInline public boolean allTrue() { return VectorSupport.test(BT_overflow, IntMask64.class, LANEBITS_TYPE_ORDINAL, VLENGTH, - this, vspecies().maskAll(true), - (m, __) -> allTrueHelper(((IntMask64)m).getBits())); + this, VSPECIES.maskAll(true), + (m, _) -> allTrueHelper(((IntMask64)m).getBits())); } @ForceInline @@ -797,7 +795,7 @@ final class IntVector64 extends IntVector { static IntMask64 maskAll(boolean bit) { return VectorSupport.fromBitsCoerced(IntMask64.class, LANEBITS_TYPE_ORDINAL, VLENGTH, (bit ? -1 : 0), MODE_BROADCAST, null, - (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); + (v, _) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); } private static final IntMask64 TRUE_MASK = new IntMask64(true); private static final IntMask64 FALSE_MASK = new IntMask64(false); @@ -857,7 +855,7 @@ final class IntVector64 extends IntVector { @Override IntVector64 toBitsVector0() { - return ((IntVector64) vspecies().asIntegral().dummyVector()).vectorFactory(indices()); + return ((IntVector64) VSPECIES.asIntegral().dummyVector()).vectorFactory(indices()); } @Override @@ -882,7 +880,7 @@ final class IntVector64 extends IntVector { @ForceInline public final IntMask64 laneIsValid() { return (IntMask64) toBitsVector().compare(VectorOperators.GE, 0) - .cast(vspecies()); + .cast(VSPECIES); } @ForceInline @@ -890,7 +888,7 @@ final class IntVector64 extends IntVector { public final IntShuffle64 rearrange(VectorShuffle shuffle) { IntShuffle64 concreteShuffle = (IntShuffle64) shuffle; return (IntShuffle64) toBitsVector().rearrange(concreteShuffle) - .toShuffle(vspecies(), false); + .toShuffle(VSPECIES, false); } @ForceInline @@ -903,7 +901,7 @@ final class IntVector64 extends IntVector { v = (IntVector64) v.blend(v.lanewise(VectorOperators.ADD, length()), v.compare(VectorOperators.LT, 0)); } - return (IntShuffle64) v.toShuffle(vspecies(), false); + return (IntShuffle64) v.toShuffle(VSPECIES, false); } private static int[] prepare(int[] indices, int offset) { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVectorMax.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVectorMax.java index 0b785b01aec..348fda59381 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVectorMax.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVectorMax.java @@ -25,7 +25,6 @@ package jdk.incubator.vector; import java.lang.foreign.MemorySegment; -import java.lang.foreign.ValueLayout; import java.nio.ByteOrder; import java.util.Arrays; import java.util.Objects; @@ -35,9 +34,8 @@ import jdk.internal.ValueBased; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.vector.VectorSupport; -import static jdk.internal.vm.vector.VectorSupport.*; - import static jdk.incubator.vector.VectorOperators.*; +import static jdk.internal.vm.vector.VectorSupport.*; // -- This file was mechanically generated: Do not edit! -- // @@ -373,7 +371,7 @@ final class IntVectorMax extends IntVector { @Override @ForceInline public final IntShuffleMax toShuffle() { - return (IntShuffleMax) toShuffle(vspecies(), false); + return (IntShuffleMax) toShuffle(VSPECIES, false); } // Specialized unary testing @@ -618,7 +616,7 @@ final class IntVectorMax extends IntVector { @Override IntMaskMax uOp(MUnOp f) { - boolean[] res = new boolean[vspecies().laneCount()]; + boolean[] res = new boolean[VSPECIES.laneCount()]; boolean[] bits = getBits(); for (int i = 0; i < res.length; i++) { res[i] = f.apply(i, bits[i]); @@ -628,7 +626,7 @@ final class IntVectorMax extends IntVector { @Override IntMaskMax bOp(VectorMask m, MBinOp f) { - boolean[] res = new boolean[vspecies().laneCount()]; + boolean[] res = new boolean[VSPECIES.laneCount()]; boolean[] bits = getBits(); boolean[] mbits = ((IntMaskMax)m).getBits(); for (int i = 0; i < res.length; i++) { @@ -778,16 +776,16 @@ final class IntVectorMax extends IntVector { @ForceInline public boolean anyTrue() { return VectorSupport.test(BT_ne, IntMaskMax.class, LANEBITS_TYPE_ORDINAL, VLENGTH, - this, vspecies().maskAll(true), - (m, __) -> anyTrueHelper(((IntMaskMax)m).getBits())); + this, VSPECIES.maskAll(true), + (m, _) -> anyTrueHelper(((IntMaskMax)m).getBits())); } @Override @ForceInline public boolean allTrue() { return VectorSupport.test(BT_overflow, IntMaskMax.class, LANEBITS_TYPE_ORDINAL, VLENGTH, - this, vspecies().maskAll(true), - (m, __) -> allTrueHelper(((IntMaskMax)m).getBits())); + this, VSPECIES.maskAll(true), + (m, _) -> allTrueHelper(((IntMaskMax)m).getBits())); } @ForceInline @@ -795,7 +793,7 @@ final class IntVectorMax extends IntVector { static IntMaskMax maskAll(boolean bit) { return VectorSupport.fromBitsCoerced(IntMaskMax.class, LANEBITS_TYPE_ORDINAL, VLENGTH, (bit ? -1 : 0), MODE_BROADCAST, null, - (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); + (v, _) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); } private static final IntMaskMax TRUE_MASK = new IntMaskMax(true); private static final IntMaskMax FALSE_MASK = new IntMaskMax(false); @@ -866,7 +864,7 @@ final class IntVectorMax extends IntVector { @Override IntVectorMax toBitsVector0() { - return ((IntVectorMax) vspecies().asIntegral().dummyVector()).vectorFactory(indices()); + return ((IntVectorMax) VSPECIES.asIntegral().dummyVector()).vectorFactory(indices()); } @Override @@ -891,7 +889,7 @@ final class IntVectorMax extends IntVector { @ForceInline public final IntMaskMax laneIsValid() { return (IntMaskMax) toBitsVector().compare(VectorOperators.GE, 0) - .cast(vspecies()); + .cast(VSPECIES); } @ForceInline @@ -899,7 +897,7 @@ final class IntVectorMax extends IntVector { public final IntShuffleMax rearrange(VectorShuffle shuffle) { IntShuffleMax concreteShuffle = (IntShuffleMax) shuffle; return (IntShuffleMax) toBitsVector().rearrange(concreteShuffle) - .toShuffle(vspecies(), false); + .toShuffle(VSPECIES, false); } @ForceInline @@ -912,7 +910,7 @@ final class IntVectorMax extends IntVector { v = (IntVectorMax) v.blend(v.lanewise(VectorOperators.ADD, length()), v.compare(VectorOperators.LT, 0)); } - return (IntShuffleMax) v.toShuffle(vspecies(), false); + return (IntShuffleMax) v.toShuffle(VSPECIES, false); } private static int[] prepare(int[] indices, int offset) { 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 7ba0af6c139..36300cf892b 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 @@ -49,7 +49,8 @@ import static jdk.incubator.vector.VectorOperators.*; * {@code long} values. */ @SuppressWarnings("cast") // warning: redundant cast -public abstract class LongVector extends AbstractVector { +public abstract sealed class LongVector extends AbstractVector + permits LongVector64, LongVector128, LongVector256, LongVector512, LongVectorMax { LongVector(long[] vec) { super(vec); diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector128.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector128.java index 594c82ca1fc..7ce60b2efe0 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector128.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector128.java @@ -35,9 +35,8 @@ import jdk.internal.ValueBased; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.vector.VectorSupport; -import static jdk.internal.vm.vector.VectorSupport.*; - import static jdk.incubator.vector.VectorOperators.*; +import static jdk.internal.vm.vector.VectorSupport.*; // -- This file was mechanically generated: Do not edit! -- // @@ -368,7 +367,7 @@ final class LongVector128 extends LongVector { @Override @ForceInline public final LongShuffle128 toShuffle() { - return (LongShuffle128) toShuffle(vspecies(), false); + return (LongShuffle128) toShuffle(VSPECIES, false); } // Specialized unary testing @@ -610,7 +609,7 @@ final class LongVector128 extends LongVector { @Override LongMask128 uOp(MUnOp f) { - boolean[] res = new boolean[vspecies().laneCount()]; + boolean[] res = new boolean[VSPECIES.laneCount()]; boolean[] bits = getBits(); for (int i = 0; i < res.length; i++) { res[i] = f.apply(i, bits[i]); @@ -620,7 +619,7 @@ final class LongVector128 extends LongVector { @Override LongMask128 bOp(VectorMask m, MBinOp f) { - boolean[] res = new boolean[vspecies().laneCount()]; + boolean[] res = new boolean[VSPECIES.laneCount()]; boolean[] bits = getBits(); boolean[] mbits = ((LongMask128)m).getBits(); for (int i = 0; i < res.length; i++) { @@ -770,16 +769,16 @@ final class LongVector128 extends LongVector { @ForceInline public boolean anyTrue() { return VectorSupport.test(BT_ne, LongMask128.class, LANEBITS_TYPE_ORDINAL, VLENGTH, - this, vspecies().maskAll(true), - (m, __) -> anyTrueHelper(((LongMask128)m).getBits())); + this, VSPECIES.maskAll(true), + (m, _) -> anyTrueHelper(((LongMask128)m).getBits())); } @Override @ForceInline public boolean allTrue() { return VectorSupport.test(BT_overflow, LongMask128.class, LANEBITS_TYPE_ORDINAL, VLENGTH, - this, vspecies().maskAll(true), - (m, __) -> allTrueHelper(((LongMask128)m).getBits())); + this, VSPECIES.maskAll(true), + (m, _) -> allTrueHelper(((LongMask128)m).getBits())); } @ForceInline @@ -787,7 +786,7 @@ final class LongVector128 extends LongVector { static LongMask128 maskAll(boolean bit) { return VectorSupport.fromBitsCoerced(LongMask128.class, LANEBITS_TYPE_ORDINAL, VLENGTH, (bit ? -1 : 0), MODE_BROADCAST, null, - (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); + (v, _) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); } private static final LongMask128 TRUE_MASK = new LongMask128(true); private static final LongMask128 FALSE_MASK = new LongMask128(false); @@ -847,7 +846,7 @@ final class LongVector128 extends LongVector { @Override LongVector128 toBitsVector0() { - return ((LongVector128) vspecies().asIntegral().dummyVector()).vectorFactory(indices()); + return ((LongVector128) VSPECIES.asIntegral().dummyVector()).vectorFactory(indices()); } @Override @@ -921,7 +920,7 @@ final class LongVector128 extends LongVector { @ForceInline public final LongMask128 laneIsValid() { return (LongMask128) toBitsVector().compare(VectorOperators.GE, 0) - .cast(vspecies()); + .cast(VSPECIES); } @ForceInline @@ -929,7 +928,7 @@ final class LongVector128 extends LongVector { public final LongShuffle128 rearrange(VectorShuffle shuffle) { LongShuffle128 concreteShuffle = (LongShuffle128) shuffle; return (LongShuffle128) toBitsVector().rearrange(concreteShuffle) - .toShuffle(vspecies(), false); + .toShuffle(VSPECIES, false); } @ForceInline @@ -942,7 +941,7 @@ final class LongVector128 extends LongVector { v = (LongVector128) v.blend(v.lanewise(VectorOperators.ADD, length()), v.compare(VectorOperators.LT, 0)); } - return (LongShuffle128) v.toShuffle(vspecies(), false); + return (LongShuffle128) v.toShuffle(VSPECIES, false); } private static long[] prepare(int[] indices, int offset) { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector256.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector256.java index c3d1ff4c276..110a54c547f 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector256.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector256.java @@ -35,9 +35,8 @@ import jdk.internal.ValueBased; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.vector.VectorSupport; -import static jdk.internal.vm.vector.VectorSupport.*; - import static jdk.incubator.vector.VectorOperators.*; +import static jdk.internal.vm.vector.VectorSupport.*; // -- This file was mechanically generated: Do not edit! -- // @@ -368,7 +367,7 @@ final class LongVector256 extends LongVector { @Override @ForceInline public final LongShuffle256 toShuffle() { - return (LongShuffle256) toShuffle(vspecies(), false); + return (LongShuffle256) toShuffle(VSPECIES, false); } // Specialized unary testing @@ -614,7 +613,7 @@ final class LongVector256 extends LongVector { @Override LongMask256 uOp(MUnOp f) { - boolean[] res = new boolean[vspecies().laneCount()]; + boolean[] res = new boolean[VSPECIES.laneCount()]; boolean[] bits = getBits(); for (int i = 0; i < res.length; i++) { res[i] = f.apply(i, bits[i]); @@ -624,7 +623,7 @@ final class LongVector256 extends LongVector { @Override LongMask256 bOp(VectorMask m, MBinOp f) { - boolean[] res = new boolean[vspecies().laneCount()]; + boolean[] res = new boolean[VSPECIES.laneCount()]; boolean[] bits = getBits(); boolean[] mbits = ((LongMask256)m).getBits(); for (int i = 0; i < res.length; i++) { @@ -774,16 +773,16 @@ final class LongVector256 extends LongVector { @ForceInline public boolean anyTrue() { return VectorSupport.test(BT_ne, LongMask256.class, LANEBITS_TYPE_ORDINAL, VLENGTH, - this, vspecies().maskAll(true), - (m, __) -> anyTrueHelper(((LongMask256)m).getBits())); + this, VSPECIES.maskAll(true), + (m, _) -> anyTrueHelper(((LongMask256)m).getBits())); } @Override @ForceInline public boolean allTrue() { return VectorSupport.test(BT_overflow, LongMask256.class, LANEBITS_TYPE_ORDINAL, VLENGTH, - this, vspecies().maskAll(true), - (m, __) -> allTrueHelper(((LongMask256)m).getBits())); + this, VSPECIES.maskAll(true), + (m, _) -> allTrueHelper(((LongMask256)m).getBits())); } @ForceInline @@ -791,7 +790,7 @@ final class LongVector256 extends LongVector { static LongMask256 maskAll(boolean bit) { return VectorSupport.fromBitsCoerced(LongMask256.class, LANEBITS_TYPE_ORDINAL, VLENGTH, (bit ? -1 : 0), MODE_BROADCAST, null, - (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); + (v, _) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); } private static final LongMask256 TRUE_MASK = new LongMask256(true); private static final LongMask256 FALSE_MASK = new LongMask256(false); @@ -851,7 +850,7 @@ final class LongVector256 extends LongVector { @Override LongVector256 toBitsVector0() { - return ((LongVector256) vspecies().asIntegral().dummyVector()).vectorFactory(indices()); + return ((LongVector256) VSPECIES.asIntegral().dummyVector()).vectorFactory(indices()); } @Override @@ -925,7 +924,7 @@ final class LongVector256 extends LongVector { @ForceInline public final LongMask256 laneIsValid() { return (LongMask256) toBitsVector().compare(VectorOperators.GE, 0) - .cast(vspecies()); + .cast(VSPECIES); } @ForceInline @@ -933,7 +932,7 @@ final class LongVector256 extends LongVector { public final LongShuffle256 rearrange(VectorShuffle shuffle) { LongShuffle256 concreteShuffle = (LongShuffle256) shuffle; return (LongShuffle256) toBitsVector().rearrange(concreteShuffle) - .toShuffle(vspecies(), false); + .toShuffle(VSPECIES, false); } @ForceInline @@ -946,7 +945,7 @@ final class LongVector256 extends LongVector { v = (LongVector256) v.blend(v.lanewise(VectorOperators.ADD, length()), v.compare(VectorOperators.LT, 0)); } - return (LongShuffle256) v.toShuffle(vspecies(), false); + return (LongShuffle256) v.toShuffle(VSPECIES, false); } private static long[] prepare(int[] indices, int offset) { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector512.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector512.java index b8c95967a99..3502f209c3b 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector512.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector512.java @@ -35,9 +35,8 @@ import jdk.internal.ValueBased; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.vector.VectorSupport; -import static jdk.internal.vm.vector.VectorSupport.*; - import static jdk.incubator.vector.VectorOperators.*; +import static jdk.internal.vm.vector.VectorSupport.*; // -- This file was mechanically generated: Do not edit! -- // @@ -368,7 +367,7 @@ final class LongVector512 extends LongVector { @Override @ForceInline public final LongShuffle512 toShuffle() { - return (LongShuffle512) toShuffle(vspecies(), false); + return (LongShuffle512) toShuffle(VSPECIES, false); } // Specialized unary testing @@ -622,7 +621,7 @@ final class LongVector512 extends LongVector { @Override LongMask512 uOp(MUnOp f) { - boolean[] res = new boolean[vspecies().laneCount()]; + boolean[] res = new boolean[VSPECIES.laneCount()]; boolean[] bits = getBits(); for (int i = 0; i < res.length; i++) { res[i] = f.apply(i, bits[i]); @@ -632,7 +631,7 @@ final class LongVector512 extends LongVector { @Override LongMask512 bOp(VectorMask m, MBinOp f) { - boolean[] res = new boolean[vspecies().laneCount()]; + boolean[] res = new boolean[VSPECIES.laneCount()]; boolean[] bits = getBits(); boolean[] mbits = ((LongMask512)m).getBits(); for (int i = 0; i < res.length; i++) { @@ -782,16 +781,16 @@ final class LongVector512 extends LongVector { @ForceInline public boolean anyTrue() { return VectorSupport.test(BT_ne, LongMask512.class, LANEBITS_TYPE_ORDINAL, VLENGTH, - this, vspecies().maskAll(true), - (m, __) -> anyTrueHelper(((LongMask512)m).getBits())); + this, VSPECIES.maskAll(true), + (m, _) -> anyTrueHelper(((LongMask512)m).getBits())); } @Override @ForceInline public boolean allTrue() { return VectorSupport.test(BT_overflow, LongMask512.class, LANEBITS_TYPE_ORDINAL, VLENGTH, - this, vspecies().maskAll(true), - (m, __) -> allTrueHelper(((LongMask512)m).getBits())); + this, VSPECIES.maskAll(true), + (m, _) -> allTrueHelper(((LongMask512)m).getBits())); } @ForceInline @@ -799,7 +798,7 @@ final class LongVector512 extends LongVector { static LongMask512 maskAll(boolean bit) { return VectorSupport.fromBitsCoerced(LongMask512.class, LANEBITS_TYPE_ORDINAL, VLENGTH, (bit ? -1 : 0), MODE_BROADCAST, null, - (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); + (v, _) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); } private static final LongMask512 TRUE_MASK = new LongMask512(true); private static final LongMask512 FALSE_MASK = new LongMask512(false); @@ -859,7 +858,7 @@ final class LongVector512 extends LongVector { @Override LongVector512 toBitsVector0() { - return ((LongVector512) vspecies().asIntegral().dummyVector()).vectorFactory(indices()); + return ((LongVector512) VSPECIES.asIntegral().dummyVector()).vectorFactory(indices()); } @Override @@ -933,7 +932,7 @@ final class LongVector512 extends LongVector { @ForceInline public final LongMask512 laneIsValid() { return (LongMask512) toBitsVector().compare(VectorOperators.GE, 0) - .cast(vspecies()); + .cast(VSPECIES); } @ForceInline @@ -941,7 +940,7 @@ final class LongVector512 extends LongVector { public final LongShuffle512 rearrange(VectorShuffle shuffle) { LongShuffle512 concreteShuffle = (LongShuffle512) shuffle; return (LongShuffle512) toBitsVector().rearrange(concreteShuffle) - .toShuffle(vspecies(), false); + .toShuffle(VSPECIES, false); } @ForceInline @@ -954,7 +953,7 @@ final class LongVector512 extends LongVector { v = (LongVector512) v.blend(v.lanewise(VectorOperators.ADD, length()), v.compare(VectorOperators.LT, 0)); } - return (LongShuffle512) v.toShuffle(vspecies(), false); + return (LongShuffle512) v.toShuffle(VSPECIES, false); } private static long[] prepare(int[] indices, int offset) { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector64.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector64.java index 3c9b525f6d0..2a2fe4329a8 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector64.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector64.java @@ -35,9 +35,8 @@ import jdk.internal.ValueBased; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.vector.VectorSupport; -import static jdk.internal.vm.vector.VectorSupport.*; - import static jdk.incubator.vector.VectorOperators.*; +import static jdk.internal.vm.vector.VectorSupport.*; // -- This file was mechanically generated: Do not edit! -- // @@ -368,7 +367,7 @@ final class LongVector64 extends LongVector { @Override @ForceInline public final LongShuffle64 toShuffle() { - return (LongShuffle64) toShuffle(vspecies(), false); + return (LongShuffle64) toShuffle(VSPECIES, false); } // Specialized unary testing @@ -608,7 +607,7 @@ final class LongVector64 extends LongVector { @Override LongMask64 uOp(MUnOp f) { - boolean[] res = new boolean[vspecies().laneCount()]; + boolean[] res = new boolean[VSPECIES.laneCount()]; boolean[] bits = getBits(); for (int i = 0; i < res.length; i++) { res[i] = f.apply(i, bits[i]); @@ -618,7 +617,7 @@ final class LongVector64 extends LongVector { @Override LongMask64 bOp(VectorMask m, MBinOp f) { - boolean[] res = new boolean[vspecies().laneCount()]; + boolean[] res = new boolean[VSPECIES.laneCount()]; boolean[] bits = getBits(); boolean[] mbits = ((LongMask64)m).getBits(); for (int i = 0; i < res.length; i++) { @@ -768,16 +767,16 @@ final class LongVector64 extends LongVector { @ForceInline public boolean anyTrue() { return VectorSupport.test(BT_ne, LongMask64.class, LANEBITS_TYPE_ORDINAL, VLENGTH, - this, vspecies().maskAll(true), - (m, __) -> anyTrueHelper(((LongMask64)m).getBits())); + this, VSPECIES.maskAll(true), + (m, _) -> anyTrueHelper(((LongMask64)m).getBits())); } @Override @ForceInline public boolean allTrue() { return VectorSupport.test(BT_overflow, LongMask64.class, LANEBITS_TYPE_ORDINAL, VLENGTH, - this, vspecies().maskAll(true), - (m, __) -> allTrueHelper(((LongMask64)m).getBits())); + this, VSPECIES.maskAll(true), + (m, _) -> allTrueHelper(((LongMask64)m).getBits())); } @ForceInline @@ -785,7 +784,7 @@ final class LongVector64 extends LongVector { static LongMask64 maskAll(boolean bit) { return VectorSupport.fromBitsCoerced(LongMask64.class, LANEBITS_TYPE_ORDINAL, VLENGTH, (bit ? -1 : 0), MODE_BROADCAST, null, - (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); + (v, _) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); } private static final LongMask64 TRUE_MASK = new LongMask64(true); private static final LongMask64 FALSE_MASK = new LongMask64(false); @@ -845,7 +844,7 @@ final class LongVector64 extends LongVector { @Override LongVector64 toBitsVector0() { - return ((LongVector64) vspecies().asIntegral().dummyVector()).vectorFactory(indices()); + return ((LongVector64) VSPECIES.asIntegral().dummyVector()).vectorFactory(indices()); } @Override @@ -919,7 +918,7 @@ final class LongVector64 extends LongVector { @ForceInline public final LongMask64 laneIsValid() { return (LongMask64) toBitsVector().compare(VectorOperators.GE, 0) - .cast(vspecies()); + .cast(VSPECIES); } @ForceInline @@ -927,7 +926,7 @@ final class LongVector64 extends LongVector { public final LongShuffle64 rearrange(VectorShuffle shuffle) { LongShuffle64 concreteShuffle = (LongShuffle64) shuffle; return (LongShuffle64) toBitsVector().rearrange(concreteShuffle) - .toShuffle(vspecies(), false); + .toShuffle(VSPECIES, false); } @ForceInline @@ -940,7 +939,7 @@ final class LongVector64 extends LongVector { v = (LongVector64) v.blend(v.lanewise(VectorOperators.ADD, length()), v.compare(VectorOperators.LT, 0)); } - return (LongShuffle64) v.toShuffle(vspecies(), false); + return (LongShuffle64) v.toShuffle(VSPECIES, false); } private static long[] prepare(int[] indices, int offset) { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVectorMax.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVectorMax.java index 4752959f884..157c58e20e8 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVectorMax.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVectorMax.java @@ -35,9 +35,8 @@ import jdk.internal.ValueBased; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.vector.VectorSupport; -import static jdk.internal.vm.vector.VectorSupport.*; - import static jdk.incubator.vector.VectorOperators.*; +import static jdk.internal.vm.vector.VectorSupport.*; // -- This file was mechanically generated: Do not edit! -- // @@ -368,7 +367,7 @@ final class LongVectorMax extends LongVector { @Override @ForceInline public final LongShuffleMax toShuffle() { - return (LongShuffleMax) toShuffle(vspecies(), false); + return (LongShuffleMax) toShuffle(VSPECIES, false); } // Specialized unary testing @@ -608,7 +607,7 @@ final class LongVectorMax extends LongVector { @Override LongMaskMax uOp(MUnOp f) { - boolean[] res = new boolean[vspecies().laneCount()]; + boolean[] res = new boolean[VSPECIES.laneCount()]; boolean[] bits = getBits(); for (int i = 0; i < res.length; i++) { res[i] = f.apply(i, bits[i]); @@ -618,7 +617,7 @@ final class LongVectorMax extends LongVector { @Override LongMaskMax bOp(VectorMask m, MBinOp f) { - boolean[] res = new boolean[vspecies().laneCount()]; + boolean[] res = new boolean[VSPECIES.laneCount()]; boolean[] bits = getBits(); boolean[] mbits = ((LongMaskMax)m).getBits(); for (int i = 0; i < res.length; i++) { @@ -768,16 +767,16 @@ final class LongVectorMax extends LongVector { @ForceInline public boolean anyTrue() { return VectorSupport.test(BT_ne, LongMaskMax.class, LANEBITS_TYPE_ORDINAL, VLENGTH, - this, vspecies().maskAll(true), - (m, __) -> anyTrueHelper(((LongMaskMax)m).getBits())); + this, VSPECIES.maskAll(true), + (m, _) -> anyTrueHelper(((LongMaskMax)m).getBits())); } @Override @ForceInline public boolean allTrue() { return VectorSupport.test(BT_overflow, LongMaskMax.class, LANEBITS_TYPE_ORDINAL, VLENGTH, - this, vspecies().maskAll(true), - (m, __) -> allTrueHelper(((LongMaskMax)m).getBits())); + this, VSPECIES.maskAll(true), + (m, _) -> allTrueHelper(((LongMaskMax)m).getBits())); } @ForceInline @@ -785,7 +784,7 @@ final class LongVectorMax extends LongVector { static LongMaskMax maskAll(boolean bit) { return VectorSupport.fromBitsCoerced(LongMaskMax.class, LANEBITS_TYPE_ORDINAL, VLENGTH, (bit ? -1 : 0), MODE_BROADCAST, null, - (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); + (v, _) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); } private static final LongMaskMax TRUE_MASK = new LongMaskMax(true); private static final LongMaskMax FALSE_MASK = new LongMaskMax(false); @@ -845,7 +844,7 @@ final class LongVectorMax extends LongVector { @Override LongVectorMax toBitsVector0() { - return ((LongVectorMax) vspecies().asIntegral().dummyVector()).vectorFactory(indices()); + return ((LongVectorMax) VSPECIES.asIntegral().dummyVector()).vectorFactory(indices()); } @Override @@ -919,7 +918,7 @@ final class LongVectorMax extends LongVector { @ForceInline public final LongMaskMax laneIsValid() { return (LongMaskMax) toBitsVector().compare(VectorOperators.GE, 0) - .cast(vspecies()); + .cast(VSPECIES); } @ForceInline @@ -927,7 +926,7 @@ final class LongVectorMax extends LongVector { public final LongShuffleMax rearrange(VectorShuffle shuffle) { LongShuffleMax concreteShuffle = (LongShuffleMax) shuffle; return (LongShuffleMax) toBitsVector().rearrange(concreteShuffle) - .toShuffle(vspecies(), false); + .toShuffle(VSPECIES, false); } @ForceInline @@ -940,7 +939,7 @@ final class LongVectorMax extends LongVector { v = (LongVectorMax) v.blend(v.lanewise(VectorOperators.ADD, length()), v.compare(VectorOperators.LT, 0)); } - return (LongShuffleMax) v.toShuffle(vspecies(), false); + return (LongShuffleMax) v.toShuffle(VSPECIES, false); } private static long[] prepare(int[] indices, int offset) { 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 7ba465706e8..21bc80a12bc 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 @@ -49,7 +49,8 @@ import static jdk.incubator.vector.VectorOperators.*; * {@code short} values. */ @SuppressWarnings("cast") // warning: redundant cast -public abstract class ShortVector extends AbstractVector { +public abstract sealed class ShortVector extends AbstractVector + permits ShortVector64, ShortVector128, ShortVector256, ShortVector512, ShortVectorMax { ShortVector(short[] vec) { super(vec); diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector128.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector128.java index 89ec97c6be0..22bbfce0928 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector128.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector128.java @@ -25,7 +25,6 @@ package jdk.incubator.vector; import java.lang.foreign.MemorySegment; -import java.lang.foreign.ValueLayout; import java.nio.ByteOrder; import java.util.Arrays; import java.util.Objects; @@ -35,9 +34,8 @@ import jdk.internal.ValueBased; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.vector.VectorSupport; -import static jdk.internal.vm.vector.VectorSupport.*; - import static jdk.incubator.vector.VectorOperators.*; +import static jdk.internal.vm.vector.VectorSupport.*; // -- This file was mechanically generated: Do not edit! -- // @@ -373,7 +371,7 @@ final class ShortVector128 extends ShortVector { @Override @ForceInline public final ShortShuffle128 toShuffle() { - return (ShortShuffle128) toShuffle(vspecies(), false); + return (ShortShuffle128) toShuffle(VSPECIES, false); } // Specialized unary testing @@ -632,7 +630,7 @@ final class ShortVector128 extends ShortVector { @Override ShortMask128 uOp(MUnOp f) { - boolean[] res = new boolean[vspecies().laneCount()]; + boolean[] res = new boolean[VSPECIES.laneCount()]; boolean[] bits = getBits(); for (int i = 0; i < res.length; i++) { res[i] = f.apply(i, bits[i]); @@ -642,7 +640,7 @@ final class ShortVector128 extends ShortVector { @Override ShortMask128 bOp(VectorMask m, MBinOp f) { - boolean[] res = new boolean[vspecies().laneCount()]; + boolean[] res = new boolean[VSPECIES.laneCount()]; boolean[] bits = getBits(); boolean[] mbits = ((ShortMask128)m).getBits(); for (int i = 0; i < res.length; i++) { @@ -792,16 +790,16 @@ final class ShortVector128 extends ShortVector { @ForceInline public boolean anyTrue() { return VectorSupport.test(BT_ne, ShortMask128.class, LANEBITS_TYPE_ORDINAL, VLENGTH, - this, vspecies().maskAll(true), - (m, __) -> anyTrueHelper(((ShortMask128)m).getBits())); + this, VSPECIES.maskAll(true), + (m, _) -> anyTrueHelper(((ShortMask128)m).getBits())); } @Override @ForceInline public boolean allTrue() { return VectorSupport.test(BT_overflow, ShortMask128.class, LANEBITS_TYPE_ORDINAL, VLENGTH, - this, vspecies().maskAll(true), - (m, __) -> allTrueHelper(((ShortMask128)m).getBits())); + this, VSPECIES.maskAll(true), + (m, _) -> allTrueHelper(((ShortMask128)m).getBits())); } @ForceInline @@ -809,7 +807,7 @@ final class ShortVector128 extends ShortVector { static ShortMask128 maskAll(boolean bit) { return VectorSupport.fromBitsCoerced(ShortMask128.class, LANEBITS_TYPE_ORDINAL, VLENGTH, (bit ? -1 : 0), MODE_BROADCAST, null, - (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); + (v, _) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); } private static final ShortMask128 TRUE_MASK = new ShortMask128(true); private static final ShortMask128 FALSE_MASK = new ShortMask128(false); @@ -869,7 +867,7 @@ final class ShortVector128 extends ShortVector { @Override ShortVector128 toBitsVector0() { - return ((ShortVector128) vspecies().asIntegral().dummyVector()).vectorFactory(indices()); + return ((ShortVector128) VSPECIES.asIntegral().dummyVector()).vectorFactory(indices()); } @Override @@ -908,7 +906,7 @@ final class ShortVector128 extends ShortVector { @ForceInline public final ShortMask128 laneIsValid() { return (ShortMask128) toBitsVector().compare(VectorOperators.GE, 0) - .cast(vspecies()); + .cast(VSPECIES); } @ForceInline @@ -916,7 +914,7 @@ final class ShortVector128 extends ShortVector { public final ShortShuffle128 rearrange(VectorShuffle shuffle) { ShortShuffle128 concreteShuffle = (ShortShuffle128) shuffle; return (ShortShuffle128) toBitsVector().rearrange(concreteShuffle) - .toShuffle(vspecies(), false); + .toShuffle(VSPECIES, false); } @ForceInline @@ -929,7 +927,7 @@ final class ShortVector128 extends ShortVector { v = (ShortVector128) v.blend(v.lanewise(VectorOperators.ADD, length()), v.compare(VectorOperators.LT, 0)); } - return (ShortShuffle128) v.toShuffle(vspecies(), false); + return (ShortShuffle128) v.toShuffle(VSPECIES, false); } private static short[] prepare(int[] indices, int offset) { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector256.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector256.java index 0f5751c27d8..6011695bf54 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector256.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector256.java @@ -25,7 +25,6 @@ package jdk.incubator.vector; import java.lang.foreign.MemorySegment; -import java.lang.foreign.ValueLayout; import java.nio.ByteOrder; import java.util.Arrays; import java.util.Objects; @@ -35,9 +34,8 @@ import jdk.internal.ValueBased; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.vector.VectorSupport; -import static jdk.internal.vm.vector.VectorSupport.*; - import static jdk.incubator.vector.VectorOperators.*; +import static jdk.internal.vm.vector.VectorSupport.*; // -- This file was mechanically generated: Do not edit! -- // @@ -373,7 +371,7 @@ final class ShortVector256 extends ShortVector { @Override @ForceInline public final ShortShuffle256 toShuffle() { - return (ShortShuffle256) toShuffle(vspecies(), false); + return (ShortShuffle256) toShuffle(VSPECIES, false); } // Specialized unary testing @@ -648,7 +646,7 @@ final class ShortVector256 extends ShortVector { @Override ShortMask256 uOp(MUnOp f) { - boolean[] res = new boolean[vspecies().laneCount()]; + boolean[] res = new boolean[VSPECIES.laneCount()]; boolean[] bits = getBits(); for (int i = 0; i < res.length; i++) { res[i] = f.apply(i, bits[i]); @@ -658,7 +656,7 @@ final class ShortVector256 extends ShortVector { @Override ShortMask256 bOp(VectorMask m, MBinOp f) { - boolean[] res = new boolean[vspecies().laneCount()]; + boolean[] res = new boolean[VSPECIES.laneCount()]; boolean[] bits = getBits(); boolean[] mbits = ((ShortMask256)m).getBits(); for (int i = 0; i < res.length; i++) { @@ -808,16 +806,16 @@ final class ShortVector256 extends ShortVector { @ForceInline public boolean anyTrue() { return VectorSupport.test(BT_ne, ShortMask256.class, LANEBITS_TYPE_ORDINAL, VLENGTH, - this, vspecies().maskAll(true), - (m, __) -> anyTrueHelper(((ShortMask256)m).getBits())); + this, VSPECIES.maskAll(true), + (m, _) -> anyTrueHelper(((ShortMask256)m).getBits())); } @Override @ForceInline public boolean allTrue() { return VectorSupport.test(BT_overflow, ShortMask256.class, LANEBITS_TYPE_ORDINAL, VLENGTH, - this, vspecies().maskAll(true), - (m, __) -> allTrueHelper(((ShortMask256)m).getBits())); + this, VSPECIES.maskAll(true), + (m, _) -> allTrueHelper(((ShortMask256)m).getBits())); } @ForceInline @@ -825,7 +823,7 @@ final class ShortVector256 extends ShortVector { static ShortMask256 maskAll(boolean bit) { return VectorSupport.fromBitsCoerced(ShortMask256.class, LANEBITS_TYPE_ORDINAL, VLENGTH, (bit ? -1 : 0), MODE_BROADCAST, null, - (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); + (v, _) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); } private static final ShortMask256 TRUE_MASK = new ShortMask256(true); private static final ShortMask256 FALSE_MASK = new ShortMask256(false); @@ -885,7 +883,7 @@ final class ShortVector256 extends ShortVector { @Override ShortVector256 toBitsVector0() { - return ((ShortVector256) vspecies().asIntegral().dummyVector()).vectorFactory(indices()); + return ((ShortVector256) VSPECIES.asIntegral().dummyVector()).vectorFactory(indices()); } @Override @@ -924,7 +922,7 @@ final class ShortVector256 extends ShortVector { @ForceInline public final ShortMask256 laneIsValid() { return (ShortMask256) toBitsVector().compare(VectorOperators.GE, 0) - .cast(vspecies()); + .cast(VSPECIES); } @ForceInline @@ -932,7 +930,7 @@ final class ShortVector256 extends ShortVector { public final ShortShuffle256 rearrange(VectorShuffle shuffle) { ShortShuffle256 concreteShuffle = (ShortShuffle256) shuffle; return (ShortShuffle256) toBitsVector().rearrange(concreteShuffle) - .toShuffle(vspecies(), false); + .toShuffle(VSPECIES, false); } @ForceInline @@ -945,7 +943,7 @@ final class ShortVector256 extends ShortVector { v = (ShortVector256) v.blend(v.lanewise(VectorOperators.ADD, length()), v.compare(VectorOperators.LT, 0)); } - return (ShortShuffle256) v.toShuffle(vspecies(), false); + return (ShortShuffle256) v.toShuffle(VSPECIES, false); } private static short[] prepare(int[] indices, int offset) { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector512.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector512.java index 3d38dfd88fd..e6101d2e6be 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector512.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector512.java @@ -25,7 +25,6 @@ package jdk.incubator.vector; import java.lang.foreign.MemorySegment; -import java.lang.foreign.ValueLayout; import java.nio.ByteOrder; import java.util.Arrays; import java.util.Objects; @@ -35,9 +34,8 @@ import jdk.internal.ValueBased; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.vector.VectorSupport; -import static jdk.internal.vm.vector.VectorSupport.*; - import static jdk.incubator.vector.VectorOperators.*; +import static jdk.internal.vm.vector.VectorSupport.*; // -- This file was mechanically generated: Do not edit! -- // @@ -373,7 +371,7 @@ final class ShortVector512 extends ShortVector { @Override @ForceInline public final ShortShuffle512 toShuffle() { - return (ShortShuffle512) toShuffle(vspecies(), false); + return (ShortShuffle512) toShuffle(VSPECIES, false); } // Specialized unary testing @@ -680,7 +678,7 @@ final class ShortVector512 extends ShortVector { @Override ShortMask512 uOp(MUnOp f) { - boolean[] res = new boolean[vspecies().laneCount()]; + boolean[] res = new boolean[VSPECIES.laneCount()]; boolean[] bits = getBits(); for (int i = 0; i < res.length; i++) { res[i] = f.apply(i, bits[i]); @@ -690,7 +688,7 @@ final class ShortVector512 extends ShortVector { @Override ShortMask512 bOp(VectorMask m, MBinOp f) { - boolean[] res = new boolean[vspecies().laneCount()]; + boolean[] res = new boolean[VSPECIES.laneCount()]; boolean[] bits = getBits(); boolean[] mbits = ((ShortMask512)m).getBits(); for (int i = 0; i < res.length; i++) { @@ -840,16 +838,16 @@ final class ShortVector512 extends ShortVector { @ForceInline public boolean anyTrue() { return VectorSupport.test(BT_ne, ShortMask512.class, LANEBITS_TYPE_ORDINAL, VLENGTH, - this, vspecies().maskAll(true), - (m, __) -> anyTrueHelper(((ShortMask512)m).getBits())); + this, VSPECIES.maskAll(true), + (m, _) -> anyTrueHelper(((ShortMask512)m).getBits())); } @Override @ForceInline public boolean allTrue() { return VectorSupport.test(BT_overflow, ShortMask512.class, LANEBITS_TYPE_ORDINAL, VLENGTH, - this, vspecies().maskAll(true), - (m, __) -> allTrueHelper(((ShortMask512)m).getBits())); + this, VSPECIES.maskAll(true), + (m, _) -> allTrueHelper(((ShortMask512)m).getBits())); } @ForceInline @@ -857,7 +855,7 @@ final class ShortVector512 extends ShortVector { static ShortMask512 maskAll(boolean bit) { return VectorSupport.fromBitsCoerced(ShortMask512.class, LANEBITS_TYPE_ORDINAL, VLENGTH, (bit ? -1 : 0), MODE_BROADCAST, null, - (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); + (v, _) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); } private static final ShortMask512 TRUE_MASK = new ShortMask512(true); private static final ShortMask512 FALSE_MASK = new ShortMask512(false); @@ -917,7 +915,7 @@ final class ShortVector512 extends ShortVector { @Override ShortVector512 toBitsVector0() { - return ((ShortVector512) vspecies().asIntegral().dummyVector()).vectorFactory(indices()); + return ((ShortVector512) VSPECIES.asIntegral().dummyVector()).vectorFactory(indices()); } @Override @@ -956,7 +954,7 @@ final class ShortVector512 extends ShortVector { @ForceInline public final ShortMask512 laneIsValid() { return (ShortMask512) toBitsVector().compare(VectorOperators.GE, 0) - .cast(vspecies()); + .cast(VSPECIES); } @ForceInline @@ -964,7 +962,7 @@ final class ShortVector512 extends ShortVector { public final ShortShuffle512 rearrange(VectorShuffle shuffle) { ShortShuffle512 concreteShuffle = (ShortShuffle512) shuffle; return (ShortShuffle512) toBitsVector().rearrange(concreteShuffle) - .toShuffle(vspecies(), false); + .toShuffle(VSPECIES, false); } @ForceInline @@ -977,7 +975,7 @@ final class ShortVector512 extends ShortVector { v = (ShortVector512) v.blend(v.lanewise(VectorOperators.ADD, length()), v.compare(VectorOperators.LT, 0)); } - return (ShortShuffle512) v.toShuffle(vspecies(), false); + return (ShortShuffle512) v.toShuffle(VSPECIES, false); } private static short[] prepare(int[] indices, int offset) { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector64.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector64.java index b319d98f784..31af959b4a8 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector64.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector64.java @@ -25,7 +25,6 @@ package jdk.incubator.vector; import java.lang.foreign.MemorySegment; -import java.lang.foreign.ValueLayout; import java.nio.ByteOrder; import java.util.Arrays; import java.util.Objects; @@ -35,9 +34,8 @@ import jdk.internal.ValueBased; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.vector.VectorSupport; -import static jdk.internal.vm.vector.VectorSupport.*; - import static jdk.incubator.vector.VectorOperators.*; +import static jdk.internal.vm.vector.VectorSupport.*; // -- This file was mechanically generated: Do not edit! -- // @@ -373,7 +371,7 @@ final class ShortVector64 extends ShortVector { @Override @ForceInline public final ShortShuffle64 toShuffle() { - return (ShortShuffle64) toShuffle(vspecies(), false); + return (ShortShuffle64) toShuffle(VSPECIES, false); } // Specialized unary testing @@ -624,7 +622,7 @@ final class ShortVector64 extends ShortVector { @Override ShortMask64 uOp(MUnOp f) { - boolean[] res = new boolean[vspecies().laneCount()]; + boolean[] res = new boolean[VSPECIES.laneCount()]; boolean[] bits = getBits(); for (int i = 0; i < res.length; i++) { res[i] = f.apply(i, bits[i]); @@ -634,7 +632,7 @@ final class ShortVector64 extends ShortVector { @Override ShortMask64 bOp(VectorMask m, MBinOp f) { - boolean[] res = new boolean[vspecies().laneCount()]; + boolean[] res = new boolean[VSPECIES.laneCount()]; boolean[] bits = getBits(); boolean[] mbits = ((ShortMask64)m).getBits(); for (int i = 0; i < res.length; i++) { @@ -784,16 +782,16 @@ final class ShortVector64 extends ShortVector { @ForceInline public boolean anyTrue() { return VectorSupport.test(BT_ne, ShortMask64.class, LANEBITS_TYPE_ORDINAL, VLENGTH, - this, vspecies().maskAll(true), - (m, __) -> anyTrueHelper(((ShortMask64)m).getBits())); + this, VSPECIES.maskAll(true), + (m, _) -> anyTrueHelper(((ShortMask64)m).getBits())); } @Override @ForceInline public boolean allTrue() { return VectorSupport.test(BT_overflow, ShortMask64.class, LANEBITS_TYPE_ORDINAL, VLENGTH, - this, vspecies().maskAll(true), - (m, __) -> allTrueHelper(((ShortMask64)m).getBits())); + this, VSPECIES.maskAll(true), + (m, _) -> allTrueHelper(((ShortMask64)m).getBits())); } @ForceInline @@ -801,7 +799,7 @@ final class ShortVector64 extends ShortVector { static ShortMask64 maskAll(boolean bit) { return VectorSupport.fromBitsCoerced(ShortMask64.class, LANEBITS_TYPE_ORDINAL, VLENGTH, (bit ? -1 : 0), MODE_BROADCAST, null, - (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); + (v, _) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); } private static final ShortMask64 TRUE_MASK = new ShortMask64(true); private static final ShortMask64 FALSE_MASK = new ShortMask64(false); @@ -861,7 +859,7 @@ final class ShortVector64 extends ShortVector { @Override ShortVector64 toBitsVector0() { - return ((ShortVector64) vspecies().asIntegral().dummyVector()).vectorFactory(indices()); + return ((ShortVector64) VSPECIES.asIntegral().dummyVector()).vectorFactory(indices()); } @Override @@ -900,7 +898,7 @@ final class ShortVector64 extends ShortVector { @ForceInline public final ShortMask64 laneIsValid() { return (ShortMask64) toBitsVector().compare(VectorOperators.GE, 0) - .cast(vspecies()); + .cast(VSPECIES); } @ForceInline @@ -908,7 +906,7 @@ final class ShortVector64 extends ShortVector { public final ShortShuffle64 rearrange(VectorShuffle shuffle) { ShortShuffle64 concreteShuffle = (ShortShuffle64) shuffle; return (ShortShuffle64) toBitsVector().rearrange(concreteShuffle) - .toShuffle(vspecies(), false); + .toShuffle(VSPECIES, false); } @ForceInline @@ -921,7 +919,7 @@ final class ShortVector64 extends ShortVector { v = (ShortVector64) v.blend(v.lanewise(VectorOperators.ADD, length()), v.compare(VectorOperators.LT, 0)); } - return (ShortShuffle64) v.toShuffle(vspecies(), false); + return (ShortShuffle64) v.toShuffle(VSPECIES, false); } private static short[] prepare(int[] indices, int offset) { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVectorMax.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVectorMax.java index 69b298857c9..fe0359c4711 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVectorMax.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVectorMax.java @@ -25,7 +25,6 @@ package jdk.incubator.vector; import java.lang.foreign.MemorySegment; -import java.lang.foreign.ValueLayout; import java.nio.ByteOrder; import java.util.Arrays; import java.util.Objects; @@ -35,9 +34,8 @@ import jdk.internal.ValueBased; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.vector.VectorSupport; -import static jdk.internal.vm.vector.VectorSupport.*; - import static jdk.incubator.vector.VectorOperators.*; +import static jdk.internal.vm.vector.VectorSupport.*; // -- This file was mechanically generated: Do not edit! -- // @@ -373,7 +371,7 @@ final class ShortVectorMax extends ShortVector { @Override @ForceInline public final ShortShuffleMax toShuffle() { - return (ShortShuffleMax) toShuffle(vspecies(), false); + return (ShortShuffleMax) toShuffle(VSPECIES, false); } // Specialized unary testing @@ -618,7 +616,7 @@ final class ShortVectorMax extends ShortVector { @Override ShortMaskMax uOp(MUnOp f) { - boolean[] res = new boolean[vspecies().laneCount()]; + boolean[] res = new boolean[VSPECIES.laneCount()]; boolean[] bits = getBits(); for (int i = 0; i < res.length; i++) { res[i] = f.apply(i, bits[i]); @@ -628,7 +626,7 @@ final class ShortVectorMax extends ShortVector { @Override ShortMaskMax bOp(VectorMask m, MBinOp f) { - boolean[] res = new boolean[vspecies().laneCount()]; + boolean[] res = new boolean[VSPECIES.laneCount()]; boolean[] bits = getBits(); boolean[] mbits = ((ShortMaskMax)m).getBits(); for (int i = 0; i < res.length; i++) { @@ -778,16 +776,16 @@ final class ShortVectorMax extends ShortVector { @ForceInline public boolean anyTrue() { return VectorSupport.test(BT_ne, ShortMaskMax.class, LANEBITS_TYPE_ORDINAL, VLENGTH, - this, vspecies().maskAll(true), - (m, __) -> anyTrueHelper(((ShortMaskMax)m).getBits())); + this, VSPECIES.maskAll(true), + (m, _) -> anyTrueHelper(((ShortMaskMax)m).getBits())); } @Override @ForceInline public boolean allTrue() { return VectorSupport.test(BT_overflow, ShortMaskMax.class, LANEBITS_TYPE_ORDINAL, VLENGTH, - this, vspecies().maskAll(true), - (m, __) -> allTrueHelper(((ShortMaskMax)m).getBits())); + this, VSPECIES.maskAll(true), + (m, _) -> allTrueHelper(((ShortMaskMax)m).getBits())); } @ForceInline @@ -795,7 +793,7 @@ final class ShortVectorMax extends ShortVector { static ShortMaskMax maskAll(boolean bit) { return VectorSupport.fromBitsCoerced(ShortMaskMax.class, LANEBITS_TYPE_ORDINAL, VLENGTH, (bit ? -1 : 0), MODE_BROADCAST, null, - (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); + (v, _) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); } private static final ShortMaskMax TRUE_MASK = new ShortMaskMax(true); private static final ShortMaskMax FALSE_MASK = new ShortMaskMax(false); @@ -855,7 +853,7 @@ final class ShortVectorMax extends ShortVector { @Override ShortVectorMax toBitsVector0() { - return ((ShortVectorMax) vspecies().asIntegral().dummyVector()).vectorFactory(indices()); + return ((ShortVectorMax) VSPECIES.asIntegral().dummyVector()).vectorFactory(indices()); } @Override @@ -894,7 +892,7 @@ final class ShortVectorMax extends ShortVector { @ForceInline public final ShortMaskMax laneIsValid() { return (ShortMaskMax) toBitsVector().compare(VectorOperators.GE, 0) - .cast(vspecies()); + .cast(VSPECIES); } @ForceInline @@ -902,7 +900,7 @@ final class ShortVectorMax extends ShortVector { public final ShortShuffleMax rearrange(VectorShuffle shuffle) { ShortShuffleMax concreteShuffle = (ShortShuffleMax) shuffle; return (ShortShuffleMax) toBitsVector().rearrange(concreteShuffle) - .toShuffle(vspecies(), false); + .toShuffle(VSPECIES, false); } @ForceInline @@ -915,7 +913,7 @@ final class ShortVectorMax extends ShortVector { v = (ShortVectorMax) v.blend(v.lanewise(VectorOperators.ADD, length()), v.compare(VectorOperators.LT, 0)); } - return (ShortShuffleMax) v.toShuffle(vspecies(), false); + return (ShortShuffleMax) v.toShuffle(VSPECIES, false); } private static short[] prepare(int[] indices, int offset) { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Util.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Util.java index 8562d4b5d7a..133195fa54d 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Util.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Util.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ */ package jdk.incubator.vector; -/*package-private*/ class Util { +/*package-private*/ final class Util { public static void requires(boolean cond, String message) { if (!cond) { throw new InternalError(message); diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Vector.java index 68b4a35067c..85b3bbca269 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Vector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1170,9 +1170,10 @@ import java.util.Arrays; * @param the boxed version of {@code ETYPE}, * the element type of a vector * + * @sealedGraph */ @SuppressWarnings("exports") -public abstract class Vector extends jdk.internal.vm.vector.VectorSupport.Vector { +public abstract sealed class Vector extends jdk.internal.vm.vector.VectorSupport.Vector permits AbstractVector { // This type is sealed within its package. // Users cannot roll their own vector types. diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorIntrinsics.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorIntrinsics.java index 266a843083a..f0115371d48 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorIntrinsics.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorIntrinsics.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ import jdk.internal.vm.annotation.ForceInline; import java.util.Objects; -/*non-public*/ class VectorIntrinsics { +/*non-public*/ final class VectorIntrinsics { static final int VECTOR_ACCESS_OOB_CHECK = Integer.getInteger("jdk.incubator.vector.VECTOR_ACCESS_OOB_CHECK", 2); diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorMask.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorMask.java index 13ee9e27e0d..607b194946b 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorMask.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorMask.java @@ -131,7 +131,7 @@ import java.util.Objects; * the element type of a vector */ @SuppressWarnings("exports") -public abstract class VectorMask extends jdk.internal.vm.vector.VectorSupport.VectorMask { +public abstract sealed class VectorMask extends jdk.internal.vm.vector.VectorSupport.VectorMask permits AbstractMask { VectorMask(boolean[] bits) { super(bits); } /** diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorMathLibrary.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorMathLibrary.java index 1c1cfcc78c7..823cebd85a9 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorMathLibrary.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorMathLibrary.java @@ -42,7 +42,7 @@ import static jdk.internal.vm.vector.Utils.debug; * A wrapper for native vector math libraries bundled with the JDK (SVML and SLEEF). * Binds vector operations to native implementations provided by the libraries. */ -/*package-private*/ class VectorMathLibrary { +/*package-private*/ final class VectorMathLibrary { private static final SymbolLookup LOOKUP = SymbolLookup.loaderLookup(); interface Library { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorOperators.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorOperators.java index 84009c55ac9..2f2d33ab130 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorOperators.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorOperators.java @@ -24,13 +24,12 @@ */ package jdk.incubator.vector; -import java.util.function.IntFunction; -import java.util.HashMap; import java.util.ArrayList; +import java.util.HashMap; +import java.util.function.IntFunction; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.annotation.Stable; - import jdk.internal.vm.vector.VectorSupport; import static jdk.internal.vm.vector.Utils.isNonCapturingLambda; @@ -115,7 +114,7 @@ import static jdk.internal.vm.vector.Utils.isNonCapturingLambda; * operations on individual lane values. * */ -public abstract class VectorOperators { +public final class VectorOperators { private VectorOperators() { } /** @@ -131,12 +130,9 @@ public abstract class VectorOperators { * @see VectorOperators.Test Test * @see VectorOperators.Conversion Conversion * - * @apiNote - * User code should not implement this interface. A future release of - * this type may restrict implementations to be members of the same - * package. + * @sealedGraph */ - public interface Operator { + public sealed interface Operator { /** * Returns the symbolic name of this operator, * as a constant in {@link VectorOperators}. @@ -235,13 +231,8 @@ public abstract class VectorOperators { * usable in expressions like {@code w = v0.}{@link * Vector#lanewise(VectorOperators.Unary) * lanewise}{@code (NEG)}. - * - * @apiNote - * User code should not implement this interface. A future release of - * this type may restrict implementations to be members of the same - * package. */ - public interface Unary extends Operator { + public sealed interface Unary extends Operator { } /** @@ -252,12 +243,9 @@ public abstract class VectorOperators { * Vector#lanewise(VectorOperators.Binary,Vector) * lanewise}{@code (ADD, v1)}. * - * @apiNote - * User code should not implement this interface. A future release of - * this type may restrict implementations to be members of the same - * package. + * @sealedGraph */ - public interface Binary extends Operator { + public sealed interface Binary extends Operator { } /** @@ -267,13 +255,8 @@ public abstract class VectorOperators { * usable in expressions like {@code w = v0.}{@link * Vector#lanewise(VectorOperators.Ternary,Vector,Vector) * lanewise}{@code (FMA, v1, v2)}. - * - * @apiNote - * User code should not implement this interface. A future release of - * this type may restrict implementations to be members of the same - * package. */ - public interface Ternary extends Operator { + public sealed interface Ternary extends Operator { } /** @@ -283,13 +266,8 @@ public abstract class VectorOperators { * usable in expressions like {@code e = v0.}{@link * IntVector#reduceLanes(VectorOperators.Associative) * reduceLanes}{@code (ADD)}. - * - * @apiNote - * User code should not implement this interface. A future release of - * this type may restrict implementations to be members of the same - * package. */ - public interface Associative extends Binary { + public sealed interface Associative extends Binary { } /** @@ -299,13 +277,8 @@ public abstract class VectorOperators { * usable in expressions like {@code m = v0.}{@link * FloatVector#test(VectorOperators.Test) * test}{@code (IS_FINITE)}. - * - * @apiNote - * User code should not implement this interface. A future release of - * this type may restrict implementations to be members of the same - * package. */ - public interface Test extends Operator { + public sealed interface Test extends Operator { } /** @@ -315,13 +288,8 @@ public abstract class VectorOperators { * usable in expressions like {@code m = v0.}{@link * Vector#compare(VectorOperators.Comparison,Vector) * compare}{@code (LT, v1)}. - * - * @apiNote - * User code should not implement this interface. A future release of - * this type may restrict implementations to be members of the same - * package. */ - public interface Comparison extends Operator { + public sealed interface Comparison extends Operator { } /** @@ -336,13 +304,8 @@ public abstract class VectorOperators { * domain type (the input lane type) * @param the boxed element type for the conversion * range type (the output lane type) - * - * @apiNote - * User code should not implement this interface. A future release of - * this type may restrict implementations to be members of the same - * package. */ - public interface Conversion extends Operator { + public sealed interface Conversion extends Operator { /** * The domain of this conversion, a primitive type. * @return the domain of this conversion @@ -831,7 +794,7 @@ public abstract class VectorOperators { kind, dom, ran); } - private abstract static class OperatorImpl implements Operator { + private abstract static sealed class OperatorImpl implements Operator { private final String symName; private final String opName; private final int opInfo; @@ -956,35 +919,35 @@ public abstract class VectorOperators { } } - private static class UnaryImpl extends OperatorImpl implements Unary { + private static final class UnaryImpl extends OperatorImpl implements Unary { private UnaryImpl(String symName, String opName, int opInfo) { super(symName, opName, opInfo); assert((opInfo & VO_ARITY_MASK) == VO_UNARY); } } - private static class BinaryImpl extends OperatorImpl implements Binary { + private static sealed class BinaryImpl extends OperatorImpl implements Binary permits AssociativeImpl { private BinaryImpl(String symName, String opName, int opInfo) { super(symName, opName, opInfo); assert((opInfo & VO_ARITY_MASK) == VO_BINARY); } } - private static class TernaryImpl extends OperatorImpl implements Ternary { + private static final class TernaryImpl extends OperatorImpl implements Ternary { private TernaryImpl(String symName, String opName, int opInfo) { super(symName, opName, opInfo); assert((opInfo & VO_ARITY_MASK) == VO_TERNARY); } } - private static class AssociativeImpl extends BinaryImpl implements Associative { + private static final class AssociativeImpl extends BinaryImpl implements Associative { private AssociativeImpl(String symName, String opName, int opInfo) { super(symName, opName, opInfo); } } /*package-private*/ - static + static final class ConversionImpl extends OperatorImpl implements Conversion { private ConversionImpl(String symName, String opName, int opInfo, @@ -1260,7 +1223,7 @@ public abstract class VectorOperators { } } - private static class TestImpl extends OperatorImpl implements Test { + private static final class TestImpl extends OperatorImpl implements Test { private TestImpl(String symName, String opName, int opInfo) { super(symName, opName, opInfo); assert((opInfo & VO_ARITY_MASK) == VO_UNARY); @@ -1272,7 +1235,7 @@ public abstract class VectorOperators { } } - private static class ComparisonImpl extends OperatorImpl implements Comparison { + private static final class ComparisonImpl extends OperatorImpl implements Comparison { private ComparisonImpl(String symName, String opName, int opInfo) { super(symName, opName, opInfo); assert((opInfo & VO_ARITY_MASK) == VO_BINARY); diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorShuffle.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorShuffle.java index 9cde9d2315c..5da38a25e16 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorShuffle.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorShuffle.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -136,7 +136,7 @@ import java.util.function.IntUnaryOperator; * the element type of a vector */ @SuppressWarnings("exports") -public abstract class VectorShuffle extends jdk.internal.vm.vector.VectorSupport.VectorShuffle { +public abstract sealed class VectorShuffle extends jdk.internal.vm.vector.VectorSupport.VectorShuffle permits AbstractShuffle { VectorShuffle(Object indices) { super(indices); } diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorSpecies.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorSpecies.java index e80bbf231ea..4c3ef3f471d 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorSpecies.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorSpecies.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * 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,11 +36,6 @@ import java.util.function.IntUnaryOperator; * of element type ({@code ETYPE}) * and {@link VectorShape shape}. * - * @apiNote - * User code should not implement this interface. A future release of - * this type may restrict implementations to be members of the same - * package. - * * @implNote * The string representation of an instance of this interface will * be of the form "Species[ETYPE, VLENGTH, SHAPE]", where {@code @@ -57,7 +52,7 @@ import java.util.function.IntUnaryOperator; * @param the boxed version of {@code ETYPE}, * the element type of a vector */ -public interface VectorSpecies { +public sealed interface VectorSpecies permits AbstractSpecies { /** * Returns the primitive element type of vectors of this * species. 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 95fe8ca35db..b3c5bfac302 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 @@ -49,7 +49,8 @@ import static jdk.incubator.vector.VectorOperators.*; * {@code $type$} values. */ @SuppressWarnings("cast") // warning: redundant cast -public abstract class $abstractvectortype$ extends AbstractVector<$Boxtype$> { +public abstract sealed class $abstractvectortype$ extends AbstractVector<$Boxtype$> + permits $Type$Vector64, $Type$Vector128, $Type$Vector256, $Type$Vector512, $Type$VectorMax { $abstractvectortype$($type$[] vec) { super(vec); diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-VectorBits.java.template b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-VectorBits.java.template index 35041a0b70f..d66d22cab19 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-VectorBits.java.template +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-VectorBits.java.template @@ -25,7 +25,9 @@ package jdk.incubator.vector; import java.lang.foreign.MemorySegment; +#if[longOrDouble] import java.lang.foreign.ValueLayout; +#end[longOrDouble] import java.nio.ByteOrder; import java.util.Arrays; import java.util.Objects; @@ -35,9 +37,8 @@ import jdk.internal.ValueBased; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.vector.VectorSupport; -import static jdk.internal.vm.vector.VectorSupport.*; - import static jdk.incubator.vector.VectorOperators.*; +import static jdk.internal.vm.vector.VectorSupport.*; #warn This file is preprocessed before being compiled @@ -389,7 +390,7 @@ final class $vectortype$ extends $abstractvectortype$ { @Override @ForceInline public final $shuffletype$ toShuffle() { - return ($shuffletype$) toShuffle(vspecies(), false); + return ($shuffletype$) toShuffle(VSPECIES, false); } // Specialized unary testing @@ -905,7 +906,7 @@ final class $vectortype$ extends $abstractvectortype$ { @Override $masktype$ uOp(MUnOp f) { - boolean[] res = new boolean[vspecies().laneCount()]; + boolean[] res = new boolean[VSPECIES.laneCount()]; boolean[] bits = getBits(); for (int i = 0; i < res.length; i++) { res[i] = f.apply(i, bits[i]); @@ -915,7 +916,7 @@ final class $vectortype$ extends $abstractvectortype$ { @Override $masktype$ bOp(VectorMask<$Boxtype$> m, MBinOp f) { - boolean[] res = new boolean[vspecies().laneCount()]; + boolean[] res = new boolean[VSPECIES.laneCount()]; boolean[] bits = getBits(); boolean[] mbits = (($masktype$)m).getBits(); for (int i = 0; i < res.length; i++) { @@ -1065,16 +1066,16 @@ final class $vectortype$ extends $abstractvectortype$ { @ForceInline public boolean anyTrue() { return VectorSupport.test(BT_ne, $masktype$.class, LANEBITS_TYPE_ORDINAL, VLENGTH, - this, vspecies().maskAll(true), - (m, __) -> anyTrueHelper((($masktype$)m).getBits())); + this, VSPECIES.maskAll(true), + (m, _) -> anyTrueHelper((($masktype$)m).getBits())); } @Override @ForceInline public boolean allTrue() { return VectorSupport.test(BT_overflow, $masktype$.class, LANEBITS_TYPE_ORDINAL, VLENGTH, - this, vspecies().maskAll(true), - (m, __) -> allTrueHelper((($masktype$)m).getBits())); + this, VSPECIES.maskAll(true), + (m, _) -> allTrueHelper((($masktype$)m).getBits())); } @ForceInline @@ -1082,7 +1083,7 @@ final class $vectortype$ extends $abstractvectortype$ { static $masktype$ maskAll(boolean bit) { return VectorSupport.fromBitsCoerced($masktype$.class, LANEBITS_TYPE_ORDINAL, VLENGTH, (bit ? -1 : 0), MODE_BROADCAST, null, - (v, __) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); + (v, _) -> (v != 0 ? TRUE_MASK : FALSE_MASK)); } private static final $masktype$ TRUE_MASK = new $masktype$(true); private static final $masktype$ FALSE_MASK = new $masktype$(false); @@ -1147,7 +1148,7 @@ final class $vectortype$ extends $abstractvectortype$ { @Override @ForceInline public $vectortype$ toVector() { - return ($vectortype$) toBitsVector().castShape(vspecies(), 0); + return ($vectortype$) toBitsVector().castShape(VSPECIES, 0); } #else[FP] @Override @@ -1165,7 +1166,7 @@ final class $vectortype$ extends $abstractvectortype$ { @Override $bitsvectortype$ toBitsVector0() { - return (($bitsvectortype$) vspecies().asIntegral().dummyVector()).vectorFactory(indices()); + return (($bitsvectortype$) VSPECIES.asIntegral().dummyVector()).vectorFactory(indices()); } @Override @@ -1301,7 +1302,7 @@ final class $vectortype$ extends $abstractvectortype$ { @ForceInline public final $masktype$ laneIsValid() { return ($masktype$) toBitsVector().compare(VectorOperators.GE, 0) - .cast(vspecies()); + .cast(VSPECIES); } @ForceInline @@ -1310,10 +1311,10 @@ final class $vectortype$ extends $abstractvectortype$ { $shuffletype$ concreteShuffle = ($shuffletype$) shuffle; #if[FP] return ($shuffletype$) toBitsVector().rearrange(concreteShuffle.cast($Bitstype$Vector.SPECIES_$BITS$)) - .toShuffle(vspecies(), false); + .toShuffle(VSPECIES, false); #else[FP] return ($shuffletype$) toBitsVector().rearrange(concreteShuffle) - .toShuffle(vspecies(), false); + .toShuffle(VSPECIES, false); #end[FP] } @@ -1327,7 +1328,7 @@ final class $vectortype$ extends $abstractvectortype$ { v = ($bitsvectortype$) v.blend(v.lanewise(VectorOperators.ADD, length()), v.compare(VectorOperators.LT, 0)); } - return ($shuffletype$) v.toShuffle(vspecies(), false); + return ($shuffletype$) v.toShuffle(VSPECIES, false); } private static $bitstype$[] prepare(int[] indices, int offset) { From 5164fbc9f841bec1ad4fb33b11a3ad11489d49d8 Mon Sep 17 00:00:00 2001 From: Rui Li Date: Thu, 26 Mar 2026 23:47:12 +0000 Subject: [PATCH 064/359] 8374191: Shenandoah: Consider an assert in get_object_age Reviewed-by: wkemper --- src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp index 02f2beaf4e0..6d77cccaa6a 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp @@ -344,6 +344,8 @@ uint ShenandoahHeap::get_object_age(oop obj) { } if (w.has_monitor()) { w = w.monitor()->header(); + } else { + assert(!w.has_displaced_mark_helper(), "Mark word should not be displaced"); } assert(w.age() <= markWord::max_age, "Impossible!"); return w.age(); From 1a9965555477ee2a6cb65e91ef54ed608e4bee66 Mon Sep 17 00:00:00 2001 From: Mohamed Issa Date: Fri, 27 Mar 2026 04:56:30 +0000 Subject: [PATCH 065/359] 8378295: Update scalar AVX10 floating point min/max definitions Reviewed-by: sviswanathan, mhaessig, jbhateja, sparasa --- src/hotspot/cpu/x86/assembler_x86.cpp | 160 ++++---- src/hotspot/cpu/x86/assembler_x86.hpp | 34 +- src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp | 77 +++- src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp | 26 +- src/hotspot/cpu/x86/macroAssembler_x86.cpp | 46 ++- src/hotspot/cpu/x86/macroAssembler_x86.hpp | 22 +- src/hotspot/cpu/x86/x86.ad | 353 +++++++++--------- .../math/TestFpMinMaxReductions.java | 32 +- .../compiler/lib/ir_framework/IRNode.java | 36 +- .../vector/Float16OperationsBenchmark.java | 38 +- .../bench/vm/compiler/FpMinMaxIntrinsics.java | 171 ++++++++- 11 files changed, 650 insertions(+), 345 deletions(-) diff --git a/src/hotspot/cpu/x86/assembler_x86.cpp b/src/hotspot/cpu/x86/assembler_x86.cpp index 38a28a6ec49..a4f2968f0d1 100644 --- a/src/hotspot/cpu/x86/assembler_x86.cpp +++ b/src/hotspot/cpu/x86/assembler_x86.cpp @@ -3472,7 +3472,7 @@ void Assembler::vmovdqu(XMMRegister dst, XMMRegister src) { emit_int16(0x6F, (0xC0 | encode)); } -void Assembler::vmovw(XMMRegister dst, Register src) { +void Assembler::evmovw(XMMRegister dst, Register src) { assert(VM_Version::supports_avx512_fp16(), "requires AVX512-FP16"); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_is_evex_instruction(); @@ -3480,7 +3480,7 @@ void Assembler::vmovw(XMMRegister dst, Register src) { emit_int16(0x6E, (0xC0 | encode)); } -void Assembler::vmovw(Register dst, XMMRegister src) { +void Assembler::evmovw(Register dst, XMMRegister src) { assert(VM_Version::supports_avx512_fp16(), "requires AVX512-FP16"); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_is_evex_instruction(); @@ -3488,6 +3488,36 @@ void Assembler::vmovw(Register dst, XMMRegister src) { emit_int16(0x7E, (0xC0 | encode)); } +void Assembler::evmovw(XMMRegister dst, Address src) { + assert(VM_Version::supports_avx10_2(), ""); + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_16bit); + attributes.set_is_evex_instruction(); + vex_prefix(src, 0, dst->encoding(), VEX_SIMD_F3, VEX_OPCODE_MAP5, &attributes); + emit_int8(0x6E); + emit_operand(dst, src, 0); +} + +void Assembler::evmovw(Address dst, XMMRegister src) { + assert(VM_Version::supports_avx10_2(), ""); + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_16bit); + attributes.set_is_evex_instruction(); + vex_prefix(dst, 0, src->encoding(), VEX_SIMD_F3, VEX_OPCODE_MAP5, &attributes); + emit_int8(0x7E); + emit_operand(src, dst, 0); +} + +void Assembler::evmovw(XMMRegister dst, XMMRegister src) { + assert(VM_Version::supports_avx10_2(), ""); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_is_evex_instruction(); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F3, VEX_OPCODE_MAP5, &attributes); + emit_int16(0x6E, (0xC0 | encode)); +} + void Assembler::vmovdqu(XMMRegister dst, Address src) { assert(UseAVX > 0, ""); InstructionMark im(this); @@ -7310,6 +7340,42 @@ void Assembler::etzcntq(Register dst, Address src, bool no_flags) { emit_operand(dst, src, 0); } +void Assembler::evucomish(XMMRegister dst, Address src) { + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_16bit); + attributes.set_is_evex_instruction(); + vex_prefix(src, 0, dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_MAP5, &attributes); + emit_int8(0x2E); + emit_operand(dst, src, 0); +} + +void Assembler::evucomish(XMMRegister dst, XMMRegister src) { + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_is_evex_instruction(); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_MAP5, &attributes); + emit_int16(0x2E, (0xC0 | encode)); +} + +void Assembler::evucomxsh(XMMRegister dst, Address src) { + assert(VM_Version::supports_avx10_2(), ""); + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_16bit); + attributes.set_is_evex_instruction(); + vex_prefix(src, 0, dst->encoding(), VEX_SIMD_F3, VEX_OPCODE_MAP5, &attributes); + emit_int8(0x2E); + emit_operand(dst, src, 0); +} + +void Assembler::evucomxsh(XMMRegister dst, XMMRegister src) { + assert(VM_Version::supports_avx10_2(), ""); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_is_evex_instruction(); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F3, VEX_OPCODE_MAP5, &attributes); + emit_int16(0x2E, (0xC0 | encode)); +} + void Assembler::ucomisd(XMMRegister dst, Address src) { InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); @@ -7327,7 +7393,7 @@ void Assembler::ucomisd(XMMRegister dst, XMMRegister src) { emit_int16(0x2E, (0xC0 | encode)); } -void Assembler::vucomxsd(XMMRegister dst, Address src) { +void Assembler::evucomxsd(XMMRegister dst, Address src) { assert(VM_Version::supports_avx10_2(), ""); InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); @@ -7338,7 +7404,7 @@ void Assembler::vucomxsd(XMMRegister dst, Address src) { emit_operand(dst, src, 0); } -void Assembler::vucomxsd(XMMRegister dst, XMMRegister src) { +void Assembler::evucomxsd(XMMRegister dst, XMMRegister src) { assert(VM_Version::supports_avx10_2(), ""); InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_is_evex_instruction(); @@ -7361,7 +7427,7 @@ void Assembler::ucomiss(XMMRegister dst, XMMRegister src) { emit_int16(0x2E, (0xC0 | encode)); } -void Assembler::vucomxss(XMMRegister dst, Address src) { +void Assembler::evucomxss(XMMRegister dst, Address src) { assert(VM_Version::supports_avx10_2(), ""); InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); @@ -7372,7 +7438,7 @@ void Assembler::vucomxss(XMMRegister dst, Address src) { emit_operand(dst, src, 0); } -void Assembler::vucomxss(XMMRegister dst, XMMRegister src) { +void Assembler::evucomxss(XMMRegister dst, XMMRegister src) { assert(VM_Version::supports_avx10_2(), ""); InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_is_evex_instruction(); @@ -8411,30 +8477,6 @@ void Assembler::vmulsh(XMMRegister dst, XMMRegister nds, XMMRegister src) { emit_int16(0x59, (0xC0 | encode)); } -void Assembler::vmaxsh(XMMRegister dst, XMMRegister nds, XMMRegister src) { - assert(VM_Version::supports_avx512_fp16(), "requires AVX512-FP16"); - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - attributes.set_is_evex_instruction(); - int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_F3, VEX_OPCODE_MAP5, &attributes); - emit_int16(0x5F, (0xC0 | encode)); -} - -void Assembler::eminmaxsh(XMMRegister dst, XMMRegister nds, XMMRegister src, int imm8) { - assert(VM_Version::supports_avx10_2(), ""); - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - attributes.set_is_evex_instruction(); - int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3A, &attributes); - emit_int24(0x53, (0xC0 | encode), imm8); -} - -void Assembler::vminsh(XMMRegister dst, XMMRegister nds, XMMRegister src) { - assert(VM_Version::supports_avx512_fp16(), "requires AVX512-FP16"); - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - attributes.set_is_evex_instruction(); - int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_F3, VEX_OPCODE_MAP5, &attributes); - emit_int16(0x5D, (0xC0 | encode)); -} - void Assembler::vsqrtsh(XMMRegister dst, XMMRegister src) { assert(VM_Version::supports_avx512_fp16(), "requires AVX512-FP16"); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); @@ -13369,48 +13411,38 @@ bool Assembler::is_demotable(bool no_flags, int dst_enc, int nds_enc) { return (!no_flags && dst_enc == nds_enc); } -void Assembler::vmaxss(XMMRegister dst, XMMRegister nds, XMMRegister src) { - assert(VM_Version::supports_avx(), ""); - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); - emit_int16(0x5F, (0xC0 | encode)); -} - -void Assembler::vmaxsd(XMMRegister dst, XMMRegister nds, XMMRegister src) { - assert(VM_Version::supports_avx(), ""); - InstructionAttr attributes(AVX_128bit, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - attributes.set_rex_vex_w_reverted(); - int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); - emit_int16(0x5F, (0xC0 | encode)); -} - -void Assembler::vminss(XMMRegister dst, XMMRegister nds, XMMRegister src) { - assert(VM_Version::supports_avx(), ""); - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); - emit_int16(0x5D, (0xC0 | encode)); -} - -void Assembler::eminmaxss(XMMRegister dst, XMMRegister nds, XMMRegister src, int imm8) { +void Assembler::evminmaxsh(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int imm8) { assert(VM_Version::supports_avx10_2(), ""); - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); attributes.set_is_evex_instruction(); + attributes.set_embedded_opmask_register_specifier(mask); + if (merge) { + attributes.reset_is_clear_context(); + } + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3A, &attributes); + emit_int24(0x53, (0xC0 | encode), imm8); +} + +void Assembler::evminmaxss(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int imm8) { + assert(VM_Version::supports_avx10_2(), ""); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); + attributes.set_is_evex_instruction(); + attributes.set_embedded_opmask_register_specifier(mask); + if (merge) { + attributes.reset_is_clear_context(); + } int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); emit_int24(0x53, (0xC0 | encode), imm8); } -void Assembler::vminsd(XMMRegister dst, XMMRegister nds, XMMRegister src) { - assert(VM_Version::supports_avx(), ""); - InstructionAttr attributes(AVX_128bit, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - attributes.set_rex_vex_w_reverted(); - int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); - emit_int16(0x5D, (0xC0 | encode)); -} - -void Assembler::eminmaxsd(XMMRegister dst, XMMRegister nds, XMMRegister src, int imm8) { +void Assembler::evminmaxsd(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int imm8) { assert(VM_Version::supports_avx10_2(), ""); - InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); attributes.set_is_evex_instruction(); + attributes.set_embedded_opmask_register_specifier(mask); + if (merge) { + attributes.reset_is_clear_context(); + } int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); emit_int24(0x53, (0xC0 | encode), imm8); } diff --git a/src/hotspot/cpu/x86/assembler_x86.hpp b/src/hotspot/cpu/x86/assembler_x86.hpp index 57a5e25d7a6..98684752b0c 100644 --- a/src/hotspot/cpu/x86/assembler_x86.hpp +++ b/src/hotspot/cpu/x86/assembler_x86.hpp @@ -1694,8 +1694,11 @@ private: void movsbl(Register dst, Address src); void movsbl(Register dst, Register src); - void vmovw(XMMRegister dst, Register src); - void vmovw(Register dst, XMMRegister src); + void evmovw(XMMRegister dst, Register src); + void evmovw(Register dst, XMMRegister src); + void evmovw(XMMRegister dst, Address src); + void evmovw(Address dst, XMMRegister src); + void evmovw(XMMRegister dst, XMMRegister src); void movsbq(Register dst, Address src); void movsbq(Register dst, Register src); @@ -2329,17 +2332,23 @@ private: void tzcntq(Register dst, Address src); void etzcntq(Register dst, Address src, bool no_flags); + // Unordered Compare Scalar Half-Precision Floating-Point Values and set EFLAGS + void evucomish(XMMRegister dst, Address src); + void evucomish(XMMRegister dst, XMMRegister src); + void evucomxsh(XMMRegister dst, Address src); + void evucomxsh(XMMRegister dst, XMMRegister src); + // Unordered Compare Scalar Double-Precision Floating-Point Values and set EFLAGS void ucomisd(XMMRegister dst, Address src); void ucomisd(XMMRegister dst, XMMRegister src); - void vucomxsd(XMMRegister dst, Address src); - void vucomxsd(XMMRegister dst, XMMRegister src); + void evucomxsd(XMMRegister dst, Address src); + void evucomxsd(XMMRegister dst, XMMRegister src); // Unordered Compare Scalar Single-Precision Floating-Point Values and set EFLAGS void ucomiss(XMMRegister dst, Address src); void ucomiss(XMMRegister dst, XMMRegister src); - void vucomxss(XMMRegister dst, Address src); - void vucomxss(XMMRegister dst, XMMRegister src); + void evucomxss(XMMRegister dst, Address src); + void evucomxss(XMMRegister dst, XMMRegister src); void xabort(int8_t imm8); @@ -2417,11 +2426,6 @@ private: void vsubss(XMMRegister dst, XMMRegister nds, Address src); void vsubss(XMMRegister dst, XMMRegister nds, XMMRegister src); - void vmaxss(XMMRegister dst, XMMRegister nds, XMMRegister src); - void vmaxsd(XMMRegister dst, XMMRegister nds, XMMRegister src); - void vminss(XMMRegister dst, XMMRegister nds, XMMRegister src); - void vminsd(XMMRegister dst, XMMRegister nds, XMMRegister src); - void sarxl(Register dst, Register src1, Register src2); void sarxl(Register dst, Address src1, Register src2); void sarxq(Register dst, Register src1, Register src2); @@ -2552,8 +2556,6 @@ private: void vsubsh(XMMRegister dst, XMMRegister nds, XMMRegister src); void vmulsh(XMMRegister dst, XMMRegister nds, XMMRegister src); void vdivsh(XMMRegister dst, XMMRegister nds, XMMRegister src); - void vmaxsh(XMMRegister dst, XMMRegister nds, XMMRegister src); - void vminsh(XMMRegister dst, XMMRegister nds, XMMRegister src); void vsqrtsh(XMMRegister dst, XMMRegister src); void vfmadd132sh(XMMRegister dst, XMMRegister src1, XMMRegister src2); @@ -2790,9 +2792,9 @@ private: void vminpd(XMMRegister dst, XMMRegister src1, XMMRegister src2, int vector_len); // AVX10.2 floating point minmax instructions - void eminmaxsh(XMMRegister dst, XMMRegister nds, XMMRegister src, int imm8); - void eminmaxss(XMMRegister dst, XMMRegister nds, XMMRegister src, int imm8); - void eminmaxsd(XMMRegister dst, XMMRegister nds, XMMRegister src, int imm8); + void evminmaxsh(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int imm8); + void evminmaxss(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int imm8); + void evminmaxsd(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int imm8); void evminmaxph(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int imm8, int vector_len); void evminmaxph(XMMRegister dst, KRegister mask, XMMRegister nds, Address src, bool merge, int imm8, int vector_len); void evminmaxps(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int imm8, int vector_len); diff --git a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp index 5b5fb02967c..c1df726b5ba 100644 --- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp @@ -1037,8 +1037,8 @@ void C2_MacroAssembler::evminmax_fp(int opcode, BasicType elem_bt, } } -void C2_MacroAssembler::vminmax_fp(int opc, BasicType elem_bt, XMMRegister dst, KRegister mask, - XMMRegister src1, XMMRegister src2, int vlen_enc) { +void C2_MacroAssembler::vminmax_fp_avx10_2(int opc, BasicType elem_bt, XMMRegister dst, KRegister mask, + XMMRegister src1, XMMRegister src2, int vlen_enc) { assert(opc == Op_MinV || opc == Op_MinReductionV || opc == Op_MaxV || opc == Op_MaxReductionV, "sanity"); @@ -1052,6 +1052,21 @@ void C2_MacroAssembler::vminmax_fp(int opc, BasicType elem_bt, XMMRegister dst, } } +void C2_MacroAssembler::sminmax_fp_avx10_2(int opc, BasicType elem_bt, XMMRegister dst, KRegister mask, + XMMRegister src1, XMMRegister src2) { + assert(opc == Op_MinF || opc == Op_MaxF || + opc == Op_MinD || opc == Op_MaxD, "sanity"); + + int imm8 = (opc == Op_MinF || opc == Op_MinD) ? AVX10_2_MINMAX_MIN_COMPARE_SIGN + : AVX10_2_MINMAX_MAX_COMPARE_SIGN; + if (elem_bt == T_FLOAT) { + evminmaxss(dst, mask, src1, src2, true, imm8); + } else { + assert(elem_bt == T_DOUBLE, ""); + evminmaxsd(dst, mask, src1, src2, true, imm8); + } +} + // Float/Double signum void C2_MacroAssembler::signum_fp(int opcode, XMMRegister dst, XMMRegister zero, XMMRegister one) { assert(opcode == Op_SignumF || opcode == Op_SignumD, "sanity"); @@ -1063,7 +1078,7 @@ void C2_MacroAssembler::signum_fp(int opcode, XMMRegister dst, XMMRegister zero, // If other floating point comparison instructions used, ZF=1 for equal and unordered cases if (opcode == Op_SignumF) { if (VM_Version::supports_avx10_2()) { - vucomxss(dst, zero); + evucomxss(dst, zero); jcc(Assembler::negative, DONE_LABEL); } else { ucomiss(dst, zero); @@ -1074,7 +1089,7 @@ void C2_MacroAssembler::signum_fp(int opcode, XMMRegister dst, XMMRegister zero, xorps(dst, ExternalAddress(StubRoutines::x86::vector_float_sign_flip()), noreg); } else if (opcode == Op_SignumD) { if (VM_Version::supports_avx10_2()) { - vucomxsd(dst, zero); + evucomxsd(dst, zero); jcc(Assembler::negative, DONE_LABEL); } else { ucomisd(dst, zero); @@ -2400,7 +2415,7 @@ void C2_MacroAssembler::reduceFloatMinMax(int opcode, int vlen, bool is_dst_vali } if (VM_Version::supports_avx10_2()) { - vminmax_fp(opcode, T_FLOAT, wdst, k0, wtmp, wsrc, vlen_enc); + vminmax_fp_avx10_2(opcode, T_FLOAT, wdst, k0, wtmp, wsrc, vlen_enc); } else { vminmax_fp(opcode, T_FLOAT, wdst, wtmp, wsrc, tmp, atmp, btmp, vlen_enc); } @@ -2409,7 +2424,7 @@ void C2_MacroAssembler::reduceFloatMinMax(int opcode, int vlen, bool is_dst_vali } if (is_dst_valid) { if (VM_Version::supports_avx10_2()) { - vminmax_fp(opcode, T_FLOAT, dst, k0, wdst, dst, Assembler::AVX_128bit); + vminmax_fp_avx10_2(opcode, T_FLOAT, dst, k0, wdst, dst, Assembler::AVX_128bit); } else { vminmax_fp(opcode, T_FLOAT, dst, wdst, dst, tmp, atmp, btmp, Assembler::AVX_128bit); } @@ -2440,7 +2455,7 @@ void C2_MacroAssembler::reduceDoubleMinMax(int opcode, int vlen, bool is_dst_val } if (VM_Version::supports_avx10_2()) { - vminmax_fp(opcode, T_DOUBLE, wdst, k0, wtmp, wsrc, vlen_enc); + vminmax_fp_avx10_2(opcode, T_DOUBLE, wdst, k0, wtmp, wsrc, vlen_enc); } else { vminmax_fp(opcode, T_DOUBLE, wdst, wtmp, wsrc, tmp, atmp, btmp, vlen_enc); } @@ -2451,7 +2466,7 @@ void C2_MacroAssembler::reduceDoubleMinMax(int opcode, int vlen, bool is_dst_val if (is_dst_valid) { if (VM_Version::supports_avx10_2()) { - vminmax_fp(opcode, T_DOUBLE, dst, k0, wdst, dst, Assembler::AVX_128bit); + vminmax_fp_avx10_2(opcode, T_DOUBLE, dst, k0, wdst, dst, Assembler::AVX_128bit); } else { vminmax_fp(opcode, T_DOUBLE, dst, wdst, dst, tmp, atmp, btmp, Assembler::AVX_128bit); } @@ -7061,13 +7076,25 @@ void C2_MacroAssembler::evfp16ph(int opcode, XMMRegister dst, XMMRegister src1, } } -void C2_MacroAssembler::scalar_max_min_fp16(int opcode, XMMRegister dst, XMMRegister src1, XMMRegister src2, - KRegister ktmp, XMMRegister xtmp1, XMMRegister xtmp2) { - vector_max_min_fp16(opcode, dst, src1, src2, ktmp, xtmp1, xtmp2, Assembler::AVX_128bit); +void C2_MacroAssembler::sminmax_fp16(int opcode, XMMRegister dst, XMMRegister src1, XMMRegister src2, + KRegister ktmp, XMMRegister xtmp1, XMMRegister xtmp2) { + vminmax_fp16(opcode, dst, src1, src2, ktmp, xtmp1, xtmp2, Assembler::AVX_128bit); } -void C2_MacroAssembler::vector_max_min_fp16(int opcode, XMMRegister dst, XMMRegister src1, XMMRegister src2, - KRegister ktmp, XMMRegister xtmp1, XMMRegister xtmp2, int vlen_enc) { +void C2_MacroAssembler::sminmax_fp16_avx10_2(int opcode, XMMRegister dst, XMMRegister src1, XMMRegister src2, + KRegister ktmp) { + if (opcode == Op_MaxHF) { + // dst = max(src1, src2) + evminmaxsh(dst, ktmp, src1, src2, true, AVX10_2_MINMAX_MAX_COMPARE_SIGN); + } else { + assert(opcode == Op_MinHF, ""); + // dst = min(src1, src2) + evminmaxsh(dst, ktmp, src1, src2, true, AVX10_2_MINMAX_MIN_COMPARE_SIGN); + } +} + +void C2_MacroAssembler::vminmax_fp16(int opcode, XMMRegister dst, XMMRegister src1, XMMRegister src2, + KRegister ktmp, XMMRegister xtmp1, XMMRegister xtmp2, int vlen_enc) { if (opcode == Op_MaxVHF || opcode == Op_MaxHF) { // Move sign bits of src2 to mask register. evpmovw2m(ktmp, src2, vlen_enc); @@ -7110,3 +7137,27 @@ void C2_MacroAssembler::vector_max_min_fp16(int opcode, XMMRegister dst, XMMRegi Assembler::evmovdquw(dst, ktmp, xtmp1, true, vlen_enc); } } + +void C2_MacroAssembler::vminmax_fp16_avx10_2(int opcode, XMMRegister dst, XMMRegister src1, XMMRegister src2, + KRegister ktmp, int vlen_enc) { + if (opcode == Op_MaxVHF) { + // dst = max(src1, src2) + evminmaxph(dst, ktmp, src1, src2, true, AVX10_2_MINMAX_MAX_COMPARE_SIGN, vlen_enc); + } else { + assert(opcode == Op_MinVHF, ""); + // dst = min(src1, src2) + evminmaxph(dst, ktmp, src1, src2, true, AVX10_2_MINMAX_MIN_COMPARE_SIGN, vlen_enc); + } +} + +void C2_MacroAssembler::vminmax_fp16_avx10_2(int opcode, XMMRegister dst, XMMRegister src1, Address src2, + KRegister ktmp, int vlen_enc) { + if (opcode == Op_MaxVHF) { + // dst = max(src1, src2) + evminmaxph(dst, ktmp, src1, src2, true, AVX10_2_MINMAX_MAX_COMPARE_SIGN, vlen_enc); + } else { + assert(opcode == Op_MinVHF, ""); + // dst = min(src1, src2) + evminmaxph(dst, ktmp, src1, src2, true, AVX10_2_MINMAX_MIN_COMPARE_SIGN, vlen_enc); + } +} diff --git a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp index 6d8b0ceaebe..4e77f8a5f6f 100644 --- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * 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,8 +67,11 @@ public: XMMRegister tmp, XMMRegister atmp, XMMRegister btmp, int vlen_enc); - void vminmax_fp(int opc, BasicType elem_bt, XMMRegister dst, KRegister mask, - XMMRegister src1, XMMRegister src2, int vlen_enc); + void vminmax_fp_avx10_2(int opc, BasicType elem_bt, XMMRegister dst, KRegister mask, + XMMRegister src1, XMMRegister src2, int vlen_enc); + + void sminmax_fp_avx10_2(int opc, BasicType elem_bt, XMMRegister dst, KRegister mask, + XMMRegister src1, XMMRegister src2); void vpuminmaxq(int opcode, XMMRegister dst, XMMRegister src1, XMMRegister src2, XMMRegister xtmp1, XMMRegister xtmp2, int vlen_enc); @@ -576,11 +579,20 @@ public: void evfp16ph(int opcode, XMMRegister dst, XMMRegister src1, Address src2, int vlen_enc); - void vector_max_min_fp16(int opcode, XMMRegister dst, XMMRegister src1, XMMRegister src2, - KRegister ktmp, XMMRegister xtmp1, XMMRegister xtmp2, int vlen_enc); + void vminmax_fp16(int opcode, XMMRegister dst, XMMRegister src1, XMMRegister src2, + KRegister ktmp, XMMRegister xtmp1, XMMRegister xtmp2, int vlen_enc); - void scalar_max_min_fp16(int opcode, XMMRegister dst, XMMRegister src1, XMMRegister src2, - KRegister ktmp, XMMRegister xtmp1, XMMRegister xtmp2); + void vminmax_fp16_avx10_2(int opcode, XMMRegister dst, XMMRegister src1, XMMRegister src2, + KRegister ktmp, int vlen_enc); + + void vminmax_fp16_avx10_2(int opcode, XMMRegister dst, XMMRegister src1, Address src2, + KRegister ktmp, int vlen_enc); + + void sminmax_fp16(int opcode, XMMRegister dst, XMMRegister src1, XMMRegister src2, + KRegister ktmp, XMMRegister xtmp1, XMMRegister xtmp2); + + void sminmax_fp16_avx10_2(int opcode, XMMRegister dst, XMMRegister src1, XMMRegister src2, + KRegister ktmp); void reconstruct_frame_pointer(Register rtmp); diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp index a0f08145d55..356bf8af5c0 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp @@ -1958,6 +1958,16 @@ void MacroAssembler::movflt(XMMRegister dst, AddressLiteral src, Register rscrat } } +void MacroAssembler::movhlf(XMMRegister dst, XMMRegister src, Register rscratch) { + if (VM_Version::supports_avx10_2()) { + evmovw(dst, src); + } else { + assert(rscratch != noreg, "missing"); + evmovw(rscratch, src); + evmovw(dst, rscratch); + } +} + void MacroAssembler::mov64(Register dst, int64_t imm64) { if (is_uimm32(imm64)) { movl(dst, checked_cast(imm64)); @@ -2661,14 +2671,14 @@ void MacroAssembler::ucomisd(XMMRegister dst, AddressLiteral src, Register rscra } } -void MacroAssembler::vucomxsd(XMMRegister dst, AddressLiteral src, Register rscratch) { +void MacroAssembler::evucomxsd(XMMRegister dst, AddressLiteral src, Register rscratch) { assert(rscratch != noreg || always_reachable(src), "missing"); if (reachable(src)) { - Assembler::vucomxsd(dst, as_Address(src)); + Assembler::evucomxsd(dst, as_Address(src)); } else { lea(rscratch, src); - Assembler::vucomxsd(dst, Address(rscratch, 0)); + Assembler::evucomxsd(dst, Address(rscratch, 0)); } } @@ -2683,14 +2693,36 @@ void MacroAssembler::ucomiss(XMMRegister dst, AddressLiteral src, Register rscra } } -void MacroAssembler::vucomxss(XMMRegister dst, AddressLiteral src, Register rscratch) { +void MacroAssembler::evucomxss(XMMRegister dst, AddressLiteral src, Register rscratch) { assert(rscratch != noreg || always_reachable(src), "missing"); if (reachable(src)) { - Assembler::vucomxss(dst, as_Address(src)); + Assembler::evucomxss(dst, as_Address(src)); } else { lea(rscratch, src); - Assembler::vucomxss(dst, Address(rscratch, 0)); + Assembler::evucomxss(dst, Address(rscratch, 0)); + } +} + +void MacroAssembler::evucomish(XMMRegister dst, AddressLiteral src, Register rscratch) { + assert(rscratch != noreg || always_reachable(src), "missing"); + + if (reachable(src)) { + Assembler::evucomish(dst, as_Address(src)); + } else { + lea(rscratch, src); + Assembler::evucomish(dst, Address(rscratch, 0)); + } +} + +void MacroAssembler::evucomxsh(XMMRegister dst, AddressLiteral src, Register rscratch) { + assert(rscratch != noreg || always_reachable(src), "missing"); + + if (reachable(src)) { + Assembler::evucomxsh(dst, as_Address(src)); + } else { + lea(rscratch, src); + Assembler::evucomxsh(dst, Address(rscratch, 0)); } } @@ -9163,7 +9195,7 @@ void MacroAssembler::evpmaxs(BasicType type, XMMRegister dst, KRegister mask, XM case T_FLOAT: evminmaxps(dst, mask, nds, src, merge, AVX10_2_MINMAX_MAX_COMPARE_SIGN, vector_len); break; case T_DOUBLE: - evminmaxps(dst, mask, nds, src, merge, AVX10_2_MINMAX_MAX_COMPARE_SIGN, vector_len); break; + evminmaxpd(dst, mask, nds, src, merge, AVX10_2_MINMAX_MAX_COMPARE_SIGN, vector_len); break; default: fatal("Unexpected type argument %s", type2name(type)); break; } diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.hpp b/src/hotspot/cpu/x86/macroAssembler_x86.hpp index 3bdd1e4477a..021d2943ee8 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.hpp @@ -162,6 +162,8 @@ class MacroAssembler: public Assembler { void incrementq(AddressLiteral dst, Register rscratch = noreg); + void movhlf(XMMRegister dst, XMMRegister src, Register rscratch = noreg); + // Support optimal SSE move instructions. void movflt(XMMRegister dst, XMMRegister src) { if (dst-> encoding() == src->encoding()) return; @@ -1308,21 +1310,29 @@ public: void subss(XMMRegister dst, Address src) { Assembler::subss(dst, src); } void subss(XMMRegister dst, AddressLiteral src, Register rscratch = noreg); + void evucomish(XMMRegister dst, XMMRegister src) { Assembler::evucomish(dst, src); } + void evucomish(XMMRegister dst, Address src) { Assembler::evucomish(dst, src); } + void evucomish(XMMRegister dst, AddressLiteral src, Register rscratch = noreg); + + void evucomxsh(XMMRegister dst, XMMRegister src) { Assembler::evucomxsh(dst, src); } + void evucomxsh(XMMRegister dst, Address src) { Assembler::evucomxsh(dst, src); } + void evucomxsh(XMMRegister dst, AddressLiteral src, Register rscratch = noreg); + void ucomiss(XMMRegister dst, XMMRegister src) { Assembler::ucomiss(dst, src); } void ucomiss(XMMRegister dst, Address src) { Assembler::ucomiss(dst, src); } void ucomiss(XMMRegister dst, AddressLiteral src, Register rscratch = noreg); - void vucomxss(XMMRegister dst, XMMRegister src) { Assembler::vucomxss(dst, src); } - void vucomxss(XMMRegister dst, Address src) { Assembler::vucomxss(dst, src); } - void vucomxss(XMMRegister dst, AddressLiteral src, Register rscratch = noreg); + void evucomxss(XMMRegister dst, XMMRegister src) { Assembler::evucomxss(dst, src); } + void evucomxss(XMMRegister dst, Address src) { Assembler::evucomxss(dst, src); } + void evucomxss(XMMRegister dst, AddressLiteral src, Register rscratch = noreg); void ucomisd(XMMRegister dst, XMMRegister src) { Assembler::ucomisd(dst, src); } void ucomisd(XMMRegister dst, Address src) { Assembler::ucomisd(dst, src); } void ucomisd(XMMRegister dst, AddressLiteral src, Register rscratch = noreg); - void vucomxsd(XMMRegister dst, XMMRegister src) { Assembler::vucomxsd(dst, src); } - void vucomxsd(XMMRegister dst, Address src) { Assembler::vucomxsd(dst, src); } - void vucomxsd(XMMRegister dst, AddressLiteral src, Register rscratch = noreg); + void evucomxsd(XMMRegister dst, XMMRegister src) { Assembler::evucomxsd(dst, src); } + void evucomxsd(XMMRegister dst, Address src) { Assembler::evucomxsd(dst, src); } + void evucomxsd(XMMRegister dst, AddressLiteral src, Register rscratch = noreg); // Bitwise Logical XOR of Packed Double-Precision Floating-Point Values void xorpd(XMMRegister dst, XMMRegister src); diff --git a/src/hotspot/cpu/x86/x86.ad b/src/hotspot/cpu/x86/x86.ad index f31d64f3d7e..d7014141234 100644 --- a/src/hotspot/cpu/x86/x86.ad +++ b/src/hotspot/cpu/x86/x86.ad @@ -1708,84 +1708,99 @@ static void emit_cmpfp3(MacroAssembler* masm, Register dst) { __ bind(done); } -// Math.min() # Math.max() -// -------------------------- -// ucomis[s/d] # -// ja -> b # a -// jp -> NaN # NaN -// jb -> a # b -// je # -// |-jz -> a | b # a & b -// | -> a # +enum FP_PREC { + fp_prec_hlf, + fp_prec_flt, + fp_prec_dbl +}; + +static inline void emit_fp_ucom(MacroAssembler* masm, enum FP_PREC pt, + XMMRegister p, XMMRegister q) { + if (pt == fp_prec_hlf) { + __ evucomish(p, q); + } else if (pt == fp_prec_flt) { + __ ucomiss(p, q); + } else { + __ ucomisd(p, q); + } +} + +static inline void movfp(MacroAssembler* masm, enum FP_PREC pt, + XMMRegister dst, XMMRegister src, Register scratch) { + if (pt == fp_prec_hlf) { + __ movhlf(dst, src, scratch); + } else if (pt == fp_prec_flt) { + __ movflt(dst, src); + } else { + __ movdbl(dst, src); + } +} + +// Math.min() # Math.max() +// ----------------------------- +// (v)ucomis[h/s/d] # +// ja -> b # a +// jp -> NaN # NaN +// jb -> a # b +// je # +// |-jz -> a | b # a & b +// | -> a # static void emit_fp_min_max(MacroAssembler* masm, XMMRegister dst, XMMRegister a, XMMRegister b, XMMRegister xmmt, Register rt, - bool min, bool single) { + bool min, enum FP_PREC pt) { Label nan, zero, below, above, done; - if (single) - __ ucomiss(a, b); - else - __ ucomisd(a, b); + emit_fp_ucom(masm, pt, a, b); - if (dst->encoding() != (min ? b : a)->encoding()) + if (dst->encoding() != (min ? b : a)->encoding()) { __ jccb(Assembler::above, above); // CF=0 & ZF=0 - else + } else { __ jccb(Assembler::above, done); + } __ jccb(Assembler::parity, nan); // PF=1 __ jccb(Assembler::below, below); // CF=1 // equal __ vpxor(xmmt, xmmt, xmmt, Assembler::AVX_128bit); - if (single) { - __ ucomiss(a, xmmt); - __ jccb(Assembler::equal, zero); + emit_fp_ucom(masm, pt, a, xmmt); - __ movflt(dst, a); - __ jmp(done); - } - else { - __ ucomisd(a, xmmt); - __ jccb(Assembler::equal, zero); + __ jccb(Assembler::equal, zero); + movfp(masm, pt, dst, a, rt); - __ movdbl(dst, a); - __ jmp(done); - } + __ jmp(done); __ bind(zero); - if (min) + if (min) { __ vpor(dst, a, b, Assembler::AVX_128bit); - else + } else { __ vpand(dst, a, b, Assembler::AVX_128bit); + } __ jmp(done); __ bind(above); - if (single) - __ movflt(dst, min ? b : a); - else - __ movdbl(dst, min ? b : a); + movfp(masm, pt, dst, min ? b : a, rt); __ jmp(done); __ bind(nan); - if (single) { + if (pt == fp_prec_hlf) { + __ movl(rt, 0x00007e00); // Float16.NaN + __ evmovw(dst, rt); + } else if (pt == fp_prec_flt) { __ movl(rt, 0x7fc00000); // Float.NaN __ movdl(dst, rt); - } - else { + } else { __ mov64(rt, 0x7ff8000000000000L); // Double.NaN __ movdq(dst, rt); } __ jmp(done); __ bind(below); - if (single) - __ movflt(dst, min ? a : b); - else - __ movdbl(dst, min ? a : b); + movfp(masm, pt, dst, min ? a : b, rt); __ bind(done); } @@ -7345,146 +7360,140 @@ instruct loadAOTRCAddress(rRegP dst, immAOTRuntimeConstantsAddress con) ins_pipe(ialu_reg_fat); %} +// min = java.lang.Math.min(float a, float b) // max = java.lang.Math.max(float a, float b) -instruct maxF_reg_avx10_2(regF dst, regF a, regF b) %{ - predicate(VM_Version::supports_avx10_2()); +instruct minmaxF_reg_avx10_2(regF dst, regF a, regF b) +%{ + predicate(VM_Version::supports_avx10_2() && !VLoopReductions::is_reduction(n)); match(Set dst (MaxF a b)); - format %{ "maxF $dst, $a, $b" %} - ins_encode %{ - __ eminmaxss($dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, AVX10_2_MINMAX_MAX_COMPARE_SIGN); - %} - ins_pipe( pipe_slow ); -%} - -// max = java.lang.Math.max(float a, float b) -instruct maxF_reg(legRegF dst, legRegF a, legRegF b, legRegF tmp, legRegF atmp, legRegF btmp) %{ - predicate(!VM_Version::supports_avx10_2() && UseAVX > 0 && !VLoopReductions::is_reduction(n)); - match(Set dst (MaxF a b)); - effect(USE a, USE b, TEMP tmp, TEMP atmp, TEMP btmp); - format %{ "maxF $dst, $a, $b \t! using $tmp, $atmp and $btmp as TEMP" %} - ins_encode %{ - __ vminmax_fp(Op_MaxV, T_FLOAT, $dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, $tmp$$XMMRegister, $atmp$$XMMRegister, $btmp$$XMMRegister, Assembler::AVX_128bit); - %} - ins_pipe( pipe_slow ); -%} - -instruct maxF_reduction_reg(legRegF dst, legRegF a, legRegF b, legRegF xtmp, rRegI rtmp, rFlagsReg cr) %{ - predicate(!VM_Version::supports_avx10_2() && UseAVX > 0 && VLoopReductions::is_reduction(n)); - match(Set dst (MaxF a b)); - effect(USE a, USE b, TEMP xtmp, TEMP rtmp, KILL cr); - - format %{ "maxF_reduction $dst, $a, $b \t!using $xtmp and $rtmp as TEMP" %} - ins_encode %{ - emit_fp_min_max(masm, $dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, $xtmp$$XMMRegister, $rtmp$$Register, - false /*min*/, true /*single*/); - %} - ins_pipe( pipe_slow ); -%} - -// max = java.lang.Math.max(double a, double b) -instruct maxD_reg_avx10_2(regD dst, regD a, regD b) %{ - predicate(VM_Version::supports_avx10_2()); - match(Set dst (MaxD a b)); - format %{ "maxD $dst, $a, $b" %} - ins_encode %{ - __ eminmaxsd($dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, AVX10_2_MINMAX_MAX_COMPARE_SIGN); - %} - ins_pipe( pipe_slow ); -%} - -// max = java.lang.Math.max(double a, double b) -instruct maxD_reg(legRegD dst, legRegD a, legRegD b, legRegD tmp, legRegD atmp, legRegD btmp) %{ - predicate(!VM_Version::supports_avx10_2() && UseAVX > 0 && !VLoopReductions::is_reduction(n)); - match(Set dst (MaxD a b)); - effect(USE a, USE b, TEMP atmp, TEMP btmp, TEMP tmp); - format %{ "maxD $dst, $a, $b \t! using $tmp, $atmp and $btmp as TEMP" %} - ins_encode %{ - __ vminmax_fp(Op_MaxV, T_DOUBLE, $dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, $tmp$$XMMRegister, $atmp$$XMMRegister, $btmp$$XMMRegister, Assembler::AVX_128bit); - %} - ins_pipe( pipe_slow ); -%} - -instruct maxD_reduction_reg(legRegD dst, legRegD a, legRegD b, legRegD xtmp, rRegL rtmp, rFlagsReg cr) %{ - predicate(!VM_Version::supports_avx10_2() && UseAVX > 0 && VLoopReductions::is_reduction(n)); - match(Set dst (MaxD a b)); - effect(USE a, USE b, TEMP xtmp, TEMP rtmp, KILL cr); - - format %{ "maxD_reduction $dst, $a, $b \t! using $xtmp and $rtmp as TEMP" %} - ins_encode %{ - emit_fp_min_max(masm, $dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, $xtmp$$XMMRegister, $rtmp$$Register, - false /*min*/, false /*single*/); - %} - ins_pipe( pipe_slow ); -%} - -// max = java.lang.Math.min(float a, float b) -instruct minF_reg_avx10_2(regF dst, regF a, regF b) %{ - predicate(VM_Version::supports_avx10_2()); match(Set dst (MinF a b)); - format %{ "minF $dst, $a, $b" %} + + format %{ "minmaxF $dst, $a, $b" %} ins_encode %{ - __ eminmaxss($dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, AVX10_2_MINMAX_MIN_COMPARE_SIGN); + int opcode = this->ideal_Opcode(); + __ sminmax_fp_avx10_2(opcode, T_FLOAT, $dst$$XMMRegister, k0, $a$$XMMRegister, $b$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct minmaxF_reduction_reg_avx10_2(regF dst, regF a, regF b, regF xtmp, rRegI rtmp, rFlagsReg cr) +%{ + predicate(VM_Version::supports_avx10_2() && VLoopReductions::is_reduction(n)); + match(Set dst (MaxF a b)); + match(Set dst (MinF a b)); + effect(USE a, USE b, TEMP xtmp, TEMP rtmp, KILL cr); + + format %{ "minmaxF_reduction $dst, $a, $b \t! using $xtmp and $rtmp as TEMP" %} + ins_encode %{ + int opcode = this->ideal_Opcode(); + bool min = (opcode == Op_MinF) ? true : false; + emit_fp_min_max(masm, $dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, $xtmp$$XMMRegister, $rtmp$$Register, + min, fp_prec_flt /*pt*/); %} ins_pipe( pipe_slow ); %} // min = java.lang.Math.min(float a, float b) -instruct minF_reg(legRegF dst, legRegF a, legRegF b, legRegF tmp, legRegF atmp, legRegF btmp) %{ +// max = java.lang.Math.max(float a, float b) +instruct minmaxF_reg(legRegF dst, legRegF a, legRegF b, legRegF tmp, legRegF atmp, legRegF btmp) +%{ predicate(!VM_Version::supports_avx10_2() && UseAVX > 0 && !VLoopReductions::is_reduction(n)); + match(Set dst (MaxF a b)); match(Set dst (MinF a b)); effect(USE a, USE b, TEMP tmp, TEMP atmp, TEMP btmp); - format %{ "minF $dst, $a, $b \t! using $tmp, $atmp and $btmp as TEMP" %} + + format %{ "minmaxF $dst, $a, $b \t! using $tmp, $atmp and $btmp as TEMP" %} ins_encode %{ - __ vminmax_fp(Op_MinV, T_FLOAT, $dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, $tmp$$XMMRegister, $atmp$$XMMRegister, $btmp$$XMMRegister, Assembler::AVX_128bit); + int opcode = this->ideal_Opcode(); + int param_opcode = (opcode == Op_MinF) ? Op_MinV : Op_MaxV; + __ vminmax_fp(param_opcode, T_FLOAT, $dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, $tmp$$XMMRegister, + $atmp$$XMMRegister, $btmp$$XMMRegister, Assembler::AVX_128bit); %} ins_pipe( pipe_slow ); %} -instruct minF_reduction_reg(legRegF dst, legRegF a, legRegF b, legRegF xtmp, rRegI rtmp, rFlagsReg cr) %{ +instruct minmaxF_reduction_reg(legRegF dst, legRegF a, legRegF b, legRegF xtmp, rRegI rtmp, rFlagsReg cr) +%{ predicate(!VM_Version::supports_avx10_2() && UseAVX > 0 && VLoopReductions::is_reduction(n)); + match(Set dst (MaxF a b)); match(Set dst (MinF a b)); effect(USE a, USE b, TEMP xtmp, TEMP rtmp, KILL cr); - format %{ "minF_reduction $dst, $a, $b \t! using $xtmp and $rtmp as TEMP" %} + format %{ "minmaxF_reduction $dst, $a, $b \t!using $xtmp and $rtmp as TEMP" %} ins_encode %{ + int opcode = this->ideal_Opcode(); + bool min = (opcode == Op_MinF) ? true : false; emit_fp_min_max(masm, $dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, $xtmp$$XMMRegister, $rtmp$$Register, - true /*min*/, true /*single*/); - %} - ins_pipe( pipe_slow ); -%} - -// max = java.lang.Math.min(double a, double b) -instruct minD_reg_avx10_2(regD dst, regD a, regD b) %{ - predicate(VM_Version::supports_avx10_2()); - match(Set dst (MinD a b)); - format %{ "minD $dst, $a, $b" %} - ins_encode %{ - __ eminmaxsd($dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, AVX10_2_MINMAX_MIN_COMPARE_SIGN); + min, fp_prec_flt /*pt*/); %} ins_pipe( pipe_slow ); %} // min = java.lang.Math.min(double a, double b) -instruct minD_reg(legRegD dst, legRegD a, legRegD b, legRegD tmp, legRegD atmp, legRegD btmp) %{ - predicate(!VM_Version::supports_avx10_2() && UseAVX > 0 && !VLoopReductions::is_reduction(n)); +// max = java.lang.Math.max(double a, double b) +instruct minmaxD_reg_avx10_2(regD dst, regD a, regD b) +%{ + predicate(VM_Version::supports_avx10_2() && !VLoopReductions::is_reduction(n)); + match(Set dst (MaxD a b)); match(Set dst (MinD a b)); - effect(USE a, USE b, TEMP tmp, TEMP atmp, TEMP btmp); - format %{ "minD $dst, $a, $b \t! using $tmp, $atmp and $btmp as TEMP" %} + + format %{ "minmaxD $dst, $a, $b" %} ins_encode %{ - __ vminmax_fp(Op_MinV, T_DOUBLE, $dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, $tmp$$XMMRegister, $atmp$$XMMRegister, $btmp$$XMMRegister, Assembler::AVX_128bit); + int opcode = this->ideal_Opcode(); + __ sminmax_fp_avx10_2(opcode, T_DOUBLE, $dst$$XMMRegister, k0, $a$$XMMRegister, $b$$XMMRegister); %} ins_pipe( pipe_slow ); %} -instruct minD_reduction_reg(legRegD dst, legRegD a, legRegD b, legRegD xtmp, rRegL rtmp, rFlagsReg cr) %{ - predicate(!VM_Version::supports_avx10_2() && UseAVX > 0 && VLoopReductions::is_reduction(n)); +instruct minmaxD_reduction_reg_avx10_2(regD dst, regD a, regD b, regD xtmp, rRegI rtmp, rFlagsReg cr) +%{ + predicate(VM_Version::supports_avx10_2() && VLoopReductions::is_reduction(n)); + match(Set dst (MaxD a b)); match(Set dst (MinD a b)); effect(USE a, USE b, TEMP xtmp, TEMP rtmp, KILL cr); - format %{ "maxD_reduction $dst, $a, $b \t! using $xtmp and $rtmp as TEMP" %} + format %{ "minmaxD_reduction $dst, $a, $b \t! using $xtmp and $rtmp as TEMP" %} ins_encode %{ + int opcode = this->ideal_Opcode(); + bool min = (opcode == Op_MinD) ? true : false; emit_fp_min_max(masm, $dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, $xtmp$$XMMRegister, $rtmp$$Register, - true /*min*/, false /*single*/); + min, fp_prec_dbl /*pt*/); + %} + ins_pipe( pipe_slow ); +%} + +// min = java.lang.Math.min(double a, double b) +// max = java.lang.Math.max(double a, double b) +instruct minmaxD_reg(legRegD dst, legRegD a, legRegD b, legRegD tmp, legRegD atmp, legRegD btmp) +%{ + predicate(!VM_Version::supports_avx10_2() && UseAVX > 0 && !VLoopReductions::is_reduction(n)); + match(Set dst (MaxD a b)); + match(Set dst (MinD a b)); + effect(USE a, USE b, TEMP atmp, TEMP btmp, TEMP tmp); + + format %{ "minmaxD $dst, $a, $b \t! using $tmp, $atmp and $btmp as TEMP" %} + ins_encode %{ + int opcode = this->ideal_Opcode(); + int param_opcode = (opcode == Op_MinD) ? Op_MinV : Op_MaxV; + __ vminmax_fp(param_opcode, T_DOUBLE, $dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, $tmp$$XMMRegister, + $atmp$$XMMRegister, $btmp$$XMMRegister, Assembler::AVX_128bit); + %} + ins_pipe( pipe_slow ); +%} + +instruct minmaxD_reduction_reg(legRegD dst, legRegD a, legRegD b, legRegD xtmp, rRegL rtmp, rFlagsReg cr) +%{ + predicate(!VM_Version::supports_avx10_2() && UseAVX > 0 && VLoopReductions::is_reduction(n)); + match(Set dst (MaxD a b)); + match(Set dst (MinD a b)); + effect(USE a, USE b, TEMP xtmp, TEMP rtmp, KILL cr); + + format %{ "minmaxD_reduction $dst, $a, $b \t! using $xtmp and $rtmp as TEMP" %} + ins_encode %{ + int opcode = this->ideal_Opcode(); + bool min = (opcode == Op_MinD) ? true : false; + emit_fp_min_max(masm, $dst$$XMMRegister, $a$$XMMRegister, $b$$XMMRegister, $xtmp$$XMMRegister, $rtmp$$Register, + min, fp_prec_dbl /*pt*/); %} ins_pipe( pipe_slow ); %} @@ -14394,9 +14403,9 @@ instruct cmpF_cc_regCFE(rFlagsRegUCFE cr, regF src1, regF src2) %{ match(Set cr (CmpF src1 src2)); ins_cost(100); - format %{ "vucomxss $src1, $src2" %} + format %{ "evucomxss $src1, $src2" %} ins_encode %{ - __ vucomxss($src1$$XMMRegister, $src2$$XMMRegister); + __ evucomxss($src1$$XMMRegister, $src2$$XMMRegister); %} ins_pipe(pipe_slow); %} @@ -14416,9 +14425,9 @@ instruct cmpF_cc_memCFE(rFlagsRegUCFE cr, regF src1, memory src2) %{ match(Set cr (CmpF src1 (LoadF src2))); ins_cost(100); - format %{ "vucomxss $src1, $src2" %} + format %{ "evucomxss $src1, $src2" %} ins_encode %{ - __ vucomxss($src1$$XMMRegister, $src2$$Address); + __ evucomxss($src1$$XMMRegister, $src2$$Address); %} ins_pipe(pipe_slow); %} @@ -14438,9 +14447,9 @@ instruct cmpF_cc_immCFE(rFlagsRegUCFE cr, regF src, immF con) %{ match(Set cr (CmpF src con)); ins_cost(100); - format %{ "vucomxss $src, [$constantaddress]\t# load from constant table: float=$con" %} + format %{ "evucomxss $src, [$constantaddress]\t# load from constant table: float=$con" %} ins_encode %{ - __ vucomxss($src$$XMMRegister, $constantaddress($con)); + __ evucomxss($src$$XMMRegister, $constantaddress($con)); %} ins_pipe(pipe_slow); %} @@ -14479,9 +14488,9 @@ instruct cmpD_cc_regCFE(rFlagsRegUCFE cr, regD src1, regD src2) %{ match(Set cr (CmpD src1 src2)); ins_cost(100); - format %{ "vucomxsd $src1, $src2 test" %} + format %{ "evucomxsd $src1, $src2 test" %} ins_encode %{ - __ vucomxsd($src1$$XMMRegister, $src2$$XMMRegister); + __ evucomxsd($src1$$XMMRegister, $src2$$XMMRegister); %} ins_pipe(pipe_slow); %} @@ -14501,9 +14510,9 @@ instruct cmpD_cc_memCFE(rFlagsRegUCFE cr, regD src1, memory src2) %{ match(Set cr (CmpD src1 (LoadD src2))); ins_cost(100); - format %{ "vucomxsd $src1, $src2" %} + format %{ "evucomxsd $src1, $src2" %} ins_encode %{ - __ vucomxsd($src1$$XMMRegister, $src2$$Address); + __ evucomxsd($src1$$XMMRegister, $src2$$Address); %} ins_pipe(pipe_slow); %} @@ -14522,9 +14531,9 @@ instruct cmpD_cc_immCFE(rFlagsRegUCFE cr, regD src, immD con) %{ match(Set cr (CmpD src con)); ins_cost(100); - format %{ "vucomxsd $src, [$constantaddress]\t# load from constant table: double=$con" %} + format %{ "evucomxsd $src, [$constantaddress]\t# load from constant table: double=$con" %} ins_encode %{ - __ vucomxsd($src$$XMMRegister, $constantaddress($con)); + __ evucomxsd($src$$XMMRegister, $constantaddress($con)); %} ins_pipe(pipe_slow); %} @@ -18832,7 +18841,7 @@ instruct ReplHF_reg(vec dst, regF src, rRegI rtmp) %{ format %{ "replicateHF $dst, $src \t! using $rtmp as TEMP" %} ins_encode %{ int vlen_enc = vector_length_encoding(this); - __ vmovw($rtmp$$Register, $src$$XMMRegister); + __ evmovw($rtmp$$Register, $src$$XMMRegister); __ evpbroadcastw($dst$$XMMRegister, $rtmp$$Register, vlen_enc); %} ins_pipe( pipe_slow ); @@ -20947,7 +20956,7 @@ instruct minmaxFP_reg_avx10_2(vec dst, vec a, vec b) %{ int vlen_enc = vector_length_encoding(this); int opcode = this->ideal_Opcode(); BasicType elem_bt = Matcher::vector_element_basic_type(this); - __ vminmax_fp(opcode, elem_bt, $dst$$XMMRegister, k0, $a$$XMMRegister, $b$$XMMRegister, vlen_enc); + __ vminmax_fp_avx10_2(opcode, elem_bt, $dst$$XMMRegister, k0, $a$$XMMRegister, $b$$XMMRegister, vlen_enc); %} ins_pipe( pipe_slow ); %} @@ -25291,9 +25300,9 @@ instruct vector_selectfrom_twovectors_reg_evex(vec index, vec src1, vec src2) instruct reinterpretS2HF(regF dst, rRegI src) %{ match(Set dst (ReinterpretS2HF src)); - format %{ "vmovw $dst, $src" %} + format %{ "evmovw $dst, $src" %} ins_encode %{ - __ vmovw($dst$$XMMRegister, $src$$Register); + __ evmovw($dst$$XMMRegister, $src$$Register); %} ins_pipe(pipe_slow); %} @@ -25301,9 +25310,9 @@ instruct reinterpretS2HF(regF dst, rRegI src) instruct reinterpretHF2S(rRegI dst, regF src) %{ match(Set dst (ReinterpretHF2S src)); - format %{ "vmovw $dst, $src" %} + format %{ "evmovw $dst, $src" %} ins_encode %{ - __ vmovw($dst$$Register, $src$$XMMRegister); + __ evmovw($dst$$Register, $src$$XMMRegister); %} ins_pipe(pipe_slow); %} @@ -25357,10 +25366,11 @@ instruct scalar_minmax_HF_reg_avx10_2(regF dst, regF src1, regF src2) predicate(VM_Version::supports_avx10_2()); match(Set dst (MaxHF src1 src2)); match(Set dst (MinHF src1 src2)); + format %{ "scalar_min_max_fp16 $dst, $src1, $src2" %} ins_encode %{ - int function = this->ideal_Opcode() == Op_MinHF ? AVX10_2_MINMAX_MIN_COMPARE_SIGN : AVX10_2_MINMAX_MAX_COMPARE_SIGN; - __ eminmaxsh($dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, function); + int opcode = this->ideal_Opcode(); + __ sminmax_fp16_avx10_2(opcode, $dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, k0); %} ins_pipe( pipe_slow ); %} @@ -25371,11 +25381,12 @@ instruct scalar_minmax_HF_reg(regF dst, regF src1, regF src2, kReg ktmp, regF xt match(Set dst (MaxHF src1 src2)); match(Set dst (MinHF src1 src2)); effect(TEMP_DEF dst, TEMP ktmp, TEMP xtmp1, TEMP xtmp2); + format %{ "scalar_min_max_fp16 $dst, $src1, $src2\t using $ktmp, $xtmp1 and $xtmp2 as TEMP" %} ins_encode %{ int opcode = this->ideal_Opcode(); - __ scalar_max_min_fp16(opcode, $dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, $ktmp$$KRegister, - $xtmp1$$XMMRegister, $xtmp2$$XMMRegister); + __ sminmax_fp16(opcode, $dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, $ktmp$$KRegister, + $xtmp1$$XMMRegister, $xtmp2$$XMMRegister); %} ins_pipe( pipe_slow ); %} @@ -25475,8 +25486,9 @@ instruct vector_minmax_HF_mem_avx10_2(vec dst, vec src1, memory src2) format %{ "vector_min_max_fp16_mem $dst, $src1, $src2" %} ins_encode %{ int vlen_enc = vector_length_encoding(this); - int function = this->ideal_Opcode() == Op_MinVHF ? AVX10_2_MINMAX_MIN_COMPARE_SIGN : AVX10_2_MINMAX_MAX_COMPARE_SIGN; - __ evminmaxph($dst$$XMMRegister, k0, $src1$$XMMRegister, $src2$$Address, true, function, vlen_enc); + int opcode = this->ideal_Opcode(); + __ vminmax_fp16_avx10_2(opcode, $dst$$XMMRegister, $src1$$XMMRegister, $src2$$Address, + k0, vlen_enc); %} ins_pipe( pipe_slow ); %} @@ -25489,8 +25501,9 @@ instruct vector_minmax_HF_reg_avx10_2(vec dst, vec src1, vec src2) format %{ "vector_min_max_fp16 $dst, $src1, $src2" %} ins_encode %{ int vlen_enc = vector_length_encoding(this); - int function = this->ideal_Opcode() == Op_MinVHF ? AVX10_2_MINMAX_MIN_COMPARE_SIGN : AVX10_2_MINMAX_MAX_COMPARE_SIGN; - __ evminmaxph($dst$$XMMRegister, k0, $src1$$XMMRegister, $src2$$XMMRegister, true, function, vlen_enc); + int opcode = this->ideal_Opcode(); + __ vminmax_fp16_avx10_2(opcode, $dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, + k0, vlen_enc); %} ins_pipe( pipe_slow ); %} @@ -25505,8 +25518,8 @@ instruct vector_minmax_HF_reg(vec dst, vec src1, vec src2, kReg ktmp, vec xtmp1, ins_encode %{ int vlen_enc = vector_length_encoding(this); int opcode = this->ideal_Opcode(); - __ vector_max_min_fp16(opcode, $dst$$XMMRegister, $src2$$XMMRegister, $src1$$XMMRegister, $ktmp$$KRegister, - $xtmp1$$XMMRegister, $xtmp2$$XMMRegister, vlen_enc); + __ vminmax_fp16(opcode, $dst$$XMMRegister, $src2$$XMMRegister, $src1$$XMMRegister, $ktmp$$KRegister, + $xtmp1$$XMMRegister, $xtmp2$$XMMRegister, vlen_enc); %} ins_pipe( pipe_slow ); %} diff --git a/test/hotspot/jtreg/compiler/intrinsics/math/TestFpMinMaxReductions.java b/test/hotspot/jtreg/compiler/intrinsics/math/TestFpMinMaxReductions.java index ff0277b33f7..5f516890dbe 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/math/TestFpMinMaxReductions.java +++ b/test/hotspot/jtreg/compiler/intrinsics/math/TestFpMinMaxReductions.java @@ -55,21 +55,21 @@ public class TestFpMinMaxReductions { } @Test - @IR(counts = {IRNode.MIN_F_REG, "1"}, - failOn = {IRNode.MIN_F_REDUCTION_REG}) + @IR(counts = {IRNode.MINMAX_F_REG, "1"}, + failOn = {IRNode.MINMAX_F_REDUCTION_REG}) private static float testFloatMin() { return Math.min(floatInput1, floatInput2); } @Test - @IR(counts = {IRNode.MAX_F_REG, "1"}, - failOn = {IRNode.MAX_F_REDUCTION_REG}) + @IR(counts = {IRNode.MINMAX_F_REG, "1"}, + failOn = {IRNode.MINMAX_F_REDUCTION_REG}) private static float testFloatMax() { return Math.max(floatInput1, floatInput2); } @Test - @IR(counts = {IRNode.MIN_F_REDUCTION_REG, ">= 1"}) + @IR(counts = {IRNode.MINMAX_F_REDUCTION_REG, ">= 1"}) private static float testFloatMinReduction() { float fmin = Float.POSITIVE_INFINITY; for (int i = 0; i < floatArray.length; i++) { @@ -79,7 +79,7 @@ public class TestFpMinMaxReductions { } @Test - @IR(counts = {IRNode.MIN_F_REDUCTION_REG, ">= 1"}) + @IR(counts = {IRNode.MINMAX_F_REDUCTION_REG, ">= 1"}) private static float testFloatMinReductionPartiallyUnrolled() { float fmin = Float.POSITIVE_INFINITY; for (int i = 0; i < floatArray.length / 2; i++) { @@ -90,7 +90,7 @@ public class TestFpMinMaxReductions { } @Test - @IR(counts = {IRNode.MIN_F_REDUCTION_REG, ">= 1"}) + @IR(counts = {IRNode.MINMAX_F_REDUCTION_REG, ">= 1"}) private static float testFloatMinReductionNonCounted() { float fmin = Float.POSITIVE_INFINITY; for (int i = 0; i < floatArray.length; i += stride) { @@ -100,7 +100,7 @@ public class TestFpMinMaxReductions { } @Test - @IR(counts = {IRNode.MIN_F_REDUCTION_REG, ">= 1"}) + @IR(counts = {IRNode.MINMAX_F_REDUCTION_REG, ">= 1"}) private static float testFloatMinReductionGlobalAccumulator() { acc = Float.POSITIVE_INFINITY; for (int i = 0; i < floatArray.length; i++) { @@ -110,7 +110,7 @@ public class TestFpMinMaxReductions { } @Test - @IR(counts = {IRNode.MIN_F_REDUCTION_REG, ">= 1"}) + @IR(counts = {IRNode.MINMAX_F_REDUCTION_REG, ">= 1"}) private static float testFloatMinReductionInOuterLoop() { float fmin = Float.POSITIVE_INFINITY; int count = 0; @@ -124,7 +124,7 @@ public class TestFpMinMaxReductions { } @Test - @IR(counts = {IRNode.MAX_F_REDUCTION_REG, ">= 1"}) + @IR(counts = {IRNode.MINMAX_F_REDUCTION_REG, ">= 1"}) private static float testFloatMaxReduction() { float fmax = Float.NEGATIVE_INFINITY; for (int i = 0; i < floatArray.length; i++) { @@ -134,21 +134,21 @@ public class TestFpMinMaxReductions { } @Test - @IR(counts = {IRNode.MIN_D_REG, "1"}, - failOn = {IRNode.MIN_D_REDUCTION_REG}) + @IR(counts = {IRNode.MINMAX_D_REG, "1"}, + failOn = {IRNode.MINMAX_D_REDUCTION_REG}) private static double testDoubleMin() { return Math.min(doubleInput1, doubleInput2); } @Test - @IR(counts = {IRNode.MAX_D_REG, "1"}, - failOn = {IRNode.MAX_D_REDUCTION_REG}) + @IR(counts = {IRNode.MINMAX_D_REG, "1"}, + failOn = {IRNode.MINMAX_D_REDUCTION_REG}) private static double testDoubleMax() { return Math.max(doubleInput1, doubleInput2); } @Test - @IR(counts = {IRNode.MIN_D_REDUCTION_REG, ">= 1"}) + @IR(counts = {IRNode.MINMAX_D_REDUCTION_REG, ">= 1"}) private static double testDoubleMinReduction() { double fmin = Double.POSITIVE_INFINITY; for (int i = 0; i < doubleArray.length; i++) { @@ -158,7 +158,7 @@ public class TestFpMinMaxReductions { } @Test - @IR(counts = {IRNode.MAX_D_REDUCTION_REG, ">= 1"}) + @IR(counts = {IRNode.MINMAX_D_REDUCTION_REG, ">= 1"}) private static double testDoubleMaxReduction() { double fmax = Double.NEGATIVE_INFINITY; for (int i = 0; i < doubleArray.length; i++) { diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java index 8885d1283df..0753a0b04bc 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java @@ -1203,31 +1203,11 @@ public class IRNode { beforeMatchingNameRegex(MAX_D, "MaxD"); } - public static final String MAX_D_REDUCTION_REG = PREFIX + "MAX_D_REDUCTION_REG" + POSTFIX; - static { - machOnlyNameRegex(MAX_D_REDUCTION_REG, "maxD_reduction_reg"); - } - - public static final String MAX_D_REG = PREFIX + "MAX_D_REG" + POSTFIX; - static { - machOnlyNameRegex(MAX_D_REG, "maxD_reg"); - } - public static final String MAX_F = PREFIX + "MAX_F" + POSTFIX; static { beforeMatchingNameRegex(MAX_F, "MaxF"); } - public static final String MAX_F_REDUCTION_REG = PREFIX + "MAX_F_REDUCTION_REG" + POSTFIX; - static { - machOnlyNameRegex(MAX_F_REDUCTION_REG, "maxF_reduction_reg"); - } - - public static final String MAX_F_REG = PREFIX + "MAX_F_REG" + POSTFIX; - static { - machOnlyNameRegex(MAX_F_REG, "maxF_reg"); - } - public static final String MAX_I = PREFIX + "MAX_I" + POSTFIX; static { beforeMatchingNameRegex(MAX_I, "MaxI"); @@ -1309,14 +1289,14 @@ public class IRNode { beforeMatchingNameRegex(MIN_D, "MinD"); } - public static final String MIN_D_REDUCTION_REG = PREFIX + "MIN_D_REDUCTION_REG" + POSTFIX; + public static final String MINMAX_D_REDUCTION_REG = PREFIX + "MINMAX_D_REDUCTION_REG" + POSTFIX; static { - machOnlyNameRegex(MIN_D_REDUCTION_REG, "minD_reduction_reg"); + machOnlyNameRegex(MINMAX_D_REDUCTION_REG, "minmaxD_reduction_reg"); } - public static final String MIN_D_REG = PREFIX + "MIN_D_REG" + POSTFIX; + public static final String MINMAX_D_REG = PREFIX + "MINMAX_D_REG" + POSTFIX; static { - machOnlyNameRegex(MIN_D_REG, "minD_reg"); + machOnlyNameRegex(MINMAX_D_REG, "minmaxD_reg"); } public static final String MIN_F = PREFIX + "MIN_F" + POSTFIX; @@ -1324,14 +1304,14 @@ public class IRNode { beforeMatchingNameRegex(MIN_F, "MinF"); } - public static final String MIN_F_REDUCTION_REG = PREFIX + "MIN_F_REDUCTION_REG" + POSTFIX; + public static final String MINMAX_F_REDUCTION_REG = PREFIX + "MINMAX_F_REDUCTION_REG" + POSTFIX; static { - machOnlyNameRegex(MIN_F_REDUCTION_REG, "minF_reduction_reg"); + machOnlyNameRegex(MINMAX_F_REDUCTION_REG, "minmaxF_reduction_reg"); } - public static final String MIN_F_REG = PREFIX + "MIN_F_REG" + POSTFIX; + public static final String MINMAX_F_REG = PREFIX + "MINMAX_F_REG" + POSTFIX; static { - machOnlyNameRegex(MIN_F_REG, "minF_reg"); + machOnlyNameRegex(MINMAX_F_REG, "minmaxF_reg"); } public static final String MIN_I = PREFIX + "MIN_I" + POSTFIX; 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 cbfe9958924..92c0b58005f 100644 --- a/test/micro/org/openjdk/bench/jdk/incubator/vector/Float16OperationsBenchmark.java +++ b/test/micro/org/openjdk/bench/jdk/incubator/vector/Float16OperationsBenchmark.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,7 @@ import jdk.incubator.vector.*; import org.openjdk.jmh.annotations.*; import static jdk.incubator.vector.Float16.*; import static java.lang.Float.*; +import java.util.Random; @OutputTimeUnit(TimeUnit.MILLISECONDS) @State(Scope.Thread) @@ -45,11 +46,20 @@ public class Float16OperationsBenchmark { short [] vector5; boolean [] vectorPredicate; + private int c0, c1, c2, s1, s2; + + Random r; + static final short f16_one = Float.floatToFloat16(1.0f); static final short f16_two = Float.floatToFloat16(2.0f); @Setup(Level.Trial) public void BmSetup() { + r = new Random(); + + c1 = s1 = step(); + c2 = vectorDim - (s2 = step()); + rexp = new int[vectorDim]; vectorRes = new short[vectorDim]; vector1 = new short[vectorDim]; @@ -84,6 +94,16 @@ public class Float16OperationsBenchmark { ); } + private int step() { + return (r.nextInt() & 0xf) + 1; + } + + private void inc() { + c1 = c1 + s1 < vectorDim ? c1 + s1 : (s1 = step()); + c2 = c2 - s2 > 0 ? c2 - s2 : vectorDim - (s2 = step()); + c0 = Math.abs(c2 - c1); + } + @Benchmark public void addBenchmark() { for (int i = 0; i < vectorDim; i++) { @@ -200,6 +220,14 @@ public class Float16OperationsBenchmark { } } + @Benchmark + public void maxScalarBenchmark() { + for (int i = 0; i < vectorDim; i++) { + inc(); // Ensures no auto-vectorization + vectorRes[c0] = float16ToRawShortBits(max(shortBitsToFloat16(vector1[c1]), shortBitsToFloat16(vector2[c2]))); + } + } + @Benchmark public void minBenchmark() { for (int i = 0; i < vectorDim; i++) { @@ -207,6 +235,14 @@ public class Float16OperationsBenchmark { } } + @Benchmark + public void minScalarBenchmark() { + for (int i = 0; i < vectorDim; i++) { + inc(); // Ensures no auto-vectorization + vectorRes[c0] = float16ToRawShortBits(min(shortBitsToFloat16(vector1[c1]), shortBitsToFloat16(vector2[c2]))); + } + } + @Benchmark public void sqrtBenchmark() { for (int i = 0; i < vectorDim; i++) { diff --git a/test/micro/org/openjdk/bench/vm/compiler/FpMinMaxIntrinsics.java b/test/micro/org/openjdk/bench/vm/compiler/FpMinMaxIntrinsics.java index 27ae2214157..62c33f5fafe 100644 --- a/test/micro/org/openjdk/bench/vm/compiler/FpMinMaxIntrinsics.java +++ b/test/micro/org/openjdk/bench/vm/compiler/FpMinMaxIntrinsics.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,14 +45,15 @@ public class FpMinMaxIntrinsics { private Random r = new Random(); private static int stride = 1; - private static float acc; + private static float f_acc; + private static double d_acc; @Setup public void init() { c1 = s1 = step(); c2 = COUNT - (s2 = step()); - for (int i=0; i Date: Fri, 27 Mar 2026 07:13:56 +0000 Subject: [PATCH 066/359] 8380872: Remove lingering comments about the removed stack locking Reviewed-by: aboldtch, dholmes --- src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp | 2 +- src/hotspot/share/oops/markWord.hpp | 1 - src/hotspot/share/runtime/objectMonitor.hpp | 6 ++---- src/hotspot/share/runtime/synchronizer.cpp | 13 +++++-------- src/hotspot/share/runtime/vmOperations.cpp | 3 --- 5 files changed, 8 insertions(+), 17 deletions(-) diff --git a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp index c1df726b5ba..23b9a77844d 100644 --- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp @@ -152,7 +152,7 @@ inline Assembler::AvxVectorLen C2_MacroAssembler::vector_length_encoding(int vle // Because the transitions from emitted code to the runtime // monitorenter/exit helper stubs are so slow it's critical that -// we inline both the stack-locking fast path and the inflated fast path. +// we inline both the lock-stack fast path and the inflated fast path. // // See also: cmpFastLock and cmpFastUnlock. // diff --git a/src/hotspot/share/oops/markWord.hpp b/src/hotspot/share/oops/markWord.hpp index c54a9f1bf5d..4583e6bd3a1 100644 --- a/src/hotspot/share/oops/markWord.hpp +++ b/src/hotspot/share/oops/markWord.hpp @@ -54,7 +54,6 @@ // // - the two lock bits are used to describe three states: locked/unlocked and monitor. // -// [ptr | 00] locked ptr points to real header on stack (stack-locking in use) // [header | 00] locked locked regular object header (fast-locking in use) // [header | 01] unlocked regular object header // [ptr | 10] monitor inflated lock (header is swapped out, UseObjectMonitorTable == false) diff --git a/src/hotspot/share/runtime/objectMonitor.hpp b/src/hotspot/share/runtime/objectMonitor.hpp index 842aa1b374e..3ab7b8ea519 100644 --- a/src/hotspot/share/runtime/objectMonitor.hpp +++ b/src/hotspot/share/runtime/objectMonitor.hpp @@ -89,10 +89,8 @@ class ObjectWaiter : public CHeapObj { } }; -// The ObjectMonitor class implements the heavyweight version of a -// JavaMonitor. The lightweight BasicLock/stack lock version has been -// inflated into an ObjectMonitor. This inflation is typically due to -// contention or use of Object.wait(). +// The ObjectMonitor class implements the heavyweight version of a JavaMonitor. +// This inflation is typically due to contention or use of Object.wait(). // // WARNING: This is a very sensitive and fragile class. DO NOT make any // changes unless you are fully aware of the underlying semantics. diff --git a/src/hotspot/share/runtime/synchronizer.cpp b/src/hotspot/share/runtime/synchronizer.cpp index e3293f94eeb..fa178dcb5a1 100644 --- a/src/hotspot/share/runtime/synchronizer.cpp +++ b/src/hotspot/share/runtime/synchronizer.cpp @@ -830,8 +830,7 @@ void ObjectSynchronizer::owned_monitors_iterate_filtered(MonitorClosure* closure }); } -// Iterate ObjectMonitors where the owner == thread; this does NOT include -// ObjectMonitors where owner is set to a stack-lock address in thread. +// Iterate ObjectMonitors where the owner == thread. void ObjectSynchronizer::owned_monitors_iterate(MonitorClosure* closure, JavaThread* thread) { int64_t key = ObjectMonitor::owner_id_from(thread); auto thread_filter = [&](ObjectMonitor* monitor) { return monitor->owner() == key; }; @@ -1964,12 +1963,10 @@ ObjectMonitor* ObjectSynchronizer::inflate_into_object_header(oop object, Object const markWord mark = object->mark_acquire(); // The mark can be in one of the following states: - // * inflated - Just return if using stack-locking. - // If using fast-locking and the ObjectMonitor owner - // is anonymous and the locking_thread owns the - // object lock, then we make the locking_thread - // the ObjectMonitor owner and remove the lock from - // the locking_thread's lock stack. + // * inflated - If the ObjectMonitor owner is anonymous and the + // locking_thread owns the object lock, then we make the + // locking_thread the ObjectMonitor owner and remove the + // lock from the locking_thread's lock stack. // * fast-locked - Coerce it to inflated from fast-locked. // * unlocked - Aggressively inflate the object. diff --git a/src/hotspot/share/runtime/vmOperations.cpp b/src/hotspot/share/runtime/vmOperations.cpp index ef480f04c57..c4a77ce3275 100644 --- a/src/hotspot/share/runtime/vmOperations.cpp +++ b/src/hotspot/share/runtime/vmOperations.cpp @@ -276,9 +276,6 @@ void VM_ThreadDump::doit_epilogue() { } // Hash table of int64_t to a list of ObjectMonitor* owned by the JavaThread. -// The JavaThread's owner key is either a JavaThread* or a stack lock -// address in the JavaThread so we use "int64_t". -// class ObjectMonitorsDump : public MonitorClosure, public ObjectMonitorsView { private: static unsigned int ptr_hash(int64_t const& s1) { From cee1e040b3729309e0f9515c4852670226e5ca88 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Fri, 27 Mar 2026 07:56:55 +0000 Subject: [PATCH 067/359] 8380541: G1: Add g1CollectorState.inline.hpp file Reviewed-by: ayang, stefank --- src/hotspot/share/gc/g1/g1CollectedHeap.cpp | 2 +- .../share/gc/g1/g1CollectedHeap.inline.hpp | 1 - src/hotspot/share/gc/g1/g1CollectionSet.cpp | 2 +- src/hotspot/share/gc/g1/g1CollectorState.cpp | 36 ++--- src/hotspot/share/gc/g1/g1CollectorState.hpp | 74 +++------- .../share/gc/g1/g1CollectorState.inline.hpp | 128 ++++++++++++++++++ src/hotspot/share/gc/g1/g1ConcurrentMark.cpp | 2 +- .../share/gc/g1/g1FullGCCompactTask.cpp | 2 +- src/hotspot/share/gc/g1/g1HeapVerifier.cpp | 1 + src/hotspot/share/gc/g1/g1PeriodicGCTask.cpp | 1 + src/hotspot/share/gc/g1/g1Policy.cpp | 12 ++ src/hotspot/share/gc/g1/g1Policy.hpp | 11 +- src/hotspot/share/gc/g1/g1RemSet.cpp | 1 + src/hotspot/share/gc/g1/g1RootClosures.cpp | 1 + src/hotspot/share/gc/g1/g1RootProcessor.cpp | 3 +- src/hotspot/share/gc/g1/g1Trace.cpp | 1 + src/hotspot/share/gc/g1/g1VMOperations.cpp | 1 + src/hotspot/share/gc/g1/g1YoungCollector.cpp | 2 +- .../g1/g1YoungGCAllocationFailureInjector.cpp | 1 + .../gc/g1/g1YoungGCPostEvacuateTasks.cpp | 2 +- src/hotspot/share/prims/whitebox.cpp | 1 + 21 files changed, 190 insertions(+), 95 deletions(-) create mode 100644 src/hotspot/share/gc/g1/g1CollectorState.inline.hpp diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index be9ecf19123..e6dd91df84b 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -34,7 +34,7 @@ #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1CollectionSet.hpp" #include "gc/g1/g1CollectionSetCandidates.hpp" -#include "gc/g1/g1CollectorState.hpp" +#include "gc/g1/g1CollectorState.inline.hpp" #include "gc/g1/g1ConcurrentMarkThread.inline.hpp" #include "gc/g1/g1ConcurrentRefine.hpp" #include "gc/g1/g1ConcurrentRefineThread.hpp" diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp b/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp index 90e87607b87..bad9ac18eec 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp @@ -28,7 +28,6 @@ #include "gc/g1/g1CollectedHeap.hpp" #include "gc/g1/g1BarrierSet.hpp" -#include "gc/g1/g1CollectorState.hpp" #include "gc/g1/g1ConcurrentMark.inline.hpp" #include "gc/g1/g1EvacFailureRegions.hpp" #include "gc/g1/g1EvacStats.inline.hpp" diff --git a/src/hotspot/share/gc/g1/g1CollectionSet.cpp b/src/hotspot/share/gc/g1/g1CollectionSet.cpp index 978925d88cb..b3bcf6094ab 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSet.cpp +++ b/src/hotspot/share/gc/g1/g1CollectionSet.cpp @@ -26,7 +26,7 @@ #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1CollectionSet.inline.hpp" #include "gc/g1/g1CollectionSetCandidates.inline.hpp" -#include "gc/g1/g1CollectorState.hpp" +#include "gc/g1/g1CollectorState.inline.hpp" #include "gc/g1/g1HeapRegion.inline.hpp" #include "gc/g1/g1HeapRegionRemSet.inline.hpp" #include "gc/g1/g1HeapRegionSet.hpp" diff --git a/src/hotspot/share/gc/g1/g1CollectorState.cpp b/src/hotspot/share/gc/g1/g1CollectorState.cpp index 2b550f36904..76de9c65cc8 100644 --- a/src/hotspot/share/gc/g1/g1CollectorState.cpp +++ b/src/hotspot/share/gc/g1/g1CollectorState.cpp @@ -22,42 +22,32 @@ * */ -#include "gc/g1/g1CollectedHeap.inline.hpp" -#include "gc/g1/g1CollectorState.hpp" -#include "gc/g1/g1ConcurrentMarkThread.inline.hpp" +#include "gc/g1/g1CollectorState.inline.hpp" #include "runtime/safepoint.hpp" +#include "utilities/debug.hpp" G1CollectorState::Pause G1CollectorState::gc_pause_type(bool concurrent_operation_is_full_mark) const { assert(SafepointSynchronize::is_at_safepoint(), "must be"); switch (_phase) { case Phase::YoungNormal: return Pause::Normal; - case Phase::YoungPrepareMixed: return Pause::PrepareMixed; case Phase::YoungConcurrentStart: return concurrent_operation_is_full_mark ? Pause::ConcurrentStartFull : Pause::ConcurrentStartUndo; + case Phase::YoungPrepareMixed: return Pause::PrepareMixed; case Phase::Mixed: return Pause::Mixed; case Phase::FullGC: return Pause::Full; default: ShouldNotReachHere(); } } -bool G1CollectorState::is_in_concurrent_cycle() const { - G1ConcurrentMark* cm = G1CollectedHeap::heap()->concurrent_mark(); - return cm->is_in_concurrent_cycle(); +const char* G1CollectorState::to_string(Pause type) { + static const char* pause_strings[] = { "Normal", + "Concurrent Start", // Do not distinguish between the different + "Concurrent Start", // Concurrent Start pauses. + "Prepare Mixed", + "Cleanup", + "Remark", + "Mixed", + "Full" }; + return pause_strings[static_cast(type)]; } - -bool G1CollectorState::is_in_marking() const { - G1ConcurrentMark* cm = G1CollectedHeap::heap()->concurrent_mark(); - return cm->is_in_marking(); -} - -bool G1CollectorState::is_in_mark_or_rebuild() const { - G1ConcurrentMark* cm = G1CollectedHeap::heap()->concurrent_mark(); - return is_in_marking() || cm->is_in_rebuild_or_scrub(); -} - -bool G1CollectorState::is_in_reset_for_next_cycle() const { - G1ConcurrentMark* cm = G1CollectedHeap::heap()->concurrent_mark(); - return cm->is_in_reset_for_next_cycle(); -} - diff --git a/src/hotspot/share/gc/g1/g1CollectorState.hpp b/src/hotspot/share/gc/g1/g1CollectorState.hpp index 64c848959ae..42aaeab03b2 100644 --- a/src/hotspot/share/gc/g1/g1CollectorState.hpp +++ b/src/hotspot/share/gc/g1/g1CollectorState.hpp @@ -67,26 +67,25 @@ public: _initiate_conc_mark_if_possible(false) { } // Phase setters - void set_in_normal_young_gc() { _phase = Phase::YoungNormal; } - void set_in_space_reclamation_phase() { _phase = Phase::Mixed; } - void set_in_full_gc() { _phase = Phase::FullGC; } + inline void set_in_normal_young_gc(); + inline void set_in_space_reclamation_phase(); + inline void set_in_full_gc(); - // Pause setters - void set_in_concurrent_start_gc() { _phase = Phase::YoungConcurrentStart; _initiate_conc_mark_if_possible = false; } - void set_in_prepare_mixed_gc() { _phase = Phase::YoungPrepareMixed; } + inline void set_in_concurrent_start_gc(); + inline void set_in_prepare_mixed_gc(); - void set_initiate_conc_mark_if_possible(bool v) { _initiate_conc_mark_if_possible = v; } + inline void set_initiate_conc_mark_if_possible(bool v); // Phase getters - bool is_in_young_only_phase() const { return _phase == Phase::YoungNormal || _phase == Phase::YoungConcurrentStart || _phase == Phase::YoungPrepareMixed; } - bool is_in_mixed_phase() const { return _phase == Phase::Mixed; } + inline bool is_in_young_only_phase() const; + inline bool is_in_mixed_phase() const; // Specific pauses - bool is_in_concurrent_start_gc() const { return _phase == Phase::YoungConcurrentStart; } - bool is_in_prepare_mixed_gc() const { return _phase == Phase::YoungPrepareMixed; } - bool is_in_full_gc() const { return _phase == Phase::FullGC; } + inline bool is_in_concurrent_start_gc() const; + inline bool is_in_prepare_mixed_gc() const; + inline bool is_in_full_gc() const; - bool initiate_conc_mark_if_possible() const { return _initiate_conc_mark_if_possible; } + inline bool initiate_conc_mark_if_possible() const; bool is_in_concurrent_cycle() const; bool is_in_marking() const; @@ -107,50 +106,17 @@ public: // Calculate GC Pause Type from internal state. Pause gc_pause_type(bool concurrent_operation_is_full_mark) const; - static const char* to_string(Pause type) { - static const char* pause_strings[] = { "Normal", - "Concurrent Start", // Do not distinguish between the different - "Concurrent Start", // Concurrent Start pauses. - "Prepare Mixed", - "Cleanup", - "Remark", - "Mixed", - "Full" }; - return pause_strings[static_cast(type)]; - } + static const char* to_string(Pause type); - static void assert_is_young_pause(Pause type) { - assert(type != Pause::Full, "must be"); - assert(type != Pause::Remark, "must be"); - assert(type != Pause::Cleanup, "must be"); - } + // Pause kind queries + inline static void assert_is_young_pause(Pause type); - static bool is_young_only_pause(Pause type) { - assert_is_young_pause(type); - return type == Pause::ConcurrentStartUndo || - type == Pause::ConcurrentStartFull || - type == Pause::PrepareMixed || - type == Pause::Normal; - } + inline static bool is_young_only_pause(Pause type); + inline static bool is_concurrent_start_pause(Pause type); + inline static bool is_prepare_mixed_pause(Pause type); + inline static bool is_mixed_pause(Pause type); - static bool is_mixed_pause(Pause type) { - assert_is_young_pause(type); - return type == Pause::Mixed; - } - - static bool is_prepare_mixed_pause(Pause type) { - assert_is_young_pause(type); - return type == Pause::PrepareMixed; - } - - static bool is_concurrent_start_pause(Pause type) { - assert_is_young_pause(type); - return type == Pause::ConcurrentStartFull || type == Pause::ConcurrentStartUndo; - } - - static bool is_concurrent_cycle_pause(Pause type) { - return type == Pause::Cleanup || type == Pause::Remark; - } + inline static bool is_concurrent_cycle_pause(Pause type); }; ENUMERATOR_RANGE(G1CollectorState::Pause, G1CollectorState::Pause::Normal, G1CollectorState::Pause::Full) diff --git a/src/hotspot/share/gc/g1/g1CollectorState.inline.hpp b/src/hotspot/share/gc/g1/g1CollectorState.inline.hpp new file mode 100644 index 00000000000..0c6c9c879c3 --- /dev/null +++ b/src/hotspot/share/gc/g1/g1CollectorState.inline.hpp @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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_G1_G1COLLECTORSTATE_INLINE_HPP +#define SHARE_GC_G1_G1COLLECTORSTATE_INLINE_HPP + +#include "gc/g1/g1CollectorState.hpp" + +#include "gc/g1/g1CollectedHeap.hpp" +#include "gc/g1/g1ConcurrentMark.inline.hpp" + +inline void G1CollectorState::set_in_normal_young_gc() { + _phase = Phase::YoungNormal; +} +inline void G1CollectorState::set_in_space_reclamation_phase() { + _phase = Phase::Mixed; +} +inline void G1CollectorState::set_in_full_gc() { + _phase = Phase::FullGC; +} + +inline void G1CollectorState::set_in_concurrent_start_gc() { + _phase = Phase::YoungConcurrentStart; + _initiate_conc_mark_if_possible = false; +} +inline void G1CollectorState::set_in_prepare_mixed_gc() { + _phase = Phase::YoungPrepareMixed; +} + +inline void G1CollectorState::set_initiate_conc_mark_if_possible(bool v) { + _initiate_conc_mark_if_possible = v; +} + +inline bool G1CollectorState::is_in_young_only_phase() const { + return _phase == Phase::YoungNormal || + _phase == Phase::YoungConcurrentStart || + _phase == Phase::YoungPrepareMixed; +} +inline bool G1CollectorState::is_in_mixed_phase() const { + return _phase == Phase::Mixed; +} + +inline bool G1CollectorState::is_in_prepare_mixed_gc() const { + return _phase == Phase::YoungPrepareMixed; +} +inline bool G1CollectorState::is_in_full_gc() const { + return _phase == Phase::FullGC; +} +inline bool G1CollectorState::is_in_concurrent_start_gc() const { + return _phase == Phase::YoungConcurrentStart; +} + +inline bool G1CollectorState::initiate_conc_mark_if_possible() const { + return _initiate_conc_mark_if_possible; +} + +inline bool G1CollectorState::is_in_concurrent_cycle() const { + G1ConcurrentMark* cm = G1CollectedHeap::heap()->concurrent_mark(); + return cm->is_in_concurrent_cycle(); +} +inline bool G1CollectorState::is_in_marking() const { + G1ConcurrentMark* cm = G1CollectedHeap::heap()->concurrent_mark(); + return cm->is_in_marking(); +} +inline bool G1CollectorState::is_in_mark_or_rebuild() const { + G1ConcurrentMark* cm = G1CollectedHeap::heap()->concurrent_mark(); + return is_in_marking() || cm->is_in_rebuild_or_scrub(); +} +inline bool G1CollectorState::is_in_reset_for_next_cycle() const { + G1ConcurrentMark* cm = G1CollectedHeap::heap()->concurrent_mark(); + return cm->is_in_reset_for_next_cycle(); +} + +inline void G1CollectorState::assert_is_young_pause(Pause type) { + assert(type != Pause::Full, "must be"); + assert(type != Pause::Remark, "must be"); + assert(type != Pause::Cleanup, "must be"); +} + +inline bool G1CollectorState::is_young_only_pause(Pause type) { + assert_is_young_pause(type); + return type == Pause::ConcurrentStartUndo || + type == Pause::ConcurrentStartFull || + type == Pause::PrepareMixed || + type == Pause::Normal; +} + +inline bool G1CollectorState::is_mixed_pause(Pause type) { + assert_is_young_pause(type); + return type == Pause::Mixed; +} + +inline bool G1CollectorState::is_prepare_mixed_pause(Pause type) { + assert_is_young_pause(type); + return type == Pause::PrepareMixed; +} + +inline bool G1CollectorState::is_concurrent_start_pause(Pause type) { + assert_is_young_pause(type); + return type == Pause::ConcurrentStartFull || type == Pause::ConcurrentStartUndo; +} + +inline bool G1CollectorState::is_concurrent_cycle_pause(Pause type) { + return type == Pause::Cleanup || type == Pause::Remark; +} + +#endif // SHARE_GC_G1_G1COLLECTORSTATE_INLINE_HPP diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp index 8fd355615d0..1caa8dbdd06 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp @@ -30,7 +30,7 @@ #include "gc/g1/g1CardSetMemory.hpp" #include "gc/g1/g1CardTableClaimTable.inline.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" -#include "gc/g1/g1CollectorState.hpp" +#include "gc/g1/g1CollectorState.inline.hpp" #include "gc/g1/g1ConcurrentMark.inline.hpp" #include "gc/g1/g1ConcurrentMarkRemarkTasks.hpp" #include "gc/g1/g1ConcurrentMarkThread.inline.hpp" diff --git a/src/hotspot/share/gc/g1/g1FullGCCompactTask.cpp b/src/hotspot/share/gc/g1/g1FullGCCompactTask.cpp index 5dbf70f36b3..93d8da0d842 100644 --- a/src/hotspot/share/gc/g1/g1FullGCCompactTask.cpp +++ b/src/hotspot/share/gc/g1/g1FullGCCompactTask.cpp @@ -22,7 +22,7 @@ * */ -#include "gc/g1/g1CollectedHeap.hpp" +#include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1ConcurrentMarkBitMap.inline.hpp" #include "gc/g1/g1FullCollector.inline.hpp" #include "gc/g1/g1FullGCCompactionPoint.hpp" diff --git a/src/hotspot/share/gc/g1/g1HeapVerifier.cpp b/src/hotspot/share/gc/g1/g1HeapVerifier.cpp index dd7a8aa117d..714a2473a08 100644 --- a/src/hotspot/share/gc/g1/g1HeapVerifier.cpp +++ b/src/hotspot/share/gc/g1/g1HeapVerifier.cpp @@ -25,6 +25,7 @@ #include "code/nmethod.hpp" #include "gc/g1/g1Allocator.inline.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" +#include "gc/g1/g1CollectorState.inline.hpp" #include "gc/g1/g1ConcurrentMarkThread.hpp" #include "gc/g1/g1HeapRegion.inline.hpp" #include "gc/g1/g1HeapRegionRemSet.hpp" diff --git a/src/hotspot/share/gc/g1/g1PeriodicGCTask.cpp b/src/hotspot/share/gc/g1/g1PeriodicGCTask.cpp index ee11bbd961f..b5ff4272764 100644 --- a/src/hotspot/share/gc/g1/g1PeriodicGCTask.cpp +++ b/src/hotspot/share/gc/g1/g1PeriodicGCTask.cpp @@ -23,6 +23,7 @@ */ #include "gc/g1/g1CollectedHeap.inline.hpp" +#include "gc/g1/g1CollectorState.inline.hpp" #include "gc/g1/g1ConcurrentMark.inline.hpp" #include "gc/g1/g1ConcurrentMarkThread.inline.hpp" #include "gc/g1/g1GCCounters.hpp" diff --git a/src/hotspot/share/gc/g1/g1Policy.cpp b/src/hotspot/share/gc/g1/g1Policy.cpp index 05caff1257a..0145f1e6e1d 100644 --- a/src/hotspot/share/gc/g1/g1Policy.cpp +++ b/src/hotspot/share/gc/g1/g1Policy.cpp @@ -28,6 +28,7 @@ #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1CollectionSet.hpp" #include "gc/g1/g1CollectionSetCandidates.inline.hpp" +#include "gc/g1/g1CollectorState.inline.hpp" #include "gc/g1/g1ConcurrentMark.hpp" #include "gc/g1/g1ConcurrentMarkThread.inline.hpp" #include "gc/g1/g1ConcurrentRefine.hpp" @@ -1133,6 +1134,17 @@ double G1Policy::predict_eden_copy_time_ms(uint count, size_t* bytes_to_copy) co return _analytics->predict_object_copy_time_ms(expected_bytes, collector_state()->is_in_young_only_phase()); } +bool G1Policy::should_update_surv_rate_group_predictors() { + return collector_state()->is_in_young_only_phase() && !collector_state()->is_in_mark_or_rebuild(); +} + +void G1Policy::cset_regions_freed() { + bool update = should_update_surv_rate_group_predictors(); + + _eden_surv_rate_group->all_surviving_words_recorded(predictor(), update); + _survivor_surv_rate_group->all_surviving_words_recorded(predictor(), update); +} + double G1Policy::predict_region_copy_time_ms(G1HeapRegion* hr, bool for_young_only_phase) const { size_t const bytes_to_copy = predict_bytes_to_copy(hr); return _analytics->predict_object_copy_time_ms(bytes_to_copy, for_young_only_phase); diff --git a/src/hotspot/share/gc/g1/g1Policy.hpp b/src/hotspot/share/gc/g1/g1Policy.hpp index 585e26441d5..bcc3bceda49 100644 --- a/src/hotspot/share/gc/g1/g1Policy.hpp +++ b/src/hotspot/share/gc/g1/g1Policy.hpp @@ -114,9 +114,7 @@ class G1Policy: public CHeapObj { G1ConcurrentStartToMixedTimeTracker _concurrent_start_to_mixed; - bool should_update_surv_rate_group_predictors() { - return collector_state()->is_in_young_only_phase() && !collector_state()->is_in_mark_or_rebuild(); - } + bool should_update_surv_rate_group_predictors(); double pending_cards_processing_time() const; public: @@ -160,12 +158,7 @@ public: // bytes_to_copy is non-null. double predict_eden_copy_time_ms(uint count, size_t* bytes_to_copy = nullptr) const; - void cset_regions_freed() { - bool update = should_update_surv_rate_group_predictors(); - - _eden_surv_rate_group->all_surviving_words_recorded(predictor(), update); - _survivor_surv_rate_group->all_surviving_words_recorded(predictor(), update); - } + void cset_regions_freed(); G1MMUTracker* mmu_tracker() { return _mmu_tracker; diff --git a/src/hotspot/share/gc/g1/g1RemSet.cpp b/src/hotspot/share/gc/g1/g1RemSet.cpp index 4b4a8a68c30..9f9f0ecdf3a 100644 --- a/src/hotspot/share/gc/g1/g1RemSet.cpp +++ b/src/hotspot/share/gc/g1/g1RemSet.cpp @@ -31,6 +31,7 @@ #include "gc/g1/g1CardTableEntryClosure.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1CollectionSet.inline.hpp" +#include "gc/g1/g1CollectorState.inline.hpp" #include "gc/g1/g1ConcurrentRefine.hpp" #include "gc/g1/g1ConcurrentRefineSweepTask.hpp" #include "gc/g1/g1FromCardCache.hpp" diff --git a/src/hotspot/share/gc/g1/g1RootClosures.cpp b/src/hotspot/share/gc/g1/g1RootClosures.cpp index 2d5150c27aa..16c47cddea1 100644 --- a/src/hotspot/share/gc/g1/g1RootClosures.cpp +++ b/src/hotspot/share/gc/g1/g1RootClosures.cpp @@ -22,6 +22,7 @@ * */ +#include "gc/g1/g1CollectorState.inline.hpp" #include "gc/g1/g1OopClosures.inline.hpp" #include "gc/g1/g1RootClosures.hpp" #include "gc/g1/g1SharedClosures.hpp" diff --git a/src/hotspot/share/gc/g1/g1RootProcessor.cpp b/src/hotspot/share/gc/g1/g1RootProcessor.cpp index dac237cb277..a534eefb428 100644 --- a/src/hotspot/share/gc/g1/g1RootProcessor.cpp +++ b/src/hotspot/share/gc/g1/g1RootProcessor.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * 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 "code/codeCache.hpp" #include "gc/g1/g1BarrierSet.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" -#include "gc/g1/g1CollectorState.hpp" #include "gc/g1/g1GCParPhaseTimesTracker.hpp" #include "gc/g1/g1GCPhaseTimes.hpp" #include "gc/g1/g1HeapRegion.inline.hpp" diff --git a/src/hotspot/share/gc/g1/g1Trace.cpp b/src/hotspot/share/gc/g1/g1Trace.cpp index 242a97ca4e3..d6eadda5d50 100644 --- a/src/hotspot/share/gc/g1/g1Trace.cpp +++ b/src/hotspot/share/gc/g1/g1Trace.cpp @@ -22,6 +22,7 @@ * */ +#include "gc/g1/g1CollectorState.inline.hpp" #include "gc/g1/g1EvacInfo.hpp" #include "gc/g1/g1HeapRegionTraceType.hpp" #include "gc/g1/g1Trace.hpp" diff --git a/src/hotspot/share/gc/g1/g1VMOperations.cpp b/src/hotspot/share/gc/g1/g1VMOperations.cpp index f98f0b078f3..b0c6b680b78 100644 --- a/src/hotspot/share/gc/g1/g1VMOperations.cpp +++ b/src/hotspot/share/gc/g1/g1VMOperations.cpp @@ -23,6 +23,7 @@ */ #include "gc/g1/g1CollectedHeap.inline.hpp" +#include "gc/g1/g1CollectorState.inline.hpp" #include "gc/g1/g1ConcurrentMarkThread.inline.hpp" #include "gc/g1/g1Policy.hpp" #include "gc/g1/g1Trace.hpp" diff --git a/src/hotspot/share/gc/g1/g1YoungCollector.cpp b/src/hotspot/share/gc/g1/g1YoungCollector.cpp index 04ccac5ff05..a4938416f25 100644 --- a/src/hotspot/share/gc/g1/g1YoungCollector.cpp +++ b/src/hotspot/share/gc/g1/g1YoungCollector.cpp @@ -31,7 +31,7 @@ #include "gc/g1/g1CardSetMemory.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1CollectionSetCandidates.inline.hpp" -#include "gc/g1/g1CollectorState.hpp" +#include "gc/g1/g1CollectorState.inline.hpp" #include "gc/g1/g1ConcurrentMark.hpp" #include "gc/g1/g1EvacFailureRegions.inline.hpp" #include "gc/g1/g1EvacInfo.hpp" diff --git a/src/hotspot/share/gc/g1/g1YoungGCAllocationFailureInjector.cpp b/src/hotspot/share/gc/g1/g1YoungGCAllocationFailureInjector.cpp index 2291a755cd3..2b33a85da29 100644 --- a/src/hotspot/share/gc/g1/g1YoungGCAllocationFailureInjector.cpp +++ b/src/hotspot/share/gc/g1/g1YoungGCAllocationFailureInjector.cpp @@ -23,6 +23,7 @@ */ #include "gc/g1/g1CollectedHeap.inline.hpp" +#include "gc/g1/g1CollectorState.inline.hpp" #include "gc/g1/g1YoungGCAllocationFailureInjector.inline.hpp" #include "gc/shared/gc_globals.hpp" diff --git a/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp b/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp index 3d49b8f025b..14282383e29 100644 --- a/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp +++ b/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp @@ -29,7 +29,7 @@ #include "gc/g1/g1CardTableEntryClosure.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1CollectionSetCandidates.inline.hpp" -#include "gc/g1/g1CollectorState.hpp" +#include "gc/g1/g1CollectorState.inline.hpp" #include "gc/g1/g1ConcurrentMark.inline.hpp" #include "gc/g1/g1EvacFailureRegions.inline.hpp" #include "gc/g1/g1EvacInfo.hpp" diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index a13d0ba47c8..f50e6ddb3db 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -107,6 +107,7 @@ #if INCLUDE_G1GC #include "gc/g1/g1Arguments.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" +#include "gc/g1/g1CollectorState.inline.hpp" #include "gc/g1/g1ConcurrentMark.hpp" #include "gc/g1/g1ConcurrentMarkThread.inline.hpp" #include "gc/g1/g1HeapRegionManager.hpp" From 53c864a881d2183d3664a6a5a56480bd99fffe45 Mon Sep 17 00:00:00 2001 From: Benjamin Peterson Date: Fri, 27 Mar 2026 08:18:47 +0000 Subject: [PATCH 068/359] 8380960: "Foreign function access" discussion links to wrong downcallHandle overload Reviewed-by: mcimadamore --- .../share/classes/java/lang/foreign/package-info.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/java.base/share/classes/java/lang/foreign/package-info.java b/src/java.base/share/classes/java/lang/foreign/package-info.java index 438d42ae7d1..2070f0c70a8 100644 --- a/src/java.base/share/classes/java/lang/foreign/package-info.java +++ b/src/java.base/share/classes/java/lang/foreign/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -114,7 +114,7 @@ * and we use it to {@linkplain java.lang.foreign.SymbolLookup#findOrThrow(java.lang.String) look up} * the {@code strlen} function in the standard C library; a downcall method handle * targeting said function is subsequently - * {@linkplain java.lang.foreign.Linker#downcallHandle(FunctionDescriptor, Linker.Option...) obtained}. + * {@linkplain java.lang.foreign.Linker#downcallHandle(MemorySegment, FunctionDescriptor, Linker.Option...) obtained}. * To complete the linking successfully, we must provide a * {@link java.lang.foreign.FunctionDescriptor} instance, describing the signature of the * {@code strlen} function. From this information, the linker will uniquely determine From c0e500ad996dd7174f6f37481f2da48dc6d98f56 Mon Sep 17 00:00:00 2001 From: Anton Seoane Ampudia Date: Fri, 27 Mar 2026 09:44:37 +0000 Subject: [PATCH 069/359] 8379794: C2: UBSAN runtime error: shift exponent 64 is too large for 64-bit type 'long unsigned int' Reviewed-by: rcastanedalo, qamai, dlong --- src/hotspot/cpu/x86/x86.ad | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/hotspot/cpu/x86/x86.ad b/src/hotspot/cpu/x86/x86.ad index d7014141234..eaa88d900c7 100644 --- a/src/hotspot/cpu/x86/x86.ad +++ b/src/hotspot/cpu/x86/x86.ad @@ -23972,8 +23972,12 @@ instruct vmask_gen_imm(kReg dst, immL len, rRegL temp) %{ format %{ "vector_mask_gen $len \t! vector mask generator" %} effect(TEMP temp); ins_encode %{ - __ mov64($temp$$Register, (0xFFFFFFFFFFFFFFFFUL >> (64 -$len$$constant))); - __ kmovql($dst$$KRegister, $temp$$Register); + if ($len$$constant > 0) { + __ mov64($temp$$Register, right_n_bits($len$$constant)); + __ kmovql($dst$$KRegister, $temp$$Register); + } else { + __ kxorql($dst$$KRegister, $dst$$KRegister, $dst$$KRegister); + } %} ins_pipe( pipe_slow ); %} From cca8c23871f1669fdd002652a20a6b7935704e30 Mon Sep 17 00:00:00 2001 From: Serhiy Sachkov Date: Fri, 27 Mar 2026 10:36:34 +0000 Subject: [PATCH 070/359] 8380999: Update IPSupport by adding diagnoseConfigurationIssue() method Reviewed-by: dfuchs --- test/lib/jdk/test/lib/net/IPSupport.java | 25 ++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/test/lib/jdk/test/lib/net/IPSupport.java b/test/lib/jdk/test/lib/net/IPSupport.java index 31255e20c6a..4a77c3a9bae 100644 --- a/test/lib/jdk/test/lib/net/IPSupport.java +++ b/test/lib/jdk/test/lib/net/IPSupport.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +34,7 @@ import java.net.InetAddress; import java.net.ProtocolFamily; import java.net.StandardProtocolFamily; import java.nio.channels.SocketChannel; +import java.util.Optional; import jtreg.SkippedException; @@ -124,13 +125,33 @@ public class IPSupport { * is non-operational */ public static void throwSkippedExceptionIfNonOperational() throws SkippedException { + Optional configurationIssue = diagnoseConfigurationIssue(); + configurationIssue.map(SkippedException::new).ifPresent(x -> { + throw x; + }); + } + + /** + * Checks that the platform supports the ability to create a + * minimally-operational socket whose protocol is either one of IPv4 + * or IPv6. + * + *

A minimally-operation socket is one that can be created and + * bound to an IP-specific loopback address. IP support is + * considered non-operational if a socket cannot be bound to either + * one of, an IPv4 loopback address, or the IPv6 loopback address. + * + * @return Optinal with config issue or empty Optinal if no issue found + */ + public static Optional diagnoseConfigurationIssue(){ if (!currentConfigurationIsValid()) { ByteArrayOutputStream os = new ByteArrayOutputStream(); PrintStream ps = new PrintStream(os); ps.println("Invalid networking configuration"); printPlatformSupport(ps); - throw new SkippedException(os.toString()); + return Optional.of(os.toString()); } + return Optional.empty(); } /** From b242eef3123a936f53ea76b28b2f6350e52afa94 Mon Sep 17 00:00:00 2001 From: Ivan Walulya Date: Fri, 27 Mar 2026 11:20:05 +0000 Subject: [PATCH 071/359] 8380656: G1: Refactor G1IHOPControl Co-authored-by: Thomas Schatzl Reviewed-by: ayang, tschatzl --- .../g1ConcurrentStartToMixedTimeTracker.hpp | 8 +- src/hotspot/share/gc/g1/g1IHOPControl.cpp | 115 ++++++++++-------- src/hotspot/share/gc/g1/g1IHOPControl.hpp | 43 ++++--- src/hotspot/share/gc/g1/g1Policy.cpp | 14 +-- .../gtest/gc/g1/test_g1IHOPControl.cpp | 38 +++--- 5 files changed, 121 insertions(+), 97 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1ConcurrentStartToMixedTimeTracker.hpp b/src/hotspot/share/gc/g1/g1ConcurrentStartToMixedTimeTracker.hpp index 57372e695c8..f8bad4bdcd7 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentStartToMixedTimeTracker.hpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentStartToMixedTimeTracker.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ // Used to track time from the end of concurrent start to the first mixed GC. // After calling the concurrent start/mixed gc notifications, the result can be -// obtained in last_marking_time() once, after which the tracking resets. +// obtained in get_and_reset_last_marking_time() once, after which the tracking resets. // Any pauses recorded by add_pause() will be subtracted from that results. class G1ConcurrentStartToMixedTimeTracker { private: @@ -60,7 +60,7 @@ public: } } - double last_marking_time() { + double get_and_reset_last_marking_time() { assert(has_result(), "Do not have all measurements yet."); double result = (_mixed_start_time - _concurrent_start_end_time) - _total_pause_time; reset(); @@ -80,6 +80,8 @@ public: } } + bool is_active() const { return _active; } + // Returns whether we have a result that can be retrieved. bool has_result() const { return _mixed_start_time > 0.0 && _concurrent_start_end_time > 0.0; } }; diff --git a/src/hotspot/share/gc/g1/g1IHOPControl.cpp b/src/hotspot/share/gc/g1/g1IHOPControl.cpp index 43698e9f12b..1e1c52477f9 100644 --- a/src/hotspot/share/gc/g1/g1IHOPControl.cpp +++ b/src/hotspot/share/gc/g1/g1IHOPControl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * 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,18 +38,18 @@ double G1IHOPControl::predict(const TruncatedSeq* seq) const { bool G1IHOPControl::have_enough_data_for_prediction() const { assert(_is_adaptive, "precondition"); - return ((size_t)_marking_times_s.num() >= G1AdaptiveIHOPNumInitialSamples) && - ((size_t)_allocation_rate_s.num() >= G1AdaptiveIHOPNumInitialSamples); + return ((size_t)_marking_start_to_mixed_time_s.num() >= G1AdaptiveIHOPNumInitialSamples) && + ((size_t)_old_gen_alloc_rate.num() >= G1AdaptiveIHOPNumInitialSamples); } -double G1IHOPControl::last_marking_length_s() const { - return _marking_times_s.last(); +double G1IHOPControl::last_marking_start_to_mixed_time_s() const { + return _marking_start_to_mixed_time_s.last(); } -size_t G1IHOPControl::actual_target_threshold() const { +size_t G1IHOPControl::effective_target_occupancy() const { assert(_is_adaptive, "precondition"); - // The actual target threshold takes the heap reserve and the expected waste in + // The effective target occupancy takes the heap reserve and the expected waste in // free space into account. // _heap_reserve is that part of the total heap capacity that is reserved for // eventual promotion failure. @@ -79,9 +79,9 @@ G1IHOPControl::G1IHOPControl(double ihop_percent, _last_allocation_time_s(0.0), _old_gen_alloc_tracker(old_gen_alloc_tracker), _predictor(predictor), - _marking_times_s(10, 0.05), - _allocation_rate_s(10, 0.05), - _last_unrestrained_young_size(0) { + _marking_start_to_mixed_time_s(10, 0.05), + _old_gen_alloc_rate(10, 0.05), + _expected_young_gen_at_first_mixed_gc(0) { assert(_initial_ihop_percent >= 0.0 && _initial_ihop_percent <= 100.0, "IHOP percent out of range: %.3f", ihop_percent); assert(!_is_adaptive || _predictor != nullptr, "precondition"); @@ -98,85 +98,104 @@ void G1IHOPControl::report_statistics(G1NewTracer* new_tracer, size_t non_young_ send_trace_event(new_tracer, non_young_occupancy); } -void G1IHOPControl::update_allocation_info(double allocation_time_s, size_t additional_buffer_size) { +void G1IHOPControl::update_allocation_info(double allocation_time_s, size_t expected_young_gen_size) { assert(allocation_time_s > 0, "Invalid allocation time: %.3f", allocation_time_s); _last_allocation_time_s = allocation_time_s; double alloc_rate = _old_gen_alloc_tracker->last_period_old_gen_growth() / allocation_time_s; - _allocation_rate_s.add(alloc_rate); - _last_unrestrained_young_size = additional_buffer_size; + _old_gen_alloc_rate.add(alloc_rate); + _expected_young_gen_at_first_mixed_gc = expected_young_gen_size; } -void G1IHOPControl::update_marking_length(double marking_length_s) { - assert(marking_length_s >= 0.0, "Invalid marking length: %.3f", marking_length_s); - _marking_times_s.add(marking_length_s); +void G1IHOPControl::add_marking_start_to_mixed_length(double length_s) { + assert(length_s >= 0.0, "Invalid marking length: %.3f", length_s); + _marking_start_to_mixed_time_s.add(length_s); } -size_t G1IHOPControl::get_conc_mark_start_threshold() { +// Determine the old generation occupancy threshold at which to start +// concurrent marking such that reclamation (first Mixed GC) begins +// before the heap reaches a critical occupancy level. +size_t G1IHOPControl::old_gen_threshold_for_conc_mark_start() { guarantee(_target_occupancy > 0, "Target occupancy must be initialized"); if (!_is_adaptive || !have_enough_data_for_prediction()) { return (size_t)(_initial_ihop_percent * _target_occupancy / 100.0); } - double pred_marking_time = predict(&_marking_times_s); - double pred_rate = predict(&_allocation_rate_s); - size_t pred_bytes = (size_t)(pred_marking_time * pred_rate); - size_t predicted_needed = pred_bytes + _last_unrestrained_young_size; - size_t internal_threshold = actual_target_threshold(); + // During the time between marking start and the first Mixed GC, + // additional memory will be consumed: + // - Old gen grows due to allocations: + // old_gen_alloc_bytes = old_gen_alloc_rate * marking_start_to_mixed_time + // - Young gen will occupy a certain size at the first Mixed GC: + // expected_young_gen_at_first_mixed_gc + double marking_start_to_mixed_time = predict(&_marking_start_to_mixed_time_s); + double old_gen_alloc_rate = predict(&_old_gen_alloc_rate); + size_t old_gen_alloc_bytes = (size_t)(marking_start_to_mixed_time * old_gen_alloc_rate); - return predicted_needed < internal_threshold - ? internal_threshold - predicted_needed + // Therefore, the total heap occupancy at the first Mixed GC is: + // current_old_gen + old_gen_growth + expected_young_gen_at_first_mixed_gc + // + // To ensure this does not exceed the target_heap_occupancy, we work + // backwards to compute the old gen occupancy at which marking must start: + // mark_start_threshold = target_heap_occupancy - + // (old_gen_growth + expected_young_gen_at_first_mixed_gc) + + size_t predicted_needed = old_gen_alloc_bytes + _expected_young_gen_at_first_mixed_gc; + size_t target_heap_occupancy = effective_target_occupancy(); + + return predicted_needed < target_heap_occupancy + ? target_heap_occupancy - predicted_needed : 0; } void G1IHOPControl::print_log(size_t non_young_occupancy) { assert(_target_occupancy > 0, "Target occupancy still not updated yet."); - size_t cur_conc_mark_start_threshold = get_conc_mark_start_threshold(); - log_debug(gc, ihop)("Basic information (value update), threshold: %zuB (%1.2f), target occupancy: %zuB, non-young occupancy: %zuB, " - "recent allocation size: %zuB, recent allocation duration: %1.2fms, recent old gen allocation rate: %1.2fB/s, recent marking phase length: %1.2fms", - cur_conc_mark_start_threshold, - percent_of(cur_conc_mark_start_threshold, _target_occupancy), + size_t old_gen_mark_start_threshold = old_gen_threshold_for_conc_mark_start(); + log_debug(gc, ihop)("Basic information (value update), old-gen threshold: %zuB (%1.2f%%), target occupancy: %zuB, old-gen occupancy: %zuB (%1.2f%%), " + "recent old-gen allocation size: %zuB, recent allocation duration: %1.2fms, recent old-gen allocation rate: %1.2fB/s, recent marking phase length: %1.2fms", + old_gen_mark_start_threshold, + percent_of(old_gen_mark_start_threshold, _target_occupancy), _target_occupancy, non_young_occupancy, + percent_of(non_young_occupancy, _target_occupancy), _old_gen_alloc_tracker->last_period_old_gen_bytes(), _last_allocation_time_s * 1000.0, _last_allocation_time_s > 0.0 ? _old_gen_alloc_tracker->last_period_old_gen_bytes() / _last_allocation_time_s : 0.0, - last_marking_length_s() * 1000.0); + last_marking_start_to_mixed_time_s() * 1000.0); if (!_is_adaptive) { return; } - size_t actual_threshold = actual_target_threshold(); - log_debug(gc, ihop)("Adaptive IHOP information (value update), threshold: %zuB (%1.2f), internal target threshold: %zuB, " - "non-young occupancy: %zuB, additional buffer size: %zuB, predicted old gen allocation rate: %1.2fB/s, " - "predicted marking phase length: %1.2fms, prediction active: %s", - cur_conc_mark_start_threshold, - percent_of(cur_conc_mark_start_threshold, actual_threshold), - actual_threshold, + size_t effective_target = effective_target_occupancy(); + log_debug(gc, ihop)("Adaptive IHOP information (value update), prediction active: %s, old-gen threshold: %zuB (%1.2f%%), internal target occupancy: %zuB, " + "old-gen occupancy: %zuB, additional buffer size: %zuB, predicted old-gen allocation rate: %1.2fB/s, " + "predicted marking phase length: %1.2fms", + BOOL_TO_STR(have_enough_data_for_prediction()), + old_gen_mark_start_threshold, + percent_of(old_gen_mark_start_threshold, effective_target), + effective_target, non_young_occupancy, - _last_unrestrained_young_size, - predict(&_allocation_rate_s), - predict(&_marking_times_s) * 1000.0, - have_enough_data_for_prediction() ? "true" : "false"); + _expected_young_gen_at_first_mixed_gc, + predict(&_old_gen_alloc_rate), + predict(&_marking_start_to_mixed_time_s) * 1000.0); } void G1IHOPControl::send_trace_event(G1NewTracer* tracer, size_t non_young_occupancy) { assert(_target_occupancy > 0, "Target occupancy still not updated yet."); - tracer->report_basic_ihop_statistics(get_conc_mark_start_threshold(), + tracer->report_basic_ihop_statistics(old_gen_threshold_for_conc_mark_start(), _target_occupancy, non_young_occupancy, _old_gen_alloc_tracker->last_period_old_gen_bytes(), _last_allocation_time_s, - last_marking_length_s()); + last_marking_start_to_mixed_time_s()); if (_is_adaptive) { - tracer->report_adaptive_ihop_statistics(get_conc_mark_start_threshold(), - actual_target_threshold(), + tracer->report_adaptive_ihop_statistics(old_gen_threshold_for_conc_mark_start(), + effective_target_occupancy(), non_young_occupancy, - _last_unrestrained_young_size, - predict(&_allocation_rate_s), - predict(&_marking_times_s), + _expected_young_gen_at_first_mixed_gc, + predict(&_old_gen_alloc_rate), + predict(&_marking_start_to_mixed_time_s), have_enough_data_for_prediction()); } } diff --git a/src/hotspot/share/gc/g1/g1IHOPControl.hpp b/src/hotspot/share/gc/g1/g1IHOPControl.hpp index 24061c026d1..ff209012f02 100644 --- a/src/hotspot/share/gc/g1/g1IHOPControl.hpp +++ b/src/hotspot/share/gc/g1/g1IHOPControl.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -58,8 +58,11 @@ class G1IHOPControl : public CHeapObj { const G1OldGenAllocationTracker* _old_gen_alloc_tracker; const G1Predictions* _predictor; - TruncatedSeq _marking_times_s; - TruncatedSeq _allocation_rate_s; + // Wall-clock time in seconds from marking start to the first mixed GC, + // excluding GC Pause time. + TruncatedSeq _marking_start_to_mixed_time_s; + // Old generation allocation rate in bytes per second. + TruncatedSeq _old_gen_alloc_rate; // The most recent unrestrained size of the young gen. This is used as an additional // factor in the calculation of the threshold, as the threshold is based on @@ -68,18 +71,18 @@ class G1IHOPControl : public CHeapObj { // Since we cannot know what young gen sizes are used in the future, we will just // use the current one. We expect that this one will be one with a fairly large size, // as there is no marking or mixed gc that could impact its size too much. - size_t _last_unrestrained_young_size; + size_t _expected_young_gen_at_first_mixed_gc; // Get a new prediction bounded below by zero from the given sequence. double predict(const TruncatedSeq* seq) const; bool have_enough_data_for_prediction() const; - double last_marking_length_s() const; + double last_marking_start_to_mixed_time_s() const; - // The "actual" target threshold the algorithm wants to keep during and at the - // end of marking. This is typically lower than the requested threshold, as the + // The "effective" target occupancy the algorithm wants to keep until the start + // of Mixed GCs. This is typically lower than the target occupancy, as the // algorithm needs to consider restrictions by the environment. - size_t actual_target_threshold() const; + size_t effective_target_occupancy() const; void print_log(size_t non_young_occupancy); void send_trace_event(G1NewTracer* tracer, size_t non_young_occupancy); @@ -95,22 +98,24 @@ class G1IHOPControl : public CHeapObj { // Adjust target occupancy. void update_target_occupancy(size_t new_target_occupancy); - // Update information about time during which allocations in the Java heap occurred, - // how large these allocations were in bytes, and an additional buffer. - // The allocations should contain any amount of space made unusable for further - // allocation, e.g. any waste caused by TLAB allocation, space at the end of - // humongous objects that can not be used for allocation, etc. - // Together with the target occupancy, this additional buffer should contain the - // difference between old gen size and total heap size at the start of reclamation, - // and space required for that reclamation. - void update_allocation_info(double allocation_time_s, size_t additional_buffer_size); + void update_target_after_marking_phase(); + + // Update allocation rate information and current expected young gen size for the + // first mixed gc needed for the predictor. Allocation rate is given as the + // separately passed in allocation increment and the time passed (mutator time) + // for the latest allocation increment here. Allocation size is the memory needed + // during the mutator before and the first mixed gc pause itself. + // Contents include young gen at that point, and the memory required for evacuating + // the collection set in that first mixed gc (including waste caused by PLAB + // allocation etc.). + void update_allocation_info(double allocation_time_s, size_t expected_young_gen_size); // Update the time spent in the mutator beginning from the end of concurrent start to // the first mixed gc. - void update_marking_length(double marking_length_s); + void add_marking_start_to_mixed_length(double length_s); // Get the current non-young occupancy at which concurrent marking should start. - size_t get_conc_mark_start_threshold(); + size_t old_gen_threshold_for_conc_mark_start(); void report_statistics(G1NewTracer* tracer, size_t non_young_occupancy); }; diff --git a/src/hotspot/share/gc/g1/g1Policy.cpp b/src/hotspot/share/gc/g1/g1Policy.cpp index 0145f1e6e1d..24a82113d20 100644 --- a/src/hotspot/share/gc/g1/g1Policy.cpp +++ b/src/hotspot/share/gc/g1/g1Policy.cpp @@ -738,15 +738,15 @@ bool G1Policy::need_to_start_conc_mark(const char* source, size_t allocation_wor return false; } - size_t marking_initiating_used_threshold = _ihop_control->get_conc_mark_start_threshold(); + size_t marking_initiating_old_gen_threshold = _ihop_control->old_gen_threshold_for_conc_mark_start(); size_t non_young_occupancy = _g1h->non_young_occupancy_after_allocation(allocation_word_size); bool result = false; - if (non_young_occupancy > marking_initiating_used_threshold) { + if (non_young_occupancy > marking_initiating_old_gen_threshold) { result = collector_state()->is_in_young_only_phase(); log_debug(gc, ergo, ihop)("%s non-young occupancy: %zuB allocation request: %zuB threshold: %zuB (%1.2f) source: %s", result ? "Request concurrent cycle initiation (occupancy higher than threshold)" : "Do not request concurrent cycle initiation (still doing mixed collections)", - non_young_occupancy, allocation_word_size * HeapWordSize, marking_initiating_used_threshold, (double) marking_initiating_used_threshold / _g1h->capacity() * 100, source); + non_young_occupancy, allocation_word_size * HeapWordSize, marking_initiating_old_gen_threshold, (double) marking_initiating_old_gen_threshold / _g1h->capacity() * 100, source); } return result; } @@ -972,8 +972,7 @@ void G1Policy::record_young_collection_end(bool concurrent_operation_is_full_mar update_young_length_bounds(); _old_gen_alloc_tracker.reset_after_gc(_g1h->humongous_regions_count() * G1HeapRegion::GrainBytes); - if (update_ihop_prediction(app_time_ms / 1000.0, - G1CollectorState::is_young_only_pause(this_pause))) { + if (update_ihop_prediction(app_time_ms / 1000.0, is_young_only_pause)) { _ihop_control->report_statistics(_g1h->gc_tracer_stw(), _g1h->non_young_occupancy_after_allocation(allocation_word_size)); } } else { @@ -1030,14 +1029,13 @@ bool G1Policy::update_ihop_prediction(double mutator_time_s, bool report = false; - double marking_to_mixed_time = -1.0; if (!this_gc_was_young_only && _concurrent_start_to_mixed.has_result()) { - marking_to_mixed_time = _concurrent_start_to_mixed.last_marking_time(); + double marking_to_mixed_time = _concurrent_start_to_mixed.get_and_reset_last_marking_time(); assert(marking_to_mixed_time > 0.0, "Concurrent start to mixed time must be larger than zero but is %.3f", marking_to_mixed_time); if (marking_to_mixed_time > min_valid_time) { - _ihop_control->update_marking_length(marking_to_mixed_time); + _ihop_control->add_marking_start_to_mixed_length(marking_to_mixed_time); report = true; } } diff --git a/test/hotspot/gtest/gc/g1/test_g1IHOPControl.cpp b/test/hotspot/gtest/gc/g1/test_g1IHOPControl.cpp index ff661fde00d..0ee0889b6e5 100644 --- a/test/hotspot/gtest/gc/g1/test_g1IHOPControl.cpp +++ b/test/hotspot/gtest/gc/g1/test_g1IHOPControl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,7 +40,7 @@ static void test_update(G1IHOPControl* ctrl, test_update_allocation_tracker(alloc_tracker, alloc_amount); for (int i = 0; i < 100; i++) { ctrl->update_allocation_info(alloc_time, young_size); - ctrl->update_marking_length(mark_time); + ctrl->add_marking_start_to_mixed_length(mark_time); } } @@ -57,7 +57,7 @@ static void test_update_humongous(G1IHOPControl* ctrl, alloc_tracker->reset_after_gc(humongous_bytes_after_last_gc); for (int i = 0; i < 100; i++) { ctrl->update_allocation_info(alloc_time, young_size); - ctrl->update_marking_length(mark_time); + ctrl->add_marking_start_to_mixed_length(mark_time); } } @@ -74,26 +74,26 @@ TEST_VM(G1IHOPControl, static_simple) { G1IHOPControl ctrl(initial_ihop, &alloc_tracker, is_adaptive, nullptr, 0, 0); ctrl.update_target_occupancy(100); - size_t threshold = ctrl.get_conc_mark_start_threshold(); + size_t threshold = ctrl.old_gen_threshold_for_conc_mark_start(); EXPECT_EQ(initial_ihop, threshold); test_update_allocation_tracker(&alloc_tracker, 100); ctrl.update_allocation_info(100.0, 100); - threshold = ctrl.get_conc_mark_start_threshold(); + threshold = ctrl.old_gen_threshold_for_conc_mark_start(); EXPECT_EQ(initial_ihop, threshold); - ctrl.update_marking_length(1000.0); - threshold = ctrl.get_conc_mark_start_threshold(); + ctrl.add_marking_start_to_mixed_length(1000.0); + threshold = ctrl.old_gen_threshold_for_conc_mark_start(); EXPECT_EQ(initial_ihop, threshold); // Whatever we pass, the IHOP value must stay the same. test_update(&ctrl, &alloc_tracker, 2, 10, 10, 3); - threshold = ctrl.get_conc_mark_start_threshold(); + threshold = ctrl.old_gen_threshold_for_conc_mark_start(); EXPECT_EQ(initial_ihop, threshold); test_update(&ctrl, &alloc_tracker, 12, 10, 10, 3); - threshold = ctrl.get_conc_mark_start_threshold(); + threshold = ctrl.old_gen_threshold_for_conc_mark_start(); EXPECT_EQ(initial_ihop, threshold); } @@ -126,23 +126,23 @@ TEST_VM(G1IHOPControl, adaptive_simple) { - (young_size + alloc_amount1 / alloc_time1 * marking_time1); size_t threshold; - threshold = ctrl.get_conc_mark_start_threshold(); + threshold = ctrl.old_gen_threshold_for_conc_mark_start(); EXPECT_EQ(initial_threshold, threshold); for (size_t i = 0; i < G1AdaptiveIHOPNumInitialSamples - 1; i++) { test_update_allocation_tracker(&alloc_tracker, alloc_amount1); ctrl.update_allocation_info(alloc_time1, young_size); - ctrl.update_marking_length(marking_time1); + ctrl.add_marking_start_to_mixed_length(marking_time1); // Not enough data yet. - threshold = ctrl.get_conc_mark_start_threshold(); + threshold = ctrl.old_gen_threshold_for_conc_mark_start(); ASSERT_EQ(initial_threshold, threshold) << "on step " << i; } test_update(&ctrl, &alloc_tracker, alloc_time1, alloc_amount1, young_size, marking_time1); - threshold = ctrl.get_conc_mark_start_threshold(); + threshold = ctrl.old_gen_threshold_for_conc_mark_start(); EXPECT_EQ(settled_ihop1, threshold); @@ -155,7 +155,7 @@ TEST_VM(G1IHOPControl, adaptive_simple) { test_update(&ctrl, &alloc_tracker, alloc_time2, alloc_amount2, young_size, marking_time2); - threshold = ctrl.get_conc_mark_start_threshold(); + threshold = ctrl.old_gen_threshold_for_conc_mark_start(); EXPECT_LT(threshold, settled_ihop1); @@ -166,14 +166,14 @@ TEST_VM(G1IHOPControl, adaptive_simple) { const size_t settled_ihop3 = 0; test_update(&ctrl, &alloc_tracker, alloc_time3, alloc_amount3, young_size, marking_time3); - threshold = ctrl.get_conc_mark_start_threshold(); + threshold = ctrl.old_gen_threshold_for_conc_mark_start(); EXPECT_EQ(settled_ihop3, threshold); // And back to some arbitrary value. test_update(&ctrl, &alloc_tracker, alloc_time2, alloc_amount2, young_size, marking_time2); - threshold = ctrl.get_conc_mark_start_threshold(); + threshold = ctrl.old_gen_threshold_for_conc_mark_start(); EXPECT_GT(threshold, settled_ihop3); } @@ -205,7 +205,7 @@ TEST_VM(G1IHOPControl, adaptive_humongous) { humongous_bytes_after_last_gc, young_size, marking_time); // Test threshold size_t threshold; - threshold = ctrl.get_conc_mark_start_threshold(); + threshold = ctrl.old_gen_threshold_for_conc_mark_start(); // Adjusted allocated bytes: // Total bytes: humongous_bytes // Freed hum bytes: humongous_bytes - humongous_bytes_after_last_gc @@ -219,7 +219,7 @@ TEST_VM(G1IHOPControl, adaptive_humongous) { ctrl2.update_target_occupancy(target_size); test_update_humongous(&ctrl2, &alloc_tracker, duration, old_bytes, humongous_bytes, humongous_bytes_after_gc, young_size, marking_time); - threshold = ctrl2.get_conc_mark_start_threshold(); + threshold = ctrl2.old_gen_threshold_for_conc_mark_start(); // Adjusted allocated bytes: // Total bytes: old_bytes + humongous_bytes // Freed hum bytes: humongous_bytes - (humongous_bytes_after_gc - humongous_bytes_after_last_gc) @@ -235,7 +235,7 @@ TEST_VM(G1IHOPControl, adaptive_humongous) { ctrl3.update_target_occupancy(target_size); test_update_humongous(&ctrl3, &alloc_tracker, duration, old_bytes, humongous_bytes, humongous_bytes_after_gc, young_size, marking_time); - threshold = ctrl3.get_conc_mark_start_threshold(); + threshold = ctrl3.old_gen_threshold_for_conc_mark_start(); // Adjusted allocated bytes: // All humongous are cleaned up since humongous_bytes_after_gc < humongous_bytes_after_last_gc // Total bytes: old_bytes + humongous_bytes From 299452402551d5387eb41ad799ce6a05c05237b9 Mon Sep 17 00:00:00 2001 From: Yasumasa Suenaga Date: Fri, 27 Mar 2026 13:26:49 +0000 Subject: [PATCH 072/359] 8380956: HexFormat shoud have @ValueBased Reviewed-by: rriggs, stuefe, liach --- src/java.base/share/classes/java/util/HexFormat.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/java.base/share/classes/java/util/HexFormat.java b/src/java.base/share/classes/java/util/HexFormat.java index aebb8b9af52..7d9fe08108d 100644 --- a/src/java.base/share/classes/java/util/HexFormat.java +++ b/src/java.base/share/classes/java/util/HexFormat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2024, Alibaba Group Holding Limited. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -26,6 +26,7 @@ package java.util; +import jdk.internal.ValueBased; import jdk.internal.access.JavaLangAccess; import jdk.internal.access.SharedSecrets; import jdk.internal.util.HexDigits; @@ -134,7 +135,7 @@ import java.nio.CharBuffer; * @since 17 */ - +@ValueBased public final class HexFormat { // Access to create strings from a byte array. From 426547d2c8df1d6b9b494eb28d0fbbdfe58c8821 Mon Sep 17 00:00:00 2001 From: Benjamin Peterson Date: Fri, 27 Mar 2026 14:56:54 +0000 Subject: [PATCH 073/359] 8380968: classfile package doc mentions nonexistent UtfEntry Reviewed-by: liach --- .../classes/java/lang/classfile/package-info.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 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 460f6699e7b..8bf5559df0a 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved. * 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,9 +493,9 @@ * * {@snippet lang="text" : * ClassElement = - * FieldModel*(UtfEntry name, Utf8Entry descriptor) - * | MethodModel*(UtfEntry name, Utf8Entry descriptor) - * | ModuleAttribute?(int flags, ModuleEntry moduleName, UtfEntry moduleVersion, + * FieldModel*(Utf8Entry name, Utf8Entry descriptor) + * | MethodModel*(Utf8Entry name, Utf8Entry descriptor) + * | ModuleAttribute?(int flags, ModuleEntry moduleName, Utf8Entry moduleVersion, * List requires, List opens, * List exports, List provides, * List uses) @@ -588,7 +588,7 @@ * | LabelTarget(Label label) * | LineNumber(int line) * | ExceptionCatch(Label tryStart, Label tryEnd, Label handler, ClassEntry exception) - * | LocalVariable(int slot, UtfEntry name, Utf8Entry type, Label startScope, Label endScope) + * | LocalVariable(int slot, Utf8Entry name, Utf8Entry type, Label startScope, Label endScope) * | LocalVariableType(int slot, Utf8Entry name, Utf8Entry type, Label startScope, Label endScope) * | CharacterRange(int rangeStart, int rangeEnd, int flags, Label startScope, Label endScope) * } From 1ed1bb8ccbc7ba0cbb54f4354c64d39b3ea64d90 Mon Sep 17 00:00:00 2001 From: Daisuke Yamazaki Date: Fri, 27 Mar 2026 15:52:13 +0000 Subject: [PATCH 074/359] 8379818: Refactor java/nio/file/Files/StreamLinesTest.java to use JUnit Reviewed-by: bpb --- .../java/nio/file/Files/StreamLinesTest.java | 63 ++++++++----------- 1 file changed, 25 insertions(+), 38 deletions(-) diff --git a/test/jdk/java/nio/file/Files/StreamLinesTest.java b/test/jdk/java/nio/file/Files/StreamLinesTest.java index 402b114ae0b..7812a4ceb89 100644 --- a/test/jdk/java/nio/file/Files/StreamLinesTest.java +++ b/test/jdk/java/nio/file/Files/StreamLinesTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * 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,18 +23,15 @@ /* @test * @bug 8072773 - * @library /test/lib /lib/testlibrary/bootlib - * @build java.base/java.util.stream.OpTestCase - * jdk.test.lib.RandomFactory - * @run testng/othervm StreamLinesTest + * @library /test/lib + * @build jdk.test.lib.RandomFactory + * @run junit/othervm StreamLinesTest * @summary Tests streams returned from Files.lines, primarily focused on * testing the file-channel-based stream stream with supported * character sets * @key randomness */ -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import java.io.BufferedReader; import java.io.BufferedWriter; @@ -50,13 +47,16 @@ import java.util.EnumSet; import java.util.List; import java.util.Random; import java.util.function.IntFunction; -import java.util.function.Supplier; -import java.util.stream.OpTestCase; import java.util.stream.Stream; -import java.util.stream.TestData; import jdk.test.lib.RandomFactory; -public class StreamLinesTest extends OpTestCase { +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 StreamLinesTest { enum LineSeparator { NONE(""), @@ -120,16 +120,15 @@ public class StreamLinesTest extends OpTestCase { } } - static Object[] of(String description, IntFunction lineGenerator, + static Arguments of(String description, IntFunction lineGenerator, IntFunction separatorGenerator, int n, Charset cs) { - return new Object[]{description, lineGenerator, separatorGenerator, n, cs}; + return Arguments.argumentSet(description, lineGenerator, separatorGenerator, n, cs); } private static final Random random = RandomFactory.getRandom(); - @DataProvider - public static Object[][] lines() { - List l = new ArrayList<>(); + static Stream lines() { + List l = new ArrayList<>(); // Include the three supported optimal-line charsets and one // which does not @@ -175,38 +174,26 @@ public class StreamLinesTest extends OpTestCase { 1024, charset)); } - return l.toArray(new Object[][]{}); + return l.stream(); } - @Test(dataProvider = "lines") - public void test(String description, - IntFunction lineGenerator, IntFunction separatorGenerator, + @ParameterizedTest + @MethodSource("lines") + public void test(IntFunction lineGenerator, IntFunction separatorGenerator, int lines, Charset cs) throws IOException { Path p = generateTempFileWithLines(lineGenerator, separatorGenerator, lines, cs, false); - Supplier> ss = () -> { - try { - return Files.lines(p, cs); - } - catch (IOException e) { - throw new RuntimeException(e); - } - }; - // Test without a separator at the end List expected = readAllLines(p, cs); - withData(TestData.Factory.ofSupplier("Lines with no separator at end", ss)) - .stream(s -> s) - .expectedResult(expected) - .exercise(); + try (Stream s = Files.lines(p, cs)) { + assertEquals(expected, s.toList()); + } // Test with a separator at the end writeLineSeparator(p, separatorGenerator, lines, cs); expected = readAllLines(p, cs); - withData(TestData.Factory.ofSupplier("Lines with separator at end", ss)) - .stream(s -> s) - .expectedResult(expected) - .exercise(); + try (Stream s = Files.lines(p, cs)) { + assertEquals(expected, s.toList()); + } } - } From ba700f105a1b65db8e905faa146884407ee13257 Mon Sep 17 00:00:00 2001 From: Vladimir Kozlov Date: Fri, 27 Mar 2026 16:16:09 +0000 Subject: [PATCH 075/359] 8381059: Add class name to deoptimization events and -Xlog:deoptimization=debug output Reviewed-by: dlong, aseoane --- src/hotspot/share/runtime/deoptimization.cpp | 53 ++++++++++++++------ 1 file changed, 37 insertions(+), 16 deletions(-) diff --git a/src/hotspot/share/runtime/deoptimization.cpp b/src/hotspot/share/runtime/deoptimization.cpp index 5fbe2842a2b..cfdcf52a5eb 100644 --- a/src/hotspot/share/runtime/deoptimization.cpp +++ b/src/hotspot/share/runtime/deoptimization.cpp @@ -2021,7 +2021,7 @@ static void post_deoptimization_event(nmethod* nm, #endif // INCLUDE_JFR static void log_deopt(nmethod* nm, Method* tm, intptr_t pc, frame& fr, int trap_bci, - const char* reason_name, const char* reason_action) { + const char* reason_name, const char* reason_action, const char* class_name) { LogTarget(Debug, deoptimization) lt; if (lt.is_enabled()) { LogStream ls(lt); @@ -2035,6 +2035,9 @@ static void log_deopt(nmethod* nm, Method* tm, intptr_t pc, frame& fr, int trap_ } ls.print("%s ", reason_name); ls.print("%s ", reason_action); + if (class_name != nullptr) { + ls.print("%s ", class_name); + } ls.print_cr("pc=" INTPTR_FORMAT " relative_pc=" INTPTR_FORMAT, pc, fr.pc() - nm->code_begin()); } @@ -2135,6 +2138,17 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* current, jint tr MethodData* trap_mdo = get_method_data(current, profiled_method, create_if_missing); + Symbol* class_name = nullptr; + bool unresolved = false; + if (unloaded_class_index >= 0) { + constantPoolHandle constants (current, trap_method->constants()); + if (constants->tag_at(unloaded_class_index).is_unresolved_klass()) { + class_name = constants->klass_name_at(unloaded_class_index); + unresolved = true; + } else if (constants->tag_at(unloaded_class_index).is_symbol()) { + class_name = constants->symbol_at(unloaded_class_index); + } + } { // Log Deoptimization event for JFR, UL and event system Method* tm = trap_method(); const char* reason_name = trap_reason_name(reason); @@ -2142,10 +2156,24 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* current, jint tr intptr_t pc = p2i(fr.pc()); JFR_ONLY(post_deoptimization_event(nm, tm, trap_bci, trap_bc, reason, action);) - log_deopt(nm, tm, pc, fr, trap_bci, reason_name, reason_action); - Events::log_deopt_message(current, "Uncommon trap: reason=%s action=%s pc=" INTPTR_FORMAT " method=%s @ %d %s", + + ResourceMark rm; + + const char* class_name_str = nullptr; + const char* class_name_msg = nullptr; + stringStream st, stm; + if (class_name != nullptr) { + class_name->print_symbol_on(&st); + class_name_str = st.freeze(); + stm.print("class=%s ", class_name_str); + class_name_msg = stm.freeze(); + } else { + class_name_msg = ""; + } + log_deopt(nm, tm, pc, fr, trap_bci, reason_name, reason_action, class_name_str); + Events::log_deopt_message(current, "Uncommon trap: reason=%s action=%s pc=" INTPTR_FORMAT " method=%s @ %d %s%s", reason_name, reason_action, pc, - tm->name_and_sig_as_C_string(), trap_bci, nm->compiler_name()); + tm->name_and_sig_as_C_string(), trap_bci, class_name_msg, nm->compiler_name()); } // Print a bunch of diagnostics, if requested. @@ -2173,20 +2201,13 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* current, jint tr #endif nm->log_identity(xtty); } - Symbol* class_name = nullptr; - bool unresolved = false; - if (unloaded_class_index >= 0) { - constantPoolHandle constants (current, trap_method->constants()); - if (constants->tag_at(unloaded_class_index).is_unresolved_klass()) { - class_name = constants->klass_name_at(unloaded_class_index); - unresolved = true; - if (xtty != nullptr) + if (class_name != nullptr) { + if (xtty != nullptr) { + if (unresolved) { xtty->print(" unresolved='1'"); - } else if (constants->tag_at(unloaded_class_index).is_symbol()) { - class_name = constants->symbol_at(unloaded_class_index); - } - if (xtty != nullptr) + } xtty->name(class_name); + } } if (xtty != nullptr && trap_mdo != nullptr && (int)reason < (int)MethodData::_trap_hist_limit) { // Dump the relevant MDO state. From a4d160e64614fa2f61a57b3eedb333fb665723f5 Mon Sep 17 00:00:00 2001 From: Vladimir Kozlov Date: Fri, 27 Mar 2026 16:19:22 +0000 Subject: [PATCH 076/359] 8380828: AOTCodeReader::fix_relocations() should be called before ICache::invalidate_range() is called Reviewed-by: adinn, asmehra --- src/hotspot/share/code/aotCodeCache.cpp | 65 +++++++++++++++---------- src/hotspot/share/code/aotCodeCache.hpp | 17 +++++-- src/hotspot/share/code/codeBlob.cpp | 56 +++++++++------------ src/hotspot/share/code/codeBlob.hpp | 19 ++++---- 4 files changed, 84 insertions(+), 73 deletions(-) diff --git a/src/hotspot/share/code/aotCodeCache.cpp b/src/hotspot/share/code/aotCodeCache.cpp index 4ad5e12d808..030e2684bfc 100644 --- a/src/hotspot/share/code/aotCodeCache.cpp +++ b/src/hotspot/share/code/aotCodeCache.cpp @@ -539,6 +539,9 @@ AOTCodeReader::AOTCodeReader(AOTCodeCache* cache, AOTCodeEntry* entry) { _load_buffer = cache->cache_buffer(); _read_position = 0; _lookup_failed = false; + _name = nullptr; + _reloc_data = nullptr; + _oop_maps = nullptr; } void AOTCodeReader::set_read_position(uint pos) { @@ -903,16 +906,6 @@ bool AOTCodeCache::store_code_blob(CodeBlob& blob, AOTCodeEntry::Kind entry_kind has_oop_maps = true; } -#ifndef PRODUCT - // Write asm remarks - if (!cache->write_asm_remarks(blob)) { - return false; - } - if (!cache->write_dbg_strings(blob)) { - return false; - } -#endif /* PRODUCT */ - if (!cache->write_relocations(blob)) { if (!cache->failed()) { // We may miss an address in AOT table - skip this code blob. @@ -921,6 +914,16 @@ bool AOTCodeCache::store_code_blob(CodeBlob& blob, AOTCodeEntry::Kind entry_kind return false; } +#ifndef PRODUCT + // Write asm remarks after relocation info + if (!cache->write_asm_remarks(blob)) { + return false; + } + if (!cache->write_dbg_strings(blob)) { + return false; + } +#endif /* PRODUCT */ + uint entry_size = cache->_write_position - entry_position; AOTCodeEntry* entry = new(cache) AOTCodeEntry(entry_kind, encode_id(entry_kind, id), entry_position, entry_size, name_offset, name_size, @@ -982,39 +985,28 @@ CodeBlob* AOTCodeReader::compile_code_blob(const char* name) { set_lookup_failed(); // Skip this blob return nullptr; } + _name = stored_name; // Read archived code blob uint offset = entry_position + _entry->blob_offset(); CodeBlob* archived_blob = (CodeBlob*)addr(offset); offset += archived_blob->size(); - address reloc_data = (address)addr(offset); + _reloc_data = (address)addr(offset); offset += archived_blob->relocation_size(); set_read_position(offset); - ImmutableOopMapSet* oop_maps = nullptr; if (_entry->has_oop_maps()) { - oop_maps = read_oop_map_set(); + _oop_maps = read_oop_map_set(); } - CodeBlob* code_blob = CodeBlob::create(archived_blob, - stored_name, - reloc_data, - oop_maps - ); + // CodeBlob::restore() calls AOTCodeReader::restore() + CodeBlob* code_blob = CodeBlob::create(archived_blob, this); + if (code_blob == nullptr) { // no space left in CodeCache return nullptr; } -#ifndef PRODUCT - code_blob->asm_remarks().init(); - read_asm_remarks(code_blob->asm_remarks()); - code_blob->dbg_strings().init(); - read_dbg_strings(code_blob->dbg_strings()); -#endif // PRODUCT - - fix_relocations(code_blob); - #ifdef ASSERT LogStreamHandle(Trace, aot, codecache, stubs) log; if (log.is_enabled()) { @@ -1025,6 +1017,25 @@ CodeBlob* AOTCodeReader::compile_code_blob(const char* name) { return code_blob; } +void AOTCodeReader::restore(CodeBlob* code_blob) { + precond(AOTCodeCache::is_on_for_use()); + precond(_name != nullptr); + precond(_reloc_data != nullptr); + + code_blob->set_name(_name); + code_blob->restore_mutable_data(_reloc_data); + code_blob->set_oop_maps(_oop_maps); + + fix_relocations(code_blob); + +#ifndef PRODUCT + code_blob->asm_remarks().init(); + read_asm_remarks(code_blob->asm_remarks()); + code_blob->dbg_strings().init(); + read_dbg_strings(code_blob->dbg_strings()); +#endif // PRODUCT +} + // ------------ process code and data -------------- // Can't use -1. It is valid value for jump to iteself destination diff --git a/src/hotspot/share/code/aotCodeCache.hpp b/src/hotspot/share/code/aotCodeCache.hpp index 7996388faa6..b0d39ff3e08 100644 --- a/src/hotspot/share/code/aotCodeCache.hpp +++ b/src/hotspot/share/code/aotCodeCache.hpp @@ -402,11 +402,13 @@ private: void clear_lookup_failed() { _lookup_failed = false; } bool lookup_failed() const { return _lookup_failed; } - AOTCodeEntry* aot_code_entry() { return (AOTCodeEntry*)_entry; } -public: - AOTCodeReader(AOTCodeCache* cache, AOTCodeEntry* entry); + // Values used by restore(code_blob). + // They should be set before calling it. + const char* _name; + address _reloc_data; + ImmutableOopMapSet* _oop_maps; - CodeBlob* compile_code_blob(const char* name); + AOTCodeEntry* aot_code_entry() { return (AOTCodeEntry*)_entry; } ImmutableOopMapSet* read_oop_map_set(); @@ -415,6 +417,13 @@ public: void read_asm_remarks(AsmRemarks& asm_remarks); void read_dbg_strings(DbgStrings& dbg_strings); #endif // PRODUCT + +public: + AOTCodeReader(AOTCodeCache* cache, AOTCodeEntry* entry); + + CodeBlob* compile_code_blob(const char* name); + + void restore(CodeBlob* code_blob); }; // code cache internal runtime constants area used by AOT code diff --git a/src/hotspot/share/code/codeBlob.cpp b/src/hotspot/share/code/codeBlob.cpp index fcc0b42a461..5b68ce48c87 100644 --- a/src/hotspot/share/code/codeBlob.cpp +++ b/src/hotspot/share/code/codeBlob.cpp @@ -22,6 +22,7 @@ * */ +#include "code/aotCodeCache.hpp" #include "code/codeBlob.hpp" #include "code/codeCache.hpp" #include "code/relocInfo.hpp" @@ -188,22 +189,6 @@ CodeBlob::CodeBlob(const char* name, CodeBlobKind kind, int size, uint16_t heade assert(_mutable_data == blob_end(), "sanity"); } -void CodeBlob::restore_mutable_data(address reloc_data) { - // Relocation data is now stored as part of the mutable data area; allocate it before copy relocations - if (_mutable_data_size > 0) { - _mutable_data = (address)os::malloc(_mutable_data_size, mtCode); - if (_mutable_data == nullptr) { - vm_exit_out_of_memory(_mutable_data_size, OOM_MALLOC_ERROR, "codebuffer: no space for mutable data"); - } - } else { - _mutable_data = blob_end(); // default value - } - if (_relocation_size > 0) { - assert(_mutable_data_size > 0, "relocation is part of mutable data section"); - memcpy((address)relocation_begin(), reloc_data, relocation_size()); - } -} - void CodeBlob::purge() { assert(_mutable_data != nullptr, "should never be null"); if (_mutable_data != blob_end()) { @@ -240,6 +225,23 @@ void CodeBlob::print_code_on(outputStream* st) { Disassembler::decode(this, st); } +#if INCLUDE_CDS +void CodeBlob::restore_mutable_data(address reloc_data) { + // Relocation data is now stored as part of the mutable data area; allocate it before copy relocations + if (_mutable_data_size > 0) { + _mutable_data = (address)os::malloc(_mutable_data_size, mtCode); + if (_mutable_data == nullptr) { + vm_exit_out_of_memory(_mutable_data_size, OOM_MALLOC_ERROR, "codebuffer: no space for mutable data"); + } + } else { + _mutable_data = blob_end(); // default value + } + if (_relocation_size > 0) { + assert(_mutable_data_size > 0, "relocation is part of mutable data section"); + memcpy((address)relocation_begin(), reloc_data, relocation_size()); + } +} + void CodeBlob::prepare_for_archiving_impl() { set_name(nullptr); _oop_maps = nullptr; @@ -269,24 +271,15 @@ void CodeBlob::post_restore() { vptr(_kind)->post_restore(this); } -CodeBlob* CodeBlob::restore(address code_cache_buffer, - const char* name, - address archived_reloc_data, - ImmutableOopMapSet* archived_oop_maps) +CodeBlob* CodeBlob::restore(address code_cache_buffer, AOTCodeReader* reader) { copy_to(code_cache_buffer); CodeBlob* code_blob = (CodeBlob*)code_cache_buffer; - code_blob->set_name(name); - code_blob->restore_mutable_data(archived_reloc_data); - code_blob->set_oop_maps(archived_oop_maps); + reader->restore(code_blob); return code_blob; } -CodeBlob* CodeBlob::create(CodeBlob* archived_blob, - const char* name, - address archived_reloc_data, - ImmutableOopMapSet* archived_oop_maps - ) +CodeBlob* CodeBlob::create(CodeBlob* archived_blob, AOTCodeReader* reader) { ThreadInVMfromUnknown __tiv; // get to VM state in case we block on CodeCache_lock @@ -298,10 +291,7 @@ CodeBlob* CodeBlob::create(CodeBlob* archived_blob, MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); address code_cache_buffer = (address)CodeCache::allocate(size, CodeBlobType::NonNMethod); if (code_cache_buffer != nullptr) { - blob = archived_blob->restore(code_cache_buffer, - name, - archived_reloc_data, - archived_oop_maps); + blob = archived_blob->restore(code_cache_buffer, reader); assert(blob != nullptr, "sanity check"); // Flush the code block @@ -315,6 +305,8 @@ CodeBlob* CodeBlob::create(CodeBlob* archived_blob, return blob; } +#endif // INCLUDE_CDS + //----------------------------------------------------------------------------------------- // Creates a RuntimeBlob from a CodeBuffer and copy code and relocation info. diff --git a/src/hotspot/share/code/codeBlob.hpp b/src/hotspot/share/code/codeBlob.hpp index 0469b6c71b1..1f9cf0adcc3 100644 --- a/src/hotspot/share/code/codeBlob.hpp +++ b/src/hotspot/share/code/codeBlob.hpp @@ -34,6 +34,7 @@ #include "utilities/align.hpp" #include "utilities/macros.hpp" +class AOTCodeReader; class ImmutableOopMap; class ImmutableOopMapSet; class JNIHandleBlock; @@ -107,9 +108,6 @@ class CodeBlob { friend class VMStructs; friend class JVMCIVMStructs; -private: - void restore_mutable_data(address reloc_data); - protected: // order fields from large to small to minimize padding between fields ImmutableOopMapSet* _oop_maps; // OopMap for this CodeBlob @@ -169,8 +167,8 @@ protected: void operator delete(void* p) { } - void prepare_for_archiving_impl(); - void post_restore_impl(); + void prepare_for_archiving_impl() NOT_CDS_RETURN; + void post_restore_impl() NOT_CDS_RETURN; public: @@ -304,6 +302,9 @@ public: void use_strings(DbgStrings &strings) { _dbg_strings.share(strings); } #endif +#if INCLUDE_CDS + void restore_mutable_data(address reloc_data); + void copy_to(address buffer) { memcpy(buffer, this, this->size()); } @@ -314,11 +315,9 @@ public: // methods to restore a blob from AOT code cache into the CodeCache void post_restore(); - CodeBlob* restore(address code_cache_buffer, const char* name, address archived_reloc_data, ImmutableOopMapSet* archived_oop_maps); - static CodeBlob* create(CodeBlob* archived_blob, - const char* name, - address archived_reloc_data, - ImmutableOopMapSet* archived_oop_maps); + CodeBlob* restore(address code_cache_buffer, AOTCodeReader* reader); + static CodeBlob* create(CodeBlob* archived_blob, AOTCodeReader* reader); +#endif }; //---------------------------------------------------------------------------------------------------- From 28e96d76b0c7a792cc88bb9183e9cb6a83fcaba2 Mon Sep 17 00:00:00 2001 From: William Kemper Date: Fri, 27 Mar 2026 17:57:30 +0000 Subject: [PATCH 077/359] 8377976: GenShen: Explicit GC requests must clear concurrent gc request cancellation Reviewed-by: kdnilsen --- .../shenandoah/shenandoahGenerationalControlThread.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp index ec33e671053..064f43ffd6b 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp @@ -121,10 +121,11 @@ void ShenandoahGenerationalControlThread::check_for_request(ShenandoahGCRequest& assert(request.generation != nullptr, "Must know which generation to use for degenerated cycle"); } } else { - if (request.cause == GCCause::_shenandoah_concurrent_gc) { - // This is a regulator request. It is also possible that the regulator "canceled" an old mark, - // so we can clear that here. This clear operation will only clear the cancellation if it is - // a regulator request. + if (request.cause == GCCause::_shenandoah_concurrent_gc || ShenandoahCollectorPolicy::is_explicit_gc(request.cause)) { + // This is a regulator request or an explicit gc request. Note that an explicit gc request is allowed to + // "upgrade" a regulator request. It is possible that the regulator "canceled" an old mark, so we must + // clear that cancellation here or the explicit gc cycle will erroneously detect it as a cancellation. + // This clear operation will only clear the cancellation if it was set by regulator request. _heap->clear_cancellation(GCCause::_shenandoah_concurrent_gc); } request.generation = _requested_generation; From 79668b007db71921938d7639ba15f8ce44682f4f Mon Sep 17 00:00:00 2001 From: Vladimir Kozlov Date: Fri, 27 Mar 2026 18:13:38 +0000 Subject: [PATCH 078/359] 8380710: nmethod::finalize_relocations() should be called before ICache::invalidate_range() is called Reviewed-by: adinn, dlong --- src/hotspot/share/asm/codeBuffer.cpp | 4 ---- src/hotspot/share/code/codeBlob.cpp | 4 ++++ src/hotspot/share/code/nmethod.cpp | 6 ++++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/hotspot/share/asm/codeBuffer.cpp b/src/hotspot/share/asm/codeBuffer.cpp index ba525588f32..c6078c0ceee 100644 --- a/src/hotspot/share/asm/codeBuffer.cpp +++ b/src/hotspot/share/asm/codeBuffer.cpp @@ -32,7 +32,6 @@ #include "oops/methodCounters.hpp" #include "oops/methodData.hpp" #include "oops/oop.inline.hpp" -#include "runtime/icache.hpp" #include "runtime/safepointVerifiers.hpp" #include "utilities/align.hpp" #include "utilities/copy.hpp" @@ -745,9 +744,6 @@ void CodeBuffer::copy_code_to(CodeBlob* dest_blob) { // Done moving code bytes; were they the right size? assert((int)align_up(dest.total_content_size(), oopSize) == dest_blob->content_size(), "sanity"); - - // Flush generated code - ICache::invalidate_range(dest_blob->code_begin(), dest_blob->code_size()); } // Move all my code into another code buffer. Consult applicable diff --git a/src/hotspot/share/code/codeBlob.cpp b/src/hotspot/share/code/codeBlob.cpp index 5b68ce48c87..9961381c31d 100644 --- a/src/hotspot/share/code/codeBlob.cpp +++ b/src/hotspot/share/code/codeBlob.cpp @@ -40,6 +40,7 @@ #include "prims/forte.hpp" #include "prims/jvmtiExport.hpp" #include "runtime/handles.inline.hpp" +#include "runtime/icache.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/javaFrameAnchor.hpp" #include "runtime/jniHandles.inline.hpp" @@ -324,6 +325,9 @@ RuntimeBlob::RuntimeBlob( align_up(cb->total_relocation_size(), oopSize)) { cb->copy_code_and_locs_to(this); + + // Flush generated code + ICache::invalidate_range(code_begin(), code_size()); } void RuntimeBlob::free(RuntimeBlob* blob) { diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 5a6ed8ab3ed..0e2aa208854 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -66,6 +66,7 @@ #include "runtime/flags/flagSetting.hpp" #include "runtime/frame.inline.hpp" #include "runtime/handles.inline.hpp" +#include "runtime/icache.hpp" #include "runtime/jniHandles.inline.hpp" #include "runtime/orderAccess.hpp" #include "runtime/os.hpp" @@ -1253,6 +1254,9 @@ void nmethod::post_init() { finalize_relocations(); + // Flush generated code + ICache::invalidate_range(code_begin(), code_size()); + Universe::heap()->register_nmethod(this); DEBUG_ONLY(Universe::heap()->verify_nmethod(this)); @@ -1584,8 +1588,6 @@ nmethod* nmethod::relocate(CodeBlobType code_blob_type) { // Attempt to start using the copy if (nm_copy->make_in_use()) { - ICache::invalidate_range(nm_copy->code_begin(), nm_copy->code_size()); - methodHandle mh(Thread::current(), nm_copy->method()); nm_copy->method()->set_code(mh, nm_copy); From 7ffc4a4fb4cc520c4f469865645764045e72cb26 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Fri, 27 Mar 2026 19:23:39 +0000 Subject: [PATCH 079/359] 8381019: Remove AppContext usage from AccessBridge Reviewed-by: serb, kizune --- .../accessibility/AccessibleContext.java | 19 +--- .../share/classes/module-info.java | 3 +- .../share/classes/sun/awt/AWTAccessor.java | 2 - .../accessibility/internal/AccessBridge.java | 89 +++---------------- 4 files changed, 13 insertions(+), 100 deletions(-) diff --git a/src/java.desktop/share/classes/javax/accessibility/AccessibleContext.java b/src/java.desktop/share/classes/javax/accessibility/AccessibleContext.java index 096ca3aef44..e7fc58b0825 100644 --- a/src/java.desktop/share/classes/javax/accessibility/AccessibleContext.java +++ b/src/java.desktop/share/classes/javax/accessibility/AccessibleContext.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,6 @@ import java.beans.PropertyChangeSupport; import java.util.Locale; import sun.awt.AWTAccessor; -import sun.awt.AppContext; /** * {@code AccessibleContext} represents the minimum information all accessible @@ -84,24 +83,8 @@ public abstract class AccessibleContext { */ protected AccessibleContext() {} - /** - * The {@code AppContext} that should be used to dispatch events for this - * {@code AccessibleContext}. - */ - private volatile AppContext targetAppContext; - static { AWTAccessor.setAccessibleContextAccessor(new AWTAccessor.AccessibleContextAccessor() { - @Override - public void setAppContext(AccessibleContext accessibleContext, AppContext appContext) { - accessibleContext.targetAppContext = appContext; - } - - @Override - public AppContext getAppContext(AccessibleContext accessibleContext) { - return accessibleContext.targetAppContext; - } - @Override public Object getNativeAXResource(AccessibleContext accessibleContext) { return accessibleContext.nativeAXResource; diff --git a/src/java.desktop/share/classes/module-info.java b/src/java.desktop/share/classes/module-info.java index 6d34d934194..57392f71321 100644 --- a/src/java.desktop/share/classes/module-info.java +++ b/src/java.desktop/share/classes/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 @@ module java.desktop { // qualified exports may be inserted at build time // see make/GensrcModuleInfo.gmk exports sun.awt to - jdk.accessibility, jdk.unsupported.desktop; exports java.awt.dnd.peer to jdk.unsupported.desktop; diff --git a/src/java.desktop/share/classes/sun/awt/AWTAccessor.java b/src/java.desktop/share/classes/sun/awt/AWTAccessor.java index f98118171b4..143d7e6198c 100644 --- a/src/java.desktop/share/classes/sun/awt/AWTAccessor.java +++ b/src/java.desktop/share/classes/sun/awt/AWTAccessor.java @@ -755,8 +755,6 @@ public final class AWTAccessor { * An accessor object for the AccessibleContext class */ public interface AccessibleContextAccessor { - void setAppContext(AccessibleContext accessibleContext, AppContext appContext); - AppContext getAppContext(AccessibleContext accessibleContext); Object getNativeAXResource(AccessibleContext accessibleContext); void setNativeAXResource(AccessibleContext accessibleContext, Object value); } diff --git a/src/jdk.accessibility/windows/classes/com/sun/java/accessibility/internal/AccessBridge.java b/src/jdk.accessibility/windows/classes/com/sun/java/accessibility/internal/AccessBridge.java index c932d0f73ff..718acf6a6b8 100644 --- a/src/jdk.accessibility/windows/classes/com/sun/java/accessibility/internal/AccessBridge.java +++ b/src/jdk.accessibility/windows/classes/com/sun/java/accessibility/internal/AccessBridge.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2026, Oracle and/or its affiliates. All rights reserved. * 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,9 +120,6 @@ import com.sun.java.accessibility.util.AccessibilityEventMonitor; import com.sun.java.accessibility.util.EventQueueMonitor; import com.sun.java.accessibility.util.SwingEventMonitor; import com.sun.java.accessibility.util.Translator; -import sun.awt.AWTAccessor; -import sun.awt.AppContext; -import sun.awt.SunToolkit; /* * Note: This class has to be public. It's loaded from the VM like this: @@ -5292,7 +5289,6 @@ public final class AccessBridge { ac = a.getAccessibleContext(); } if (ac != null) { - InvocationUtils.registerAccessibleContext(ac, AppContext.getAppContext()); accessBridge.debugString("[INFO]: AccessibleContext: " + ac); String propertyName = e.getPropertyName(); @@ -5385,11 +5381,9 @@ public final class AccessBridge { if (e.getOldValue() instanceof AccessibleContext) { oldAC = (AccessibleContext) e.getOldValue(); - InvocationUtils.registerAccessibleContext(oldAC, AppContext.getAppContext()); } if (e.getNewValue() instanceof AccessibleContext) { newAC = (AccessibleContext) e.getNewValue(); - InvocationUtils.registerAccessibleContext(newAC, AppContext.getAppContext()); } accessBridge.debugString("[INFO]: - about to call propertyChildChange() old AC: " + oldAC + "new AC: " + newAC); accessBridge.propertyChildChange(e, ac, oldAC, newAC); @@ -5455,8 +5449,6 @@ public final class AccessBridge { prevAC = newAC; accessBridge.debugString("[INFO]: - about to call propertyActiveDescendentChange() AC: " + ac + " old AC: " + oldAC + "new AC: " + newAC); - InvocationUtils.registerAccessibleContext(oldAC, AppContext.getAppContext()); - InvocationUtils.registerAccessibleContext(newAC, AppContext.getAppContext()); accessBridge.propertyActiveDescendentChange(e, ac, oldAC, newAC); } @@ -5493,14 +5485,12 @@ public final class AccessBridge { // selected. The menu itself is selected. FocusEvent e = new FocusEvent(penult, FocusEvent.FOCUS_GAINED); AccessibleContext context = penult.getAccessibleContext(); - InvocationUtils.registerAccessibleContext(context, SunToolkit.targetToAppContext(penult)); accessBridge.focusGained(e, context); } else if (penult instanceof JPopupMenu) { // This is a popup with an item selected FocusEvent e = new FocusEvent(last, FocusEvent.FOCUS_GAINED); AccessibleContext focusedAC = last.getAccessibleContext(); - InvocationUtils.registerAccessibleContext(focusedAC, SunToolkit.targetToAppContext(last)); accessBridge.debugString("[INFO]: - about to call focusGained() AC: " + focusedAC); accessBridge.focusGained(e, focusedAC); } @@ -5511,7 +5501,6 @@ public final class AccessBridge { FocusEvent e = new FocusEvent(focusOwner, FocusEvent.FOCUS_GAINED); AccessibleContext focusedAC = focusOwner.getAccessibleContext(); - InvocationUtils.registerAccessibleContext(focusedAC, SunToolkit.targetToAppContext(focusOwner)); accessBridge.debugString("[INFO]: - about to call focusGained() AC: " + focusedAC); accessBridge.focusGained(e, focusedAC); } @@ -5524,7 +5513,6 @@ public final class AccessBridge { if (a != null) { accessBridge.debugString("[INFO]: - about to call focusLost() AC: " + a.getAccessibleContext()); AccessibleContext context = a.getAccessibleContext(); - InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext()); accessBridge.focusLost(e, context); } } @@ -5538,7 +5526,6 @@ public final class AccessBridge { Accessible a = Translator.getAccessible(e.getSource()); if (a != null) { AccessibleContext context = a.getAccessibleContext(); - InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext()); accessBridge.caretUpdate(e, context); } } @@ -5553,7 +5540,6 @@ public final class AccessBridge { Accessible a = Translator.getAccessible(e.getSource()); if (a != null) { AccessibleContext context = a.getAccessibleContext(); - InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext()); accessBridge.mouseClicked(e, context); } } @@ -5564,7 +5550,6 @@ public final class AccessBridge { Accessible a = Translator.getAccessible(e.getSource()); if (a != null) { AccessibleContext context = a.getAccessibleContext(); - InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext()); accessBridge.mouseEntered(e, context); } } @@ -5575,7 +5560,6 @@ public final class AccessBridge { Accessible a = Translator.getAccessible(e.getSource()); if (a != null) { AccessibleContext context = a.getAccessibleContext(); - InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext()); accessBridge.mouseExited(e, context); } } @@ -5586,7 +5570,6 @@ public final class AccessBridge { Accessible a = Translator.getAccessible(e.getSource()); if (a != null) { AccessibleContext context = a.getAccessibleContext(); - InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext()); accessBridge.mousePressed(e, context); } } @@ -5597,7 +5580,6 @@ public final class AccessBridge { Accessible a = Translator.getAccessible(e.getSource()); if (a != null) { AccessibleContext context = a.getAccessibleContext(); - InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext()); accessBridge.mouseReleased(e, context); } } @@ -5611,7 +5593,6 @@ public final class AccessBridge { Accessible a = Translator.getAccessible(e.getSource()); if (a != null) { AccessibleContext context = a.getAccessibleContext(); - InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext()); accessBridge.menuCanceled(e, context); } } @@ -5622,7 +5603,6 @@ public final class AccessBridge { Accessible a = Translator.getAccessible(e.getSource()); if (a != null) { AccessibleContext context = a.getAccessibleContext(); - InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext()); accessBridge.menuDeselected(e, context); } } @@ -5633,7 +5613,6 @@ public final class AccessBridge { Accessible a = Translator.getAccessible(e.getSource()); if (a != null) { AccessibleContext context = a.getAccessibleContext(); - InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext()); accessBridge.menuSelected(e, context); } } @@ -5644,7 +5623,6 @@ public final class AccessBridge { Accessible a = Translator.getAccessible(e.getSource()); if (a != null) { AccessibleContext context = a.getAccessibleContext(); - InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext()); accessBridge.popupMenuCanceled(e, context); } } @@ -5655,7 +5633,6 @@ public final class AccessBridge { Accessible a = Translator.getAccessible(e.getSource()); if (a != null) { AccessibleContext context = a.getAccessibleContext(); - InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext()); accessBridge.popupMenuWillBecomeInvisible(e, context); } } @@ -5666,7 +5643,6 @@ public final class AccessBridge { Accessible a = Translator.getAccessible(e.getSource()); if (a != null) { AccessibleContext context = a.getAccessibleContext(); - InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext()); accessBridge.popupMenuWillBecomeVisible(e, context); } } @@ -7227,8 +7203,7 @@ public final class AccessBridge { private static class InvocationUtils { /** - * Invokes a {@code Callable} in the {@code AppContext} of the given {@code Accessible} - * and waits for it to finish blocking the caller thread. + * Invokes a {@code Callable} and waits for it to finish blocking the caller thread. * * @param callable the {@code Callable} to invoke * @param accessibleTable the {@code AccessibleExtendedTable} which would be used to find the right context @@ -7246,8 +7221,7 @@ public final class AccessBridge { } /** - * Invokes a {@code Callable} in the {@code AppContext} of the given {@code Accessible} - * and waits for it to finish blocking the caller thread. + * Invokes a {@code Callable} and waits for it to finish blocking the caller thread. * * @param callable the {@code Callable} to invoke * @param accessible the {@code Accessible} which would be used to find the right context @@ -7269,8 +7243,7 @@ public final class AccessBridge { } /** - * Invokes a {@code Callable} in the {@code AppContext} of the given {@code Component} - * and waits for it to finish blocking the caller thread. + * Invokes a {@code Callable} and waits for it to finish blocking the caller thread. * * @param callable the {@code Callable} to invoke * @param component the {@code Component} which would be used to find the right context @@ -7281,12 +7254,11 @@ public final class AccessBridge { */ public static T invokeAndWait(final Callable callable, final Component component) { - return invokeAndWait(callable, SunToolkit.targetToAppContext(component)); + return invokeAndWait(callable); } /** - * Invokes a {@code Callable} in the {@code AppContext} mapped to the given {@code AccessibleContext} - * and waits for it to finish blocking the caller thread. + * Invokes a {@code Callable} and waits for it to finish blocking the caller thread. * * @param callable the {@code Callable} to invoke * @param accessibleContext the {@code AccessibleContext} which would be used to determine the right @@ -7297,45 +7269,26 @@ public final class AccessBridge { */ public static T invokeAndWait(final Callable callable, final AccessibleContext accessibleContext) { - AppContext targetContext = AWTAccessor.getAccessibleContextAccessor() - .getAppContext(accessibleContext); - if (targetContext != null) { - return invokeAndWait(callable, targetContext); - } else { - // Normally this should not happen, unmapped context provided and - // the target AppContext is unknown. - - // Try to recover in case the context is a translator. - if (accessibleContext instanceof Translator) { - Object source = ((Translator)accessibleContext).getSource(); - if (source instanceof Component) { - return invokeAndWait(callable, (Component)source); - } - } - } - throw new RuntimeException("Unmapped AccessibleContext used to dispatch event: " + accessibleContext); + return invokeAndWait(callable); } - private static T invokeAndWait(final Callable callable, - final AppContext targetAppContext) { + private static T invokeAndWait(final Callable callable) { final CallableWrapper wrapper = new CallableWrapper(callable); try { - invokeAndWait(wrapper, targetAppContext); + invokeAndWait(wrapper); T result = wrapper.getResult(); - updateAppContextMap(result, targetAppContext); return result; } catch (final Exception e) { throw new RuntimeException(e); } } - private static void invokeAndWait(final Runnable runnable, - final AppContext appContext) + private static void invokeAndWait(final Runnable runnable) throws InterruptedException, InvocationTargetException { - EventQueue eq = SunToolkit.getSystemEventQueueImplPP(appContext); Object lock = new Object(); Toolkit source = Toolkit.getDefaultToolkit(); + EventQueue eq = source.getSystemEventQueue(); InvocationEvent event = new InvocationEvent(source, runnable, lock, true); synchronized (lock) { @@ -7349,26 +7302,6 @@ public final class AccessBridge { } } - /** - * Maps the {@code AccessibleContext} to the {@code AppContext} which should be used - * to dispatch events related to the {@code AccessibleContext} - * @param accessibleContext the {@code AccessibleContext} for the mapping - * @param targetContext the {@code AppContext} for the mapping - */ - public static void registerAccessibleContext(final AccessibleContext accessibleContext, - final AppContext targetContext) { - if (accessibleContext != null) { - AWTAccessor.getAccessibleContextAccessor().setAppContext(accessibleContext, targetContext); - } - } - - private static void updateAppContextMap(final T accessibleContext, - final AppContext targetContext) { - if (accessibleContext instanceof AccessibleContext) { - registerAccessibleContext((AccessibleContext)accessibleContext, targetContext); - } - } - private static class CallableWrapper implements Runnable { private final Callable callable; private volatile T object; From 7e4ac140d9faad938bda3e60a00cc5e8ed0fe7d7 Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Fri, 27 Mar 2026 19:55:32 +0000 Subject: [PATCH 080/359] 8380686: GenerateOopMap logging crashes in rewriter Reviewed-by: matsaave, phubner --- .../share/interpreter/bytecodeTracer.cpp | 30 +++++++------ .../jtreg/runtime/interpreter/JsrLogging.jasm | 43 +++++++++++++++++++ .../runtime/interpreter/JsrLoggingTest.java | 40 +++++++++++++++++ 3 files changed, 99 insertions(+), 14 deletions(-) create mode 100644 test/hotspot/jtreg/runtime/interpreter/JsrLogging.jasm create mode 100644 test/hotspot/jtreg/runtime/interpreter/JsrLoggingTest.java diff --git a/src/hotspot/share/interpreter/bytecodeTracer.cpp b/src/hotspot/share/interpreter/bytecodeTracer.cpp index 2610a8a2bd6..4578a3eec4e 100644 --- a/src/hotspot/share/interpreter/bytecodeTracer.cpp +++ b/src/hotspot/share/interpreter/bytecodeTracer.cpp @@ -52,9 +52,9 @@ class BytecodePrinter { Bytecodes::Code _code; address _next_pc; // current decoding position int _flags; - bool _is_linked; + bool _use_cp_cache; - bool is_linked() const { return _is_linked; } + bool use_cp_cache() const { return _use_cp_cache; } void align() { _next_pc = align_up(_next_pc, sizeof(jint)); } int get_byte() { return *(jbyte*) _next_pc++; } // signed int get_index_u1() { return *(address)_next_pc++; } // returns 0x00 - 0xff as an int @@ -69,7 +69,7 @@ class BytecodePrinter { bool is_wide() const { return _is_wide; } Bytecodes::Code raw_code() const { return Bytecodes::Code(_code); } ConstantPool* constants() const { return method()->constants(); } - ConstantPoolCache* cpcache() const { assert(is_linked(), "must be"); return constants()->cache(); } + ConstantPoolCache* cpcache() const { assert(use_cp_cache(), "must be"); return constants()->cache(); } void print_constant(int i, outputStream* st); void print_cpcache_entry(int cpc_index, outputStream* st); @@ -94,8 +94,9 @@ class BytecodePrinter { ResourceMark rm; bool method_changed = _current_method != method(); _current_method = method(); - _is_linked = method->method_holder()->is_linked(); - assert(_is_linked, "this function must be called on methods that are already executing"); + _use_cp_cache = method->constants()->cache() != nullptr; + assert(method->method_holder()->is_linked(), + "this function must be called on methods that are already executing"); if (method_changed) { // Note 1: This code will not work as expected with true MT/MP. @@ -150,7 +151,8 @@ class BytecodePrinter { // BytecodeStream, which will skip wide bytecodes. void trace(const methodHandle& method, address bcp, outputStream* st) { _current_method = method(); - _is_linked = method->method_holder()->is_linked(); + // This may be called during linking after bytecodes are rewritten to point to the cpCache. + _use_cp_cache = method->constants()->cache() != nullptr; ResourceMark rm; Bytecodes::Code code = Bytecodes::code_at(method(), bcp); // Set is_wide @@ -301,7 +303,7 @@ void BytecodePrinter::print_invokedynamic(int indy_index, int cp_index, outputSt if (ClassPrinter::has_mode(_flags, ClassPrinter::PRINT_DYNAMIC)) { print_bsm(cp_index, st); - if (is_linked()) { + if (use_cp_cache()) { ResolvedIndyEntry* indy_entry = constants()->resolved_indy_entry_at(indy_index); st->print(" ResolvedIndyEntry: "); indy_entry->print_on(st); @@ -365,7 +367,7 @@ void BytecodePrinter::print_attributes(int bci, outputStream* st) { { int cp_index; if (Bytecodes::uses_cp_cache(raw_code())) { - assert(is_linked(), "fast ldc bytecode must be in linked classes"); + assert(use_cp_cache(), "fast ldc bytecode must be in linked classes"); int obj_index = get_index_u1(); cp_index = constants()->object_to_cp_index(obj_index); } else { @@ -380,7 +382,7 @@ void BytecodePrinter::print_attributes(int bci, outputStream* st) { { int cp_index; if (Bytecodes::uses_cp_cache(raw_code())) { - assert(is_linked(), "fast ldc bytecode must be in linked classes"); + assert(use_cp_cache(), "fast ldc bytecode must be in linked classes"); int obj_index = get_native_index_u2(); cp_index = constants()->object_to_cp_index(obj_index); } else { @@ -510,7 +512,7 @@ void BytecodePrinter::print_attributes(int bci, outputStream* st) { case Bytecodes::_getfield: { int cp_index; - if (is_linked()) { + if (use_cp_cache()) { int field_index = get_native_index_u2(); cp_index = cpcache()->resolved_field_entry_at(field_index)->constant_pool_index(); } else { @@ -525,7 +527,7 @@ void BytecodePrinter::print_attributes(int bci, outputStream* st) { case Bytecodes::_invokestatic: { int cp_index; - if (is_linked()) { + if (use_cp_cache()) { int method_index = get_native_index_u2(); ResolvedMethodEntry* method_entry = cpcache()->resolved_method_entry_at(method_index); cp_index = method_entry->constant_pool_index(); @@ -533,7 +535,7 @@ void BytecodePrinter::print_attributes(int bci, outputStream* st) { if (raw_code() == Bytecodes::_invokehandle && ClassPrinter::has_mode(_flags, ClassPrinter::PRINT_METHOD_HANDLE)) { - assert(is_linked(), "invokehandle is only in rewritten methods"); + assert(use_cp_cache(), "invokehandle is only in rewritten methods"); method_entry->print_on(st); if (method_entry->has_appendix()) { st->print(" appendix: "); @@ -550,7 +552,7 @@ void BytecodePrinter::print_attributes(int bci, outputStream* st) { case Bytecodes::_invokeinterface: { int cp_index; - if (is_linked()) { + if (use_cp_cache()) { int method_index = get_native_index_u2(); cp_index = cpcache()->resolved_method_entry_at(method_index)->constant_pool_index(); } else { @@ -566,7 +568,7 @@ void BytecodePrinter::print_attributes(int bci, outputStream* st) { { int indy_index; int cp_index; - if (is_linked()) { + if (use_cp_cache()) { indy_index = get_native_index_u4(); cp_index = constants()->resolved_indy_entry_at(indy_index)->constant_pool_index(); } else { diff --git a/test/hotspot/jtreg/runtime/interpreter/JsrLogging.jasm b/test/hotspot/jtreg/runtime/interpreter/JsrLogging.jasm new file mode 100644 index 00000000000..ac1d0fffa49 --- /dev/null +++ b/test/hotspot/jtreg/runtime/interpreter/JsrLogging.jasm @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +public super class JsrLogging version 49:0 +{ + static Field i:I; + + public static Method test:"()V" + stack 3 locals 1 + { + nop; + jsr LABEL; + bipush 66; + LABEL: + bipush 55; + putstatic Field i:"I"; + getstatic Field java/lang/System.out:"Ljava/io/PrintStream;"; + ldc String "hello"; + invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/String;)V"; + return; + } +} diff --git a/test/hotspot/jtreg/runtime/interpreter/JsrLoggingTest.java b/test/hotspot/jtreg/runtime/interpreter/JsrLoggingTest.java new file mode 100644 index 00000000000..36a8f7e9b76 --- /dev/null +++ b/test/hotspot/jtreg/runtime/interpreter/JsrLoggingTest.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8380686 + * @summary Ensure logging works while processing jsr while linking. + * @library /test/lib + * @compile JsrLogging.jasm + * @run main/othervm -Xlog:generateoopmap=debug JsrLoggingTest + */ + +public class JsrLoggingTest { + public static void main(String[] args) { + for (int i = 0; i < 10; ++i) { + JsrLogging.test(); + } + System.out.println("PASSED"); + } +} From ac242550fea72a3c37e61014f5204f72e27e2cbd Mon Sep 17 00:00:00 2001 From: Jeremy Wood Date: Sat, 28 Mar 2026 09:33:31 +0000 Subject: [PATCH 081/359] 8379347: VoiceOver Doesn't Correctly Identify JToggleButtons as "toggle buttons" Reviewed-by: honkar, kizune, prr --- .../awt/a11y/CheckboxAccessibility.m | 14 +++- .../awt/a11y/CommonComponentAccessibility.m | 1 + .../8379347/VoiceOverToggleButtonRole.java | 69 +++++++++++++++++++ 3 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 test/jdk/javax/accessibility/8379347/VoiceOverToggleButtonRole.java diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/CheckboxAccessibility.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/CheckboxAccessibility.m index f2dbf60d92d..a5faf255440 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/CheckboxAccessibility.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/CheckboxAccessibility.m @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. * 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,18 @@ return NSAccessibilityCheckBoxRole; } +- (NSAccessibilitySubrole _Nullable)accessibilitySubrole +{ + JNIEnv *env = [ThreadUtilities getJNIEnv]; + if (env != NULL) { + NSString *javaRole = [self javaRole]; + if ([javaRole isEqualToString:@"togglebutton"]) { + return NSAccessibilityToggleSubrole; + } + } + return [super accessibilitySubrole]; +} + - (id _Nonnull) accessibilityValue { AWT_ASSERT_APPKIT_THREAD; diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/CommonComponentAccessibility.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/CommonComponentAccessibility.m index 0f0a395c597..45e8f981f50 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/CommonComponentAccessibility.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/CommonComponentAccessibility.m @@ -136,6 +136,7 @@ static jobject sAccessibilityClass = NULL; [rolesMap setObject:@"StaticTextAccessibility" forKey:@"label"]; [rolesMap setObject:@"RadiobuttonAccessibility" forKey:@"radiobutton"]; [rolesMap setObject:@"CheckboxAccessibility" forKey:@"checkbox"]; + [rolesMap setObject:@"CheckboxAccessibility" forKey:@"togglebutton"]; [rolesMap setObject:@"SliderAccessibility" forKey:@"slider"]; [rolesMap setObject:@"ScrollAreaAccessibility" forKey:@"scrollpane"]; [rolesMap setObject:@"ScrollBarAccessibility" forKey:@"scrollbar"]; diff --git a/test/jdk/javax/accessibility/8379347/VoiceOverToggleButtonRole.java b/test/jdk/javax/accessibility/8379347/VoiceOverToggleButtonRole.java new file mode 100644 index 00000000000..31264f69dd8 --- /dev/null +++ b/test/jdk/javax/accessibility/8379347/VoiceOverToggleButtonRole.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.swing.JToggleButton; +import javax.swing.JFrame; + +/* + * @test + * @key headful + * @bug 8379347 + * @summary manual test for VoiceOver reading JToggleButtons correctly + * @requires os.family == "mac" + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual VoiceOverToggleButtonRole + */ + +public class VoiceOverToggleButtonRole { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + INSTRUCTIONS (Mac-only): + 1. Open VoiceOver + 2. Move the VoiceOver cursor over the JToggleButton. + 3. Observe how VoiceOver identifies the toggle button. + + Expected behavior: VoiceOver should identify it as a + "toggle button" initially. (VO does still say "to select + or deselect this checkbox", though.) + + If you select the link using "Accessibility Inspector": + it should identify its subrole as AXToggle. + """; + + PassFailJFrame.builder() + .title("VoiceOverToggleButtonRole Instruction") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(VoiceOverToggleButtonRole::createUI) + .build() + .awaitAndCheck(); + } + + private static JFrame createUI() { + JFrame frame = new JFrame(); + frame.getContentPane().add(new JToggleButton("JToggleButton")); + frame.pack(); + return frame; + } +} From 6520c95a79ee2e5a249827c49c75b0db48d63209 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Sat, 28 Mar 2026 17:36:58 +0000 Subject: [PATCH 082/359] 8380771: Add missing CodeBlob Vptr implementations Reviewed-by: kvn, asmehra --- src/hotspot/share/code/codeBlob.cpp | 30 +++++------ src/hotspot/share/code/codeBlob.hpp | 77 +++++++++++++++++++++++++---- 2 files changed, 84 insertions(+), 23 deletions(-) diff --git a/src/hotspot/share/code/codeBlob.cpp b/src/hotspot/share/code/codeBlob.cpp index 9961381c31d..a7d939e590d 100644 --- a/src/hotspot/share/code/codeBlob.cpp +++ b/src/hotspot/share/code/codeBlob.cpp @@ -79,8 +79,10 @@ const BufferBlob::Vptr BufferBlob::_vpntr; const RuntimeStub::Vptr RuntimeStub::_vpntr; const SingletonBlob::Vptr SingletonBlob::_vpntr; const DeoptimizationBlob::Vptr DeoptimizationBlob::_vpntr; +const SafepointBlob::Vptr SafepointBlob::_vpntr; #ifdef COMPILER2 const ExceptionBlob::Vptr ExceptionBlob::_vpntr; +const UncommonTrapBlob::Vptr UncommonTrapBlob::_vpntr; #endif // COMPILER2 const UpcallStub::Vptr UpcallStub::_vpntr; @@ -386,7 +388,7 @@ void RuntimeBlob::trace_new_stub(RuntimeBlob* stub, const char* name1, const cha // Implementation of BufferBlob BufferBlob::BufferBlob(const char* name, CodeBlobKind kind, int size, uint16_t header_size) -: RuntimeBlob(name, kind, size, header_size) + : RuntimeBlob(name, kind, size, header_size) {} BufferBlob* BufferBlob::create(const char* name, uint buffer_size) { @@ -621,8 +623,8 @@ DeoptimizationBlob::DeoptimizationBlob( int unpack_with_reexecution_offset, int frame_size ) -: SingletonBlob("DeoptimizationBlob", CodeBlobKind::Deoptimization, cb, - size, sizeof(DeoptimizationBlob), frame_size, oop_maps) + : SingletonBlob("DeoptimizationBlob", CodeBlobKind::Deoptimization, cb, + size, sizeof(DeoptimizationBlob), frame_size, oop_maps) { _unpack_offset = unpack_offset; _unpack_with_exception = unpack_with_exception_offset; @@ -671,8 +673,8 @@ UncommonTrapBlob::UncommonTrapBlob( OopMapSet* oop_maps, int frame_size ) -: SingletonBlob("UncommonTrapBlob", CodeBlobKind::UncommonTrap, cb, - size, sizeof(UncommonTrapBlob), frame_size, oop_maps) + : SingletonBlob("UncommonTrapBlob", CodeBlobKind::UncommonTrap, cb, + size, sizeof(UncommonTrapBlob), frame_size, oop_maps) {} @@ -703,8 +705,8 @@ ExceptionBlob::ExceptionBlob( OopMapSet* oop_maps, int frame_size ) -: SingletonBlob("ExceptionBlob", CodeBlobKind::Exception, cb, - size, sizeof(ExceptionBlob), frame_size, oop_maps) + : SingletonBlob("ExceptionBlob", CodeBlobKind::Exception, cb, + size, sizeof(ExceptionBlob), frame_size, oop_maps) {} @@ -737,8 +739,8 @@ SafepointBlob::SafepointBlob( OopMapSet* oop_maps, int frame_size ) -: SingletonBlob("SafepointBlob", CodeBlobKind::Safepoint, cb, - size, sizeof(SafepointBlob), frame_size, oop_maps) + : SingletonBlob(cb->name(), CodeBlobKind::Safepoint, cb, + size, sizeof(SafepointBlob), frame_size, oop_maps) {} @@ -755,7 +757,7 @@ SafepointBlob* SafepointBlob::create( blob = new (size) SafepointBlob(cb, size, oop_maps, frame_size); } - trace_new_stub(blob, "SafepointBlob"); + trace_new_stub(blob, "SafepointBlob - ", blob->name()); return blob; } @@ -895,7 +897,7 @@ void CodeBlob::dump_for_addr(address addr, outputStream* st, bool verbose) const } } if (is_nmethod()) { - nmethod* nm = (nmethod*)this; + nmethod* nm = as_nmethod(); ResourceMark rm; st->print(INTPTR_FORMAT " is at entry_point+%d in (nmethod*)" INTPTR_FORMAT, p2i(addr), (int)(addr - nm->entry_point()), p2i(nm)); @@ -931,7 +933,7 @@ void RuntimeStub::print_on_impl(outputStream* st) const { RuntimeBlob::print_on_impl(st); st->print("Runtime Stub (" INTPTR_FORMAT "): ", p2i(this)); st->print_cr("%s", name()); - Disassembler::decode((RuntimeBlob*)this, st); + Disassembler::decode((CodeBlob*)this, st); } void RuntimeStub::print_value_on_impl(outputStream* st) const { @@ -942,7 +944,7 @@ void SingletonBlob::print_on_impl(outputStream* st) const { ttyLocker ttyl; RuntimeBlob::print_on_impl(st); st->print_cr("%s", name()); - Disassembler::decode((RuntimeBlob*)this, st); + Disassembler::decode((CodeBlob*)this, st); } void SingletonBlob::print_value_on_impl(outputStream* st) const { @@ -960,7 +962,7 @@ void UpcallStub::print_on_impl(outputStream* st) const { oop recv = JNIHandles::resolve(_receiver); st->print("Receiver MH="); recv->print_on(st); - Disassembler::decode((RuntimeBlob*)this, st); + Disassembler::decode((CodeBlob*)this, st); } void UpcallStub::print_value_on_impl(outputStream* st) const { diff --git a/src/hotspot/share/code/codeBlob.hpp b/src/hotspot/share/code/codeBlob.hpp index 1f9cf0adcc3..6a1686b80e2 100644 --- a/src/hotspot/share/code/codeBlob.hpp +++ b/src/hotspot/share/code/codeBlob.hpp @@ -98,7 +98,9 @@ enum class CodeBlobKind : u1 { class UpcallStub; // for as_upcall_stub() class RuntimeStub; // for as_runtime_stub() class JavaFrameAnchor; // for UpcallStub::jfa_for_frame +class BufferBlob; class AdapterBlob; +class SingletonBlob; class ExceptionBlob; class DeoptimizationBlob; class SafepointBlob; @@ -185,8 +187,19 @@ public: // Typing bool is_nmethod() const { return _kind == CodeBlobKind::Nmethod; } - bool is_buffer_blob() const { return _kind == CodeBlobKind::Buffer; } + // we may want to check for an actual buffer blob or subtype instance + bool is_buffer_blob(bool strict=true) const { + if (strict) { + return _kind == CodeBlobKind::Buffer; + } else { + return (_kind == CodeBlobKind::Buffer || + _kind == CodeBlobKind::Adapter || + _kind == CodeBlobKind::Vtable || + _kind == CodeBlobKind::MHAdapter); + } + } bool is_runtime_stub() const { return _kind == CodeBlobKind::RuntimeStub; } + // singleton blobs are never directly implemented bool is_deoptimization_stub() const { return _kind == CodeBlobKind::Deoptimization; } #ifdef COMPILER2 bool is_uncommon_trap_stub() const { return _kind == CodeBlobKind::UncommonTrap; } @@ -196,6 +209,12 @@ public: bool is_exception_stub() const { return false; } #endif bool is_safepoint_stub() const { return _kind == CodeBlobKind::Safepoint; } + bool is_singleton_blob() const { + return (is_deoptimization_stub() || + is_uncommon_trap_stub() || + is_exception_stub() || + is_safepoint_stub()); + } 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::MHAdapter; } @@ -205,8 +224,12 @@ public: 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; } + // we may want to force an actual buffer blob or subtype instance + BufferBlob* as_buffer_blob(bool strict = true) const { assert(is_buffer_blob(), "must be %sbuffer blob", (strict ? "strict " : "")); return (BufferBlob*) this; } AdapterBlob* as_adapter_blob() const { assert(is_adapter_blob(), "must be adapter blob"); return (AdapterBlob*) this; } ExceptionBlob* as_exception_blob() const { assert(is_exception_stub(), "must be exception stub"); return (ExceptionBlob*) this; } + // this will always return a subtype instance + SingletonBlob* as_singleton_blob() const { assert(is_singleton_blob(), "must be singleton blob"); return (SingletonBlob*) this; } DeoptimizationBlob* as_deoptimization_blob() const { assert(is_deoptimization_stub(), "must be deopt stub"); return (DeoptimizationBlob*) this; } SafepointBlob* as_safepoint_blob() const { assert(is_safepoint_stub(), "must be safepoint stub"); return (SafepointBlob*) this; } UpcallStub* as_upcall_stub() const { assert(is_upcall_stub(), "must be upcall stub"); return (UpcallStub*) this; } @@ -387,10 +410,10 @@ class BufferBlob: public RuntimeBlob { class Vptr : public RuntimeBlob::Vptr { void print_on(const CodeBlob* instance, outputStream* st) const override { - ((const BufferBlob*)instance)->print_on_impl(st); + instance->as_buffer_blob(false)->print_on_impl(st); } void print_value_on(const CodeBlob* instance, outputStream* st) const override { - ((const BufferBlob*)instance)->print_value_on_impl(st); + instance->as_buffer_blob(false)->print_value_on_impl(st); } }; @@ -486,10 +509,17 @@ class RuntimeStub: public RuntimeBlob { address entry_point() const { return code_begin(); } + void post_restore_impl() { + trace_new_stub(this, "RuntimeStub - ", name()); + } + void print_on_impl(outputStream* st) const; void print_value_on_impl(outputStream* st) const; class Vptr : public RuntimeBlob::Vptr { + void post_restore(CodeBlob* instance) const override { + instance->as_runtime_stub()->post_restore_impl(); + } void print_on(const CodeBlob* instance, outputStream* st) const override { instance->as_runtime_stub()->print_on_impl(st); } @@ -531,10 +561,10 @@ class SingletonBlob: public RuntimeBlob { class Vptr : public RuntimeBlob::Vptr { void print_on(const CodeBlob* instance, outputStream* st) const override { - ((const SingletonBlob*)instance)->print_on_impl(st); + instance->as_singleton_blob()->print_on_impl(st); } void print_value_on(const CodeBlob* instance, outputStream* st) const override { - ((const SingletonBlob*)instance)->print_value_on_impl(st); + instance->as_singleton_blob()->print_value_on_impl(st); } }; @@ -605,20 +635,28 @@ class DeoptimizationBlob: public SingletonBlob { _uncommon_trap_offset = offset; assert(contains(code_begin() + _uncommon_trap_offset), "must be PC inside codeblob"); } - address uncommon_trap() const { return code_begin() + _uncommon_trap_offset; } + address uncommon_trap() const { return (EnableJVMCI ? code_begin() + _uncommon_trap_offset : nullptr); } void set_implicit_exception_uncommon_trap_offset(int offset) { _implicit_exception_uncommon_trap_offset = offset; assert(contains(code_begin() + _implicit_exception_uncommon_trap_offset), "must be PC inside codeblob"); } - address implicit_exception_uncommon_trap() const { return code_begin() + _implicit_exception_uncommon_trap_offset; } + address implicit_exception_uncommon_trap() const { return (EnableJVMCI ? code_begin() + _implicit_exception_uncommon_trap_offset : nullptr); } #endif // INCLUDE_JVMCI + void post_restore_impl() { + trace_new_stub(this, "DeoptimizationBlob"); + } + void print_value_on_impl(outputStream* st) const; class Vptr : public SingletonBlob::Vptr { + void post_restore(CodeBlob* instance) const override { + instance->as_deoptimization_blob()->post_restore_impl(); + } + void print_value_on(const CodeBlob* instance, outputStream* st) const override { - ((const DeoptimizationBlob*)instance)->print_value_on_impl(st); + instance->as_deoptimization_blob()->print_value_on_impl(st); } }; @@ -648,6 +686,16 @@ class UncommonTrapBlob: public SingletonBlob { OopMapSet* oop_maps, int frame_size ); + void post_restore_impl() { + trace_new_stub(this, "UncommonTrapBlob"); + } + class Vptr : public SingletonBlob::Vptr { + void post_restore(CodeBlob* instance) const override { + instance->as_uncommon_trap_blob()->post_restore_impl(); + } + }; + + static const Vptr _vpntr; }; @@ -678,7 +726,7 @@ class ExceptionBlob: public SingletonBlob { class Vptr : public SingletonBlob::Vptr { void post_restore(CodeBlob* instance) const override { - ((ExceptionBlob*)instance)->post_restore_impl(); + instance->as_exception_blob()->post_restore_impl(); } }; @@ -708,6 +756,17 @@ class SafepointBlob: public SingletonBlob { OopMapSet* oop_maps, int frame_size ); + + void post_restore_impl() { + trace_new_stub(this, "SafepointBlob - ", name()); + } + class Vptr : public SingletonBlob::Vptr { + void post_restore(CodeBlob* instance) const override { + instance->as_safepoint_blob()->post_restore_impl(); + } + }; + + static const Vptr _vpntr; }; //---------------------------------------------------------------------------------------------------- From 66a34be54a43c110f8dd577775fc213ed912faa7 Mon Sep 17 00:00:00 2001 From: Jaikiran Pai Date: Sun, 29 Mar 2026 02:01:46 +0000 Subject: [PATCH 083/359] 8273874: LdapClient can trigger memory leak Reviewed-by: dfuchs --- .../classes/com/sun/jndi/ldap/Connection.java | 9 +- .../classes/com/sun/jndi/ldap/EventQueue.java | 9 +- .../sun/jndi/ldap/NamingEventNotifier.java | 6 +- test/jdk/com/sun/jndi/ldap/LdapTCCLTest.java | 323 ++++++++++++++++++ 4 files changed, 336 insertions(+), 11 deletions(-) create mode 100644 test/jdk/com/sun/jndi/ldap/LdapTCCLTest.java diff --git a/src/java.naming/share/classes/com/sun/jndi/ldap/Connection.java b/src/java.naming/share/classes/com/sun/jndi/ldap/Connection.java index dcb739a8697..1e0a924f12c 100644 --- a/src/java.naming/share/classes/com/sun/jndi/ldap/Connection.java +++ b/src/java.naming/share/classes/com/sun/jndi/ldap/Connection.java @@ -57,6 +57,8 @@ import javax.net.ssl.HandshakeCompletedListener; import javax.net.ssl.SSLPeerUnverifiedException; import javax.security.sasl.SaslException; +import jdk.internal.misc.InnocuousThread; + /** * A thread that creates a connection to an LDAP server. * After the connection, the thread reads from the connection. @@ -112,9 +114,6 @@ import javax.security.sasl.SaslException; * for v2. * %%% made public for access by LdapSasl %%% * - * @author Vincent Ryan - * @author Rosanna Lee - * @author Jagane Sundar */ public final class Connection implements Runnable { @@ -254,7 +253,7 @@ public final class Connection implements Runnable { throw ce; } - worker = new Thread(this); + worker = InnocuousThread.newSystemThread("LDAP Connection", this); worker.setDaemon(true); worker.start(); } @@ -912,7 +911,7 @@ public final class Connection implements Runnable { // //////////////////////////////////////////////////////////////////////////// - + @Override public void run() { byte inbuf[]; // Buffer for reading incoming bytes int inMsgId; // Message id of incoming response diff --git a/src/java.naming/share/classes/com/sun/jndi/ldap/EventQueue.java b/src/java.naming/share/classes/com/sun/jndi/ldap/EventQueue.java index 4f1cb9ec6a7..7d45d058c68 100644 --- a/src/java.naming/share/classes/com/sun/jndi/ldap/EventQueue.java +++ b/src/java.naming/share/classes/com/sun/jndi/ldap/EventQueue.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2026, Oracle and/or its affiliates. All rights reserved. * 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,13 +36,13 @@ import javax.naming.event.NamingListener; import javax.naming.ldap.UnsolicitedNotificationEvent; import javax.naming.ldap.UnsolicitedNotificationListener; +import jdk.internal.misc.InnocuousThread; + /** * Package private class used by EventSupport to dispatch events. * This class implements an event queue, and a dispatcher thread that * dequeues and dispatches events from the queue. * - * Pieces stolen from sun.misc.Queue. - * * @author Bill Shannon (from javax.mail.event) * @author Rosanna Lee (modified for JNDI-related events) */ @@ -71,7 +71,7 @@ final class EventQueue implements Runnable { // package private EventQueue() { - qThread = new Thread(this); + qThread = InnocuousThread.newSystemThread("LDAP Event Dispatcher", this); qThread.setDaemon(true); // not a user thread qThread.start(); } @@ -141,6 +141,7 @@ final class EventQueue implements Runnable { /** * Pull events off the queue and dispatch them. */ + @Override public void run() { QueueElement qe; diff --git a/src/java.naming/share/classes/com/sun/jndi/ldap/NamingEventNotifier.java b/src/java.naming/share/classes/com/sun/jndi/ldap/NamingEventNotifier.java index 40a8173b768..0e30c1c1d38 100644 --- a/src/java.naming/share/classes/com/sun/jndi/ldap/NamingEventNotifier.java +++ b/src/java.naming/share/classes/com/sun/jndi/ldap/NamingEventNotifier.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2026, Oracle and/or its affiliates. All rights reserved. * 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 javax.naming.ldap.LdapName; import java.util.Vector; import com.sun.jndi.toolkit.ctx.Continuation; +import jdk.internal.misc.InnocuousThread; /** * Gathers information to generate events by using the Persistent Search @@ -86,7 +87,7 @@ final class NamingEventNotifier implements Runnable { namingListeners = new Vector<>(); namingListeners.addElement(firstListener); - worker = new Thread(this); + worker = InnocuousThread.newSystemThread("LDAP Event Notifier", this); worker.setDaemon(true); // not a user thread worker.start(); } @@ -111,6 +112,7 @@ final class NamingEventNotifier implements Runnable { * For each result, create the appropriate NamingEvent and * queue to be dispatched to listeners. */ + @Override public void run() { try { Continuation cont = new Continuation(); diff --git a/test/jdk/com/sun/jndi/ldap/LdapTCCLTest.java b/test/jdk/com/sun/jndi/ldap/LdapTCCLTest.java new file mode 100644 index 00000000000..21f355442d7 --- /dev/null +++ b/test/jdk/com/sun/jndi/ldap/LdapTCCLTest.java @@ -0,0 +1,323 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.net.Socket; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.Collection; +import java.util.Collections; +import java.util.Hashtable; + +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.event.EventContext; +import javax.naming.event.NamingEvent; +import javax.naming.event.NamingExceptionEvent; +import javax.naming.event.ObjectChangeListener; + +import jdk.test.lib.net.URIBuilder; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import static java.nio.charset.StandardCharsets.US_ASCII; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.fail; + +/* + * @test + * @bug 8273874 + * @summary Verify that the system threads that LdapContext creates for its internal + * use do not hold on to the application specific context classloaders + * @comment The test uses ThreadGroup.enumerate() to find live threads and check their + * context classsloader, ThreadGroup of virtual threads don't enumerate threads, + * so we skip this test when the main thread is a virtual thread. + * @requires test.thread.factory != "Virtual" + * @library lib/ /test/lib + * @build BaseLdapServer + * LdapMessage + * jdk.test.lib.net.URIBuilder + * @run junit ${test.main.class} + */ +class LdapTCCLTest { + + private static final String LOOKUP_NAME = "CN=duke"; + + private static final byte BER_TYPE_LDAP_SEQUENCE = 0x30; + private static final byte BER_TYPE_INTEGER = 0x02; + private static final byte BER_TYPE_OCTET_STRING = 0x04; + private static final byte BER_TYPE_ENUM = 0x0a; + private static final byte BER_TYPE_LDAP_SEARCH_RESULT_ENTRY_OP = 0x64; + private static final byte BER_TYPE_LDAP_SEARCH_RESULT_DONE_OP = 0x65; + private static final byte LDAP_SEARCH_RESULT_DONE_SUCCESS = 0x00; + + private static Server server; + private static Hashtable envProps; + + @BeforeAll + static void beforeAll() throws Exception { + server = new Server(); + server.start(); + System.err.println("server started at " + server.getInetAddress() + + ":" + server.getPort()); + + final Hashtable props = new Hashtable<>(); + props.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); + final String providerUrl = URIBuilder.newBuilder() + .scheme("ldap") + .host(server.getInetAddress().getHostAddress()) + .port(server.getPort()) + .build().toString(); + props.put(Context.PROVIDER_URL, providerUrl); + // explicitly set LDAP version to 3 to prevent LDAP BIND requests + // during LdapCtx instantiation + props.put("java.naming.ldap.version", "3"); + + envProps = props; + } + + @AfterAll + static void afterAll() throws Exception { + if (server != null) { + System.err.println("stopping server " + server.getInetAddress() + + ":" + server.getPort()); + server.close(); + } + } + + /* + * Sets a test specific Thread context classloader and then creates a InitialContext + * backed by a LdapCtxFactory and looks up an arbitrary name. The test then verifies + * that none of the live Threads (including any created for the internal LDAP connection + * management) have their context classloader set to the test specific classloader. + */ + @Test + void testLdapCtxCreation() throws Exception { + try (final URLClassLoader urlc = new URLClassLoader(new URL[0])) { + final ClassLoader previous = Thread.currentThread().getContextClassLoader(); + Context ctx = null; + try { + // switch the TCCL to a test specific one + Thread.currentThread().setContextClassLoader(urlc); + + // create the LDAP Context and initiate a lookup() + // to allow for the underlying LDAP connection management + // infrastructure to create the necessary Thread(s) + ctx = new InitialContext(envProps); + + System.err.println("issuing ldap request against " + + envProps.get(Context.PROVIDER_URL) + " using context " + ctx); + final Object result = ctx.lookup(LOOKUP_NAME); + System.err.println("lookup returned " + result); + assertNotNull(result, "Context.lookup() returned null"); + + // verify that none of the live Thread(s) other than the current Thread + // have their TCCL set to the one set by the test. i.e. verify that the + // context classloader hasn't leaked into Thread(s) that may have been + // created by the LDAP connection management code. + assertTCCL(urlc, Collections.singleton(Thread.currentThread())); + } finally { + if (ctx != null) { + ctx.close(); + } + Thread.currentThread().setContextClassLoader(previous); + } + } + } + + /* + * Sets a test specific Thread context classloader and then creates a InitialContext + * backed by a LdapCtxFactory and adds a NamingListener. The test then verifies + * that none of the live Threads (including any newly created ones during the + * NamingListener registration) have their context classloader set to the test + * specific classloader. + */ + @Test + void testAddNamingListener() throws Exception { + try (final URLClassLoader urlc = new URLClassLoader(new URL[0])) { + final ClassLoader previous = Thread.currentThread().getContextClassLoader(); + EventContext ctx = null; + try { + // switch the TCCL to a test specific one + Thread.currentThread().setContextClassLoader(urlc); + + ctx = (EventContext) (new InitialContext(envProps).lookup(LOOKUP_NAME)); + // add a NamingListener to exercise the Thread creation in the internals + // of LdapCtx + ctx.addNamingListener(LOOKUP_NAME, EventContext.OBJECT_SCOPE, new Listener()); + // verify that none of the live Thread(s) other than the current Thread + // have their TCCL set to the one set by the test. i.e. verify that the + // context classloader hasn't leaked into Thread(s) that may have been + // created by the LDAP naming listener code. + assertTCCL(urlc, Collections.singleton(Thread.currentThread())); + } finally { + if (ctx != null) { + ctx.close(); + } + Thread.currentThread().setContextClassLoader(previous); + } + } + } + + /* + * Verifies that none of the live threads have their context classloader set to + * the given "notExpected" classloader. + */ + private static void assertTCCL(final ClassLoader notExpected, + final Collection threadsToIgnore) { + ThreadGroup topMostThreadGroup = Thread.currentThread().getThreadGroup(); + assertNotNull(topMostThreadGroup, + "ThreadGroup for current thread " + Thread.currentThread() + " was null"); + while (topMostThreadGroup.getParent() != null) { + topMostThreadGroup = topMostThreadGroup.getParent(); + } + // recursively enumerate the threads in the top most thread group + final Thread[] threads = new Thread[1024]; + final int numThreads = topMostThreadGroup.enumerate(threads); + // verify the threads + int numFailedThreads = 0; + final StringBuilder diagnosticMsg = new StringBuilder(); + for (int i = 0; i < numThreads; i++) { + final Thread t = threads[i]; + if (threadsToIgnore.contains(t)) { + continue; // skip verification of the thread + } + System.err.println("verifying " + t); + if (t.getContextClassLoader() == notExpected) { + // Thread has an unexpected context classloader + numFailedThreads++; + // for debugging track the stacktrace of the thread + // that failed the check + diagnosticMsg.append("FAILED - ").append(t) + .append(" is using unexpected context classloader: ") + .append(notExpected) + .append(", its current activity is:\n"); + for (StackTraceElement ste : t.getStackTrace()) { + diagnosticMsg.append("\t").append(ste).append("\n"); + } + } + } + if (numFailedThreads > 0) { + // for debugging print out the stacktrace of the + // Thread(s) that failed the check + System.err.println(diagnosticMsg); + fail(numFailedThreads + " Thread(s) had unexpected context classloader " + + notExpected); + } + } + + private static final class Server extends BaseLdapServer { + + private Server() throws IOException { + super(); + } + + // handles and responds to the incoming LDAP request + @Override + protected void handleRequest(final Socket socket, + final LdapMessage request, + final OutputStream out) throws IOException { + switch (request.getOperation()) { + case SEARCH_REQUEST: { + System.err.println("responding to SEARCH_REQUEST with id: " + + request.getMessageID() + " on socket " + socket); + // write out a search response + final byte[] rsp = makeSearchResponse((byte) request.getMessageID(), LOOKUP_NAME); + out.write(rsp); + out.flush(); + System.err.println("wrote response for message: " + request.getMessageID()); + break; + } + default: { + throw new IOException("unexpected operation type: " + request.getOperation() + + ", request: " + request); + } + } + } + + // constructs and returns a byte[] response containing the following (in that order): + // - Search Result Entry + // - Search Result Done + private static byte[] makeSearchResponse(final byte msgId, final String dn) + throws IOException { + final ByteArrayOutputStream bout = new ByteArrayOutputStream(); + final byte msgIdLen = 1; + + // write the BER elements + // each BER element is 3 parts: + // Type, length, value + + // Search Result Entry BER element (refer to LDAPv3 wire format for details) + bout.write(BER_TYPE_LDAP_SEQUENCE); + bout.write(dn.length() + 9); + bout.write(new byte[]{BER_TYPE_INTEGER, msgIdLen, msgId}); + bout.write(BER_TYPE_LDAP_SEARCH_RESULT_ENTRY_OP); + bout.write(dn.length() + 2); + bout.write(BER_TYPE_OCTET_STRING); + bout.write(dn.length()); + bout.write(dn.getBytes(US_ASCII)); + bout.write(BER_TYPE_LDAP_SEQUENCE); + // 0 length for the LDAP sequence, implying no attributes in this Search Result Entry + bout.write(0); + + bout.write(makeSearchResultDone(msgId)); + + return bout.toByteArray(); + } + + // Search Result Done BER element (refer to LDAPv3 wire format for details) + private static byte[] makeSearchResultDone(final byte msgId) throws IOException { + final ByteArrayOutputStream bout = new ByteArrayOutputStream(); + final byte msgIdLen = 1; + final String matchedDN = ""; + bout.write(BER_TYPE_LDAP_SEQUENCE); + bout.write(matchedDN.length() + 12); + bout.write(new byte[]{BER_TYPE_INTEGER, msgIdLen, msgId}); + bout.write(BER_TYPE_LDAP_SEARCH_RESULT_DONE_OP); + bout.write(7); + bout.write(new byte[]{BER_TYPE_ENUM, 1, LDAP_SEARCH_RESULT_DONE_SUCCESS}); + // the matched DN + bout.write(BER_TYPE_OCTET_STRING); + bout.write(matchedDN.length()); + bout.write(matchedDN.getBytes(US_ASCII)); + // 0 length implies no diagnostic message + bout.write(new byte[]{BER_TYPE_OCTET_STRING, 0}); + return bout.toByteArray(); + } + } + + private static final class Listener implements ObjectChangeListener { + + @Override + public void namingExceptionThrown(final NamingExceptionEvent evt) { + System.err.println("namingExceptionThrown() called for " + evt); + } + + @Override + public void objectChanged(final NamingEvent evt) { + System.err.println("objectChanged() called for " + evt); + } + } +} From eb96bfb2a538e60f4ff0c682100931d3cf8da8d2 Mon Sep 17 00:00:00 2001 From: jonghoonpark Date: Mon, 30 Mar 2026 02:58:19 +0000 Subject: [PATCH 084/359] 8379873: Remove undefined debugging declarations in os_windows.cpp Reviewed-by: dholmes, ayang --- src/hotspot/os/windows/os_windows.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index 18d047348cb..9d8fb45f0d1 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -2528,12 +2528,6 @@ LONG Handle_Exception(struct _EXCEPTION_POINTERS* exceptionInfo, return EXCEPTION_CONTINUE_EXECUTION; } - -// Used for PostMortemDump -extern "C" void safepoints(); -extern "C" void find(int x); -extern "C" void events(); - // According to Windows API documentation, an illegal instruction sequence should generate // the 0xC000001C exception code. However, real world experience shows that occasionnaly // the execution of an illegal instruction can generate the exception code 0xC000001E. This From 7527da081b777f280144af5841874729a671e9c5 Mon Sep 17 00:00:00 2001 From: Trupti Patil Date: Mon, 30 Mar 2026 04:40:26 +0000 Subject: [PATCH 085/359] 8377534: Test java/awt/print/PrinterJob/PrintNullString.java fails with FAILURE: No IAE for empty iterator, int Reviewed-by: aivanov, prr --- .../awt/print/PrinterJob/PrintNullString.java | 20 ++++++------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/test/jdk/java/awt/print/PrinterJob/PrintNullString.java b/test/jdk/java/awt/print/PrinterJob/PrintNullString.java index 2bcee65fe9b..8feb50602f7 100644 --- a/test/jdk/java/awt/print/PrinterJob/PrintNullString.java +++ b/test/jdk/java/awt/print/PrinterJob/PrintNullString.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ import javax.print.attribute.standard.Destination; /* * @test - * @bug 4223328 + * @bug 4223328 4138921 * @summary Printer graphics must throw expected exceptions * @key printer * @run main PrintNullString @@ -106,12 +106,8 @@ public class PrintNullString implements Printable { g2d.drawString("caught expected NPE for null iterator, int", 20, 120); } - try { - g2d.drawString(emptyIterator, 20, 140); - throw new RuntimeException("FAILURE: No IAE for empty iterator, int"); - } catch (IllegalArgumentException e) { - g2d.drawString("caught expected IAE for empty iterator, int", 20, 140); - } + g2d.drawString(emptyIterator, 20, 140); + g2d.drawString("OK for empty iterator, int", 20, 140); // API 4: null & empty drawString(Iterator, float, int); try { @@ -121,12 +117,8 @@ public class PrintNullString implements Printable { g2d.drawString("caught expected NPE for null iterator, float", 20, 160); } - try { - g2d.drawString(emptyIterator, 20.0f, 180.0f); - throw new RuntimeException("FAILURE: No IAE for empty iterator, float"); - } catch (IllegalArgumentException e) { - g2d.drawString("caught expected IAE for empty iterator, float", 20, 180); - } + g2d.drawString(emptyIterator, 20.0f, 180.0f); + g2d.drawString("OK for empty iterator, float", 20.0f, 100.f); return PAGE_EXISTS; } From ca3fe721ba23a1304089b71c1b58940f16a0d053 Mon Sep 17 00:00:00 2001 From: Thomas Stuefe Date: Mon, 30 Mar 2026 04:54:17 +0000 Subject: [PATCH 086/359] 8357089: Remove VFORK launch mechanism from Process implementation (linux) Reviewed-by: rriggs, andrew --- .../unix/classes/java/lang/ProcessImpl.java | 37 ++--- .../unix/native/libjava/ProcessImpl_md.c | 153 ++++-------------- src/java.base/unix/native/libjava/childproc.c | 52 ++---- src/java.base/unix/native/libjava/childproc.h | 1 - test/jdk/java/lang/ProcessBuilder/Basic.java | 10 -- .../ConcNativeForkTest.java | 10 -- .../ProcessBuilder/FDLeakTest/FDLeakTest.java | 8 - .../ProcessBuilder/NonPipelineLeaksFD.java | 8 - .../PipesCloseOnExecTest.java | 10 -- .../lang/ProcessBuilder/RejectVFORKMode.java | 59 +++++++ .../TestChildSignalDisposition.java | 11 +- 11 files changed, 110 insertions(+), 249 deletions(-) create mode 100644 test/jdk/java/lang/ProcessBuilder/RejectVFORKMode.java diff --git a/src/java.base/unix/classes/java/lang/ProcessImpl.java b/src/java.base/unix/classes/java/lang/ProcessImpl.java index 00b51fb3389..d9a4547848f 100644 --- a/src/java.base/unix/classes/java/lang/ProcessImpl.java +++ b/src/java.base/unix/classes/java/lang/ProcessImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -82,8 +82,7 @@ final class ProcessImpl extends Process { private static enum LaunchMechanism { // order IS important! FORK, - POSIX_SPAWN, - VFORK + POSIX_SPAWN } /** @@ -98,29 +97,16 @@ final class ProcessImpl extends Process { try { // Should be value of a LaunchMechanism enum - LaunchMechanism lm = LaunchMechanism.valueOf(s.toUpperCase(Locale.ROOT)); - switch (OperatingSystem.current()) { - case LINUX: { - // All options are valid for Linux, but VFORK is deprecated and results - // in a warning - if (lm == LaunchMechanism.VFORK) { - System.err.println("VFORK MODE DEPRECATED"); - System.err.println(""" - The VFORK launch mechanism has been deprecated for being dangerous. - It will be removed in a future java version. Either remove the - jdk.lang.Process.launchMechanism property (preferred) or use FORK mode - instead (-Djdk.lang.Process.launchMechanism=FORK). - """); - } - return lm; - } - case AIX: - case MACOS: - if (lm != LaunchMechanism.VFORK) { - return lm; // All but VFORK are valid - } - break; + String launchMechanism = s.toUpperCase(Locale.ROOT); + if (launchMechanism.equals("VFORK") && OperatingSystem.isLinux()) { + launchMechanism = "FORK"; + System.err.println(String.format(""" + The VFORK launch mechanism has been removed. Switching to %s instead. + Please remove the jdk.lang.Process.launchMechanism property (preferred) + or use FORK mode instead (-Djdk.lang.Process.launchMechanism=FORK).%n + """, launchMechanism)); } + return LaunchMechanism.valueOf(launchMechanism); } catch (IllegalArgumentException e) { } @@ -266,7 +252,6 @@ final class ProcessImpl extends Process { *

      *   1 - fork(2) and exec(2)
      *   2 - posix_spawn(3P)
-     *   3 - vfork(2) and exec(2)
      * 
* @param fds an array of three file descriptors. * Indexes 0, 1, and 2 correspond to standard input, diff --git a/src/java.base/unix/native/libjava/ProcessImpl_md.c b/src/java.base/unix/native/libjava/ProcessImpl_md.c index f7d91166e76..69af948d2da 100644 --- a/src/java.base/unix/native/libjava/ProcessImpl_md.c +++ b/src/java.base/unix/native/libjava/ProcessImpl_md.c @@ -60,51 +60,33 @@ * changing paths... * - then exec(2) the target binary * - * There are three ways to fork off: + * On the OS-side are three ways to fork off, but we only use two of them: * - * A) fork(2). Portable and safe (no side effects) but may fail with ENOMEM on - * all Unices when invoked from a VM with a high memory footprint. On Unices - * with strict no-overcommit policy this problem is most visible. + * A) fork(2). Portable and safe (no side effects) but could fail on very ancient + * Unices that don't employ COW on fork(2). The modern platforms we support + * (Linux, MacOS, AIX) all do. It may have a small performance penalty compared + * to modern posix_spawn(3) implementations - see below. + * fork(2) can be used by specifying -Djdk.lang.Process.launchMechanism=FORK when starting + * the (parent process) JVM. * - * This is because forking the VM will first create a child process with - * theoretically the same memory footprint as the parent - even if you plan - * to follow up with exec'ing a tiny binary. In reality techniques like - * copy-on-write etc mitigate the problem somewhat but we still run the risk - * of hitting system limits. + * B) vfork(2): Portable and fast but very unsafe. For details, see JDK-8357090. + * We supported this mode in older releases but removed support for it in JDK 27. + * Modern posix_spawn(3) implementations use techniques similar to vfork(2), but + * in a much safer way * - * For a Linux centric description of this problem, see the documentation on - * /proc/sys/vm/overcommit_memory in Linux proc(5). - * - * B) vfork(2): Portable and fast but very unsafe. It bypasses the memory - * problems related to fork(2) by starting the child in the memory image of - * the parent. Things that can go wrong include: - * - Programming errors in the child process before the exec(2) call may - * trash memory in the parent process, most commonly the stack of the - * thread invoking vfork. - * - Signals received by the child before the exec(2) call may be at best - * misdirected to the parent, at worst immediately kill child and parent. - * - * This is mitigated by very strict rules about what one is allowed to do in - * the child process between vfork(2) and exec(2), which is basically nothing. - * However, we always broke this rule by doing the pre-exec work between - * vfork(2) and exec(2). - * - * Also note that vfork(2) has been deprecated by the OpenGroup, presumably - * because of its many dangers. - * - * C) clone(2): This is a Linux specific call which gives the caller fine - * grained control about how exactly the process fork is executed. It is - * powerful, but Linux-specific. - * - * Aside from these three possibilities there is a forth option: posix_spawn(3). - * Where fork/vfork/clone all fork off the process and leave pre-exec work and - * calling exec(2) to the user, posix_spawn(3) offers the user fork+exec-like - * functionality in one package, similar to CreateProcess() on Windows. - * - * It is not a system call in itself, but usually a wrapper implemented within - * the libc in terms of one of (fork|vfork|clone)+exec - so whether or not it - * has advantages over calling the naked (fork|vfork|clone) functions depends - * on how posix_spawn(3) is implemented. + * C) posix_spawn(3): Where fork/vfork/clone all fork off the process and leave + * pre-exec work and calling exec(2) to the user, posix_spawn(3) offers the user + * fork+exec-like functionality in one package, similar to CreateProcess() on Windows. + * It is not a system call, but a wrapper implemented in user-space libc in terms + * of one of (fork|vfork|clone)+exec - so whether or not it has advantages over calling + * the naked (fork|vfork|clone) functions depends on how posix_spawn(3) is implemented. + * Modern posix_spawn(3) implementations, on Linux, use clone(2) with CLONE_VM | CLONE_VFORK, + * giving us the best ratio between performance and safety. + * Note however, that posix_spawn(3) can be buggy, depending on the libc implementation. + * E.g., on MacOS, it is still fully not POSIX-compliant. Therefore, we need to retain the + * FORK mode as a backup. + * Posix_spawn mode is used by default, but can be explicitly enabled using + * -Djdk.lang.Process.launchMechanism=POSIX_SPAWN when starting the (parent process) JVM. * * Note that when using posix_spawn(3), we exec twice: first a tiny binary called * the jspawnhelper, then in the jspawnhelper we do the pre-exec work and exec a @@ -117,58 +99,14 @@ * --- Linux-specific --- * * How does glibc implement posix_spawn? - * (see: sysdeps/posix/spawni.c for glibc < 2.24, - * sysdeps/unix/sysv/linux/spawni.c for glibc >= 2.24): * - * 1) Before glibc 2.4 (released 2006), posix_spawn(3) used just fork(2)/exec(2). - * This would be bad for the JDK since we would risk the known memory issues with - * fork(2). But since this only affects glibc variants which have long been - * phased out by modern distributions, this is irrelevant. + * Before glibc 2.4 (released 2006), posix_spawn(3) used just fork(2)/exec(2). From + * glibc 2.4 up to and including 2.23, it used either fork(2) or vfork(2). None of these + * versions still matter. * - * 2) Between glibc 2.4 and glibc 2.23, posix_spawn uses either fork(2) or - * vfork(2) depending on how exactly the user called posix_spawn(3): - * - * - * The child process is created using vfork(2) instead of fork(2) when - * either of the following is true: - * - * * the spawn-flags element of the attributes object pointed to by - * attrp contains the GNU-specific flag POSIX_SPAWN_USEVFORK; or - * - * * file_actions is NULL and the spawn-flags element of the attributes - * object pointed to by attrp does not contain - * POSIX_SPAWN_SETSIGMASK, POSIX_SPAWN_SETSIGDEF, - * POSIX_SPAWN_SETSCHEDPARAM, POSIX_SPAWN_SETSCHEDULER, - * POSIX_SPAWN_SETPGROUP, or POSIX_SPAWN_RESETIDS. - * - * - * Due to the way the JDK calls posix_spawn(3), it would therefore call vfork(2). - * So we would avoid the fork(2) memory problems. However, there still remains the - * risk associated with vfork(2). But it is smaller than were we to call vfork(2) - * directly since we use the jspawnhelper, moving all pre-exec work off to after - * the first exec, thereby reducing the vulnerable time window. - * - * 3) Since glibc >= 2.24, glibc uses clone+exec: - * - * new_pid = CLONE (__spawni_child, STACK (stack, stack_size), stack_size, - * CLONE_VM | CLONE_VFORK | SIGCHLD, &args); - * - * This is even better than (2): - * - * CLONE_VM means we run in the parent's memory image, as with (2) - * CLONE_VFORK means parent waits until we exec, as with (2) - * - * However, error possibilities are further reduced since: - * - posix_spawn(3) passes a separate stack for the child to run on, eliminating - * the danger of trashing the forking thread's stack in the parent process. - * - posix_spawn(3) takes care to temporarily block all incoming signals to the - * child process until the first exec(2) has been called, - * - * TL;DR - * Calling posix_spawn(3) for glibc - * (2) < 2.24 is not perfect but still better than using plain vfork(2), since - * the chance of an error happening is greatly reduced - * (3) >= 2.24 is the best option - portable, fast and as safe as possible. + * Since glibc >= 2.24, glibc uses clone+exec with CLONE_VM | CLONE_VFORK to emulate vfork + * performance but without the inherent dangers (we run inside the parent's memory image + * and stop the parent for as long as it takes the child process to exec). * * --- * @@ -180,7 +118,6 @@ * * * - * * Based on the above analysis, we are currently defaulting to posix_spawn() * on all Unices including Linux. */ @@ -489,28 +426,6 @@ static int copystrings(char *buf, int offset, const char * const *arg) { __attribute_noinline__ #endif -/* vfork(2) is deprecated on Darwin */ -#ifndef __APPLE__ -static pid_t -vforkChild(ChildStuff *c) { - volatile pid_t resultPid; - - /* - * We separate the call to vfork into a separate function to make - * very sure to keep stack of child from corrupting stack of parent, - * as suggested by the scary gcc warning: - * warning: variable 'foo' might be clobbered by 'longjmp' or 'vfork' - */ - resultPid = vfork(); - - if (resultPid == 0) { - childProcess(c); - } - assert(resultPid != 0); /* childProcess never returns */ - return resultPid; -} -#endif - static pid_t forkChild(ChildStuff *c) { pid_t resultPid; @@ -734,11 +649,6 @@ spawnChild(JNIEnv *env, jobject process, ChildStuff *c, const char *helperpath) static pid_t startChild(JNIEnv *env, jobject process, ChildStuff *c, const char *helperpath) { switch (c->mode) { -/* vfork(2) is deprecated on Darwin*/ - #ifndef __APPLE__ - case MODE_VFORK: - return vforkChild(c); - #endif case MODE_FORK: return forkChild(c); case MODE_POSIX_SPAWN: @@ -872,9 +782,6 @@ Java_java_lang_ProcessImpl_forkAndExec(JNIEnv *env, if (resultPid < 0) { char * failMessage = "unknown"; switch (c->mode) { - case MODE_VFORK: - failMessage = "vfork failed"; - break; case MODE_FORK: failMessage = "fork failed"; break; diff --git a/src/java.base/unix/native/libjava/childproc.c b/src/java.base/unix/native/libjava/childproc.c index 83ee782482f..6bc15dfb40c 100644 --- a/src/java.base/unix/native/libjava/childproc.c +++ b/src/java.base/unix/native/libjava/childproc.c @@ -271,31 +271,6 @@ initVectorFromBlock(const char**vector, const char* block, int count) vector[count] = NULL; } -/** - * Exec FILE as a traditional Bourne shell script (i.e. one without #!). - * If we could do it over again, we would probably not support such an ancient - * misfeature, but compatibility wins over sanity. The original support for - * this was imported accidentally from execvp(). - */ -static void -execve_as_traditional_shell_script(const char *file, - const char *argv[], - const char *const envp[]) -{ - /* Use the extra word of space provided for us in argv by caller. */ - const char *argv0 = argv[0]; - const char *const *end = argv; - while (*end != NULL) - ++end; - memmove(argv+2, argv+1, (end-argv) * sizeof(*end)); - argv[0] = "/bin/sh"; - argv[1] = file; - execve(argv[0], (char **) argv, (char **) envp); - /* Can't even exec /bin/sh? Big trouble, but let's soldier on... */ - memmove(argv+1, argv+2, (end-argv) * sizeof(*end)); - argv[0] = argv0; -} - /** * Like execve(2), except that in case of ENOEXEC, FILE is assumed to * be a shell script and the system default shell is invoked to run it. @@ -305,16 +280,9 @@ execve_with_shell_fallback(int mode, const char *file, const char *argv[], const char *const envp[]) { - if (mode == MODE_VFORK) { - /* shared address space; be very careful. */ - execve(file, (char **) argv, (char **) envp); - if (errno == ENOEXEC) - execve_as_traditional_shell_script(file, argv, envp); - } else { - /* unshared address space; we can mutate environ. */ - environ = (char **) envp; - execvp(file, (char **) argv); - } + /* unshared address space; we can mutate environ. */ + environ = (char **) envp; + execvp(file, (char **) argv); } /** @@ -430,7 +398,7 @@ childProcess(void *arg) #endif /* File descriptor setup for non-Posix-spawn mode */ - if (p->mode != MODE_POSIX_SPAWN) { + if (p->mode == MODE_FORK) { /* Close the parent sides of the pipes. Closing pipe fds here is redundant, since markDescriptorsCloseOnExec() @@ -482,7 +450,7 @@ childProcess(void *arg) /* We moved the fail pipe fd */ fail_pipe_fd = FAIL_FILENO; - } /* end: FORK/VFORK mode */ + } /* end: FORK mode */ assert(fail_pipe_fd == FAIL_FILENO); @@ -508,12 +476,10 @@ childProcess(void *arg) goto WhyCantJohnnyExec; } - // Reset any mask signals from parent, but not in VFORK mode - if (p->mode != MODE_VFORK) { - sigset_t unblock_signals; - sigemptyset(&unblock_signals); - sigprocmask(SIG_SETMASK, &unblock_signals, NULL); - } + // Reset any mask signals from parent + sigset_t unblock_signals; + sigemptyset(&unblock_signals); + sigprocmask(SIG_SETMASK, &unblock_signals, NULL); // Children should be started with default signal disposition for SIGPIPE if (signal(SIGPIPE, SIG_DFL) == SIG_ERR) { diff --git a/src/java.base/unix/native/libjava/childproc.h b/src/java.base/unix/native/libjava/childproc.h index 27414e60137..0b02df7f3dd 100644 --- a/src/java.base/unix/native/libjava/childproc.h +++ b/src/java.base/unix/native/libjava/childproc.h @@ -81,7 +81,6 @@ extern char **environ; */ #define MODE_FORK 1 #define MODE_POSIX_SPAWN 2 -#define MODE_VFORK 3 typedef struct _ChildStuff { diff --git a/test/jdk/java/lang/ProcessBuilder/Basic.java b/test/jdk/java/lang/ProcessBuilder/Basic.java index 70d6101c1a5..b150690ef48 100644 --- a/test/jdk/java/lang/ProcessBuilder/Basic.java +++ b/test/jdk/java/lang/ProcessBuilder/Basic.java @@ -50,16 +50,6 @@ * @run main/othervm/native/timeout=360 -Djdk.lang.Process.launchMechanism=fork Basic */ -/* - * @test id=VFORK - * @modules java.base/java.lang:open - * java.base/java.io:open - * java.base/jdk.internal.misc - * @requires (os.family == "linux") - * @library /test/lib - * @run main/othervm/timeout=300 -Djdk.lang.Process.launchMechanism=vfork Basic - */ - import java.lang.ProcessBuilder.Redirect; import java.lang.ProcessHandle; import static java.lang.ProcessBuilder.Redirect.*; diff --git a/test/jdk/java/lang/ProcessBuilder/ConcNativeForkTest/ConcNativeForkTest.java b/test/jdk/java/lang/ProcessBuilder/ConcNativeForkTest/ConcNativeForkTest.java index f02e4991302..904a0e12f98 100644 --- a/test/jdk/java/lang/ProcessBuilder/ConcNativeForkTest/ConcNativeForkTest.java +++ b/test/jdk/java/lang/ProcessBuilder/ConcNativeForkTest/ConcNativeForkTest.java @@ -42,16 +42,6 @@ * @run main/othervm/manual -Djdk.lang.Process.launchMechanism=FORK ConcNativeForkTest */ -/* - * @test id=VFORK - * @bug 8377907 - * @summary Test that demonstrates the hanging-parent-on-native-concurrent-forks problem - * @requires os.family == "linux" - * @requires vm.flagless - * @library /test/lib - * @run main/othervm/manual -Djdk.lang.Process.launchMechanism=VFORK ConcNativeForkTest - */ - public class ConcNativeForkTest { // How this works: diff --git a/test/jdk/java/lang/ProcessBuilder/FDLeakTest/FDLeakTest.java b/test/jdk/java/lang/ProcessBuilder/FDLeakTest/FDLeakTest.java index aee85e2335f..02c60395f17 100644 --- a/test/jdk/java/lang/ProcessBuilder/FDLeakTest/FDLeakTest.java +++ b/test/jdk/java/lang/ProcessBuilder/FDLeakTest/FDLeakTest.java @@ -38,14 +38,6 @@ * @run main/othervm/native -Djdk.lang.Process.launchMechanism=fork -agentlib:FDLeaker FDLeakTest */ -/** - * @test id=vfork - * @summary Check that we don't leak FDs to child processes - * @requires os.family == "linux" - * @library /test/lib - * @run main/othervm/native -Djdk.lang.Process.launchMechanism=vfork -agentlib:FDLeaker FDLeakTest - */ - import jdk.test.lib.process.ProcessTools; public class FDLeakTest { // This test has two native parts: diff --git a/test/jdk/java/lang/ProcessBuilder/NonPipelineLeaksFD.java b/test/jdk/java/lang/ProcessBuilder/NonPipelineLeaksFD.java index be2c4af3bbe..e43255d8c52 100644 --- a/test/jdk/java/lang/ProcessBuilder/NonPipelineLeaksFD.java +++ b/test/jdk/java/lang/ProcessBuilder/NonPipelineLeaksFD.java @@ -32,14 +32,6 @@ import java.io.*; * @run main/othervm -Djdk.lang.Process.launchMechanism=fork NonPipelineLeaksFD */ -/* - * @test id=VFORK - * @summary Check that we don't accumulate leaked FDs in the parent process - * @requires os.family == "linux" - * @library /test/lib - * @run main/othervm -Djdk.lang.Process.launchMechanism=vfork NonPipelineLeaksFD - */ - /* * @test id=POSIX_SPAWN * @summary Check that we don't accumulate leaked FDs in the parent process diff --git a/test/jdk/java/lang/ProcessBuilder/PipesCloseOnExecTest/PipesCloseOnExecTest.java b/test/jdk/java/lang/ProcessBuilder/PipesCloseOnExecTest/PipesCloseOnExecTest.java index 1e988f0496c..8390caae59a 100644 --- a/test/jdk/java/lang/ProcessBuilder/PipesCloseOnExecTest/PipesCloseOnExecTest.java +++ b/test/jdk/java/lang/ProcessBuilder/PipesCloseOnExecTest/PipesCloseOnExecTest.java @@ -32,16 +32,6 @@ * @run main/othervm/native -Djdk.lang.Process.launchMechanism=FORK PipesCloseOnExecTest */ -/* - * @test id=VFORK - * @bug 8377907 - * @summary Check that we don't open pipes without CLOEXCEC - * @requires os.family == "linux" - * @requires vm.flagless - * @library /test/lib - * @run main/othervm/native -Djdk.lang.Process.launchMechanism=VFORK PipesCloseOnExecTest - */ - /* * @test id=POSIX_SPAWN * @bug 8377907 diff --git a/test/jdk/java/lang/ProcessBuilder/RejectVFORKMode.java b/test/jdk/java/lang/ProcessBuilder/RejectVFORKMode.java new file mode 100644 index 00000000000..db8387821f5 --- /dev/null +++ b/test/jdk/java/lang/ProcessBuilder/RejectVFORKMode.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2026, IBM Corp. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8357089 + * @summary Check that specifying VFORK correctly falls back to FORK with a clear warning to stderr. + * @requires (os.family == "linux") + * @library /test/lib + * @run main RejectVFORKMode GRANDPARENT + */ + +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +public class RejectVFORKMode { + public static void main(String[] args) throws Exception { + + switch (args[0]) { + case "PARENT" -> { + ProcessBuilder pb = new ProcessBuilder("sh", "-c", "echo 'Child Process'; exit 12;"); + // This should result in a (written to this process' stderr) warning about VFORK mode. + // But child should have been started successfully. + OutputAnalyzer outputAnalyzer = ProcessTools.executeCommand(pb); + outputAnalyzer.shouldHaveExitValue(12); + outputAnalyzer.shouldContain("Child Process"); + System.exit(0); + } + case "GRANDPARENT" -> { + ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-Djdk.lang.Process.launchMechanism=VFORK", RejectVFORKMode.class.getName(), "PARENT"); + OutputAnalyzer outputAnalyzer = ProcessTools.executeCommand(pb); + outputAnalyzer.shouldHaveExitValue(0); + outputAnalyzer.shouldContain("The VFORK launch mechanism has been removed. Switching to FORK instead."); + } + default -> throw new RuntimeException("Bad arg"); + } + } +} diff --git a/test/jdk/java/lang/ProcessBuilder/childSignalDisposition/TestChildSignalDisposition.java b/test/jdk/java/lang/ProcessBuilder/childSignalDisposition/TestChildSignalDisposition.java index 50fe054ee34..80b63b765da 100644 --- a/test/jdk/java/lang/ProcessBuilder/childSignalDisposition/TestChildSignalDisposition.java +++ b/test/jdk/java/lang/ProcessBuilder/childSignalDisposition/TestChildSignalDisposition.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,15 +39,6 @@ * @run main/othervm/native -Djdk.lang.Process.launchMechanism=fork -agentlib:ChangeSignalDisposition TestChildSignalDisposition */ -/** - * @test id=vfork - * @bug 8364611 - * @summary Check that childs start with SIG_DFL as SIGPIPE disposition - * @requires os.family == "linux" - * @library /test/lib - * @run main/othervm/native -Djdk.lang.Process.launchMechanism=vfork -agentlib:ChangeSignalDisposition TestChildSignalDisposition - */ - import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; public class TestChildSignalDisposition { From 61df7cc8b91365e487591ec8402e797a25790a79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20H=C3=A4ssig?= Date: Mon, 30 Mar 2026 06:27:30 +0000 Subject: [PATCH 087/359] 8380988: C2: Unexpected node in SuperWord truncation: UModI/UDivI Reviewed-by: epeter, jkarthikeyan --- src/hotspot/share/opto/superword.cpp | 2 + .../vectorization/TestSubwordTruncation.java | 46 ++++++++++++++++++- 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/opto/superword.cpp b/src/hotspot/share/opto/superword.cpp index d878b2b1d3d..53845a94c1c 100644 --- a/src/hotspot/share/opto/superword.cpp +++ b/src/hotspot/share/opto/superword.cpp @@ -2500,7 +2500,9 @@ static bool can_subword_truncate(Node* in, const Type* type) { switch (opc) { case Op_AbsI: case Op_DivI: + case Op_UDivI: case Op_ModI: + case Op_UModI: case Op_MinI: case Op_MaxI: case Op_CMoveI: diff --git a/test/hotspot/jtreg/compiler/vectorization/TestSubwordTruncation.java b/test/hotspot/jtreg/compiler/vectorization/TestSubwordTruncation.java index 2f6296e41d2..0a80a59efd4 100644 --- a/test/hotspot/jtreg/compiler/vectorization/TestSubwordTruncation.java +++ b/test/hotspot/jtreg/compiler/vectorization/TestSubwordTruncation.java @@ -29,7 +29,7 @@ import compiler.lib.generators.*; /* * @test - * @bug 8350177 8362171 8369881 8342095 + * @bug 8350177 8362171 8369881 8342095 8380988 * @summary Ensure that truncation of subword vectors produces correct results * @library /test/lib / * @run driver compiler.vectorization.TestSubwordTruncation @@ -448,6 +448,50 @@ public class TestSubwordTruncation { } } + @Test + @IR(counts = { IRNode.UMOD_I, ">0" }) + @Arguments(setup = "setupByteArray") + public Object[] testUMod(final byte[] in) { + int n = G.next().intValue(); + for (int i = 1; i < SIZE; i++) { + in[i] = (byte) Integer.remainderUnsigned(n, i); + } + + return new Object[] { Integer.valueOf(n), in }; + } + + @Check(test = "testUMod") + public void checkTestUMod(Object[] vals) { + int n = (Integer) vals[0]; + byte[] res = (byte[]) vals[1]; + for (int i = 1; i < SIZE; i++) { + byte val = (byte) Integer.remainderUnsigned(n, i); + Asserts.assertEQ(res[i], val); + } + } + + @Test + @IR(counts = { IRNode.UDIV_I, ">0" }) + @Arguments(setup = "setupByteArray") + public Object[] testUDiv(final byte[] in) { + int n = G.next().intValue(); + for (int i = 1; i < SIZE; i++) { + in[i] = (byte) Integer.divideUnsigned(n, i); + } + + return new Object[] { Integer.valueOf(n), in }; + } + + @Check(test = "testUDiv") + public void checkTestUDiv(Object[] vals) { + int n = (Integer) vals[0]; + byte[] res = (byte[]) vals[1]; + for (int i = 1; i < SIZE; i++) { + byte val = (byte) Integer.divideUnsigned(n, i); + Asserts.assertEQ(res[i], val); + } + } + @Test @IR(counts = { IRNode.CMP_LT_MASK, ">0" }) @Arguments(setup = "setupByteArray") From bbbd5b9984c909773227123ad31b1dd8336df0d9 Mon Sep 17 00:00:00 2001 From: Stefan Johansson Date: Mon, 30 Mar 2026 06:29:43 +0000 Subject: [PATCH 088/359] 8380773: Extend ContainerMemoryUsageEvent to include host memory usage Reviewed-by: mgronlun, tkiriyama, sgehwolf --- src/hotspot/share/jfr/jni/jfrJniMethod.cpp | 9 +++++++++ src/hotspot/share/jfr/jni/jfrJniMethod.hpp | 2 ++ src/hotspot/share/jfr/jni/jfrJniMethodRegistration.cpp | 1 + .../jdk/jfr/events/ContainerMemoryUsageEvent.java | 5 +++++ .../share/classes/jdk/jfr/internal/JDKEvents.java | 1 + src/jdk.jfr/share/classes/jdk/jfr/internal/JVM.java | 6 ++++++ test/hotspot/jtreg/containers/docker/TestJFREvents.java | 4 +++- 7 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/jfr/jni/jfrJniMethod.cpp b/src/hotspot/share/jfr/jni/jfrJniMethod.cpp index 885484020bd..0183bf634f6 100644 --- a/src/hotspot/share/jfr/jni/jfrJniMethod.cpp +++ b/src/hotspot/share/jfr/jni/jfrJniMethod.cpp @@ -410,6 +410,15 @@ JVM_ENTRY_NO_ENV(jlong, jfr_host_total_swap_memory(JNIEnv* env, jclass jvm)) return static_cast(total_swap_space); JVM_END +JVM_ENTRY_NO_ENV(jlong, jfr_host_memory_usage(JNIEnv* env, jclass jvm)) + physical_memory_size_type memory_usage = 0; + if (!os::Machine::used_memory(memory_usage)) { + // Return -1 to signal failure to get memory usage. + return static_cast(-1); + } + return static_cast(memory_usage); +JVM_END + JVM_ENTRY_NO_ENV(void, jfr_emit_data_loss(JNIEnv* env, jclass jvm, jlong bytes)) EventDataLoss::commit(bytes, min_jlong); JVM_END diff --git a/src/hotspot/share/jfr/jni/jfrJniMethod.hpp b/src/hotspot/share/jfr/jni/jfrJniMethod.hpp index 9769df57bd3..bcdaf7a99b7 100644 --- a/src/hotspot/share/jfr/jni/jfrJniMethod.hpp +++ b/src/hotspot/share/jfr/jni/jfrJniMethod.hpp @@ -163,6 +163,8 @@ jlong JNICALL jfr_host_total_memory(JNIEnv* env, jclass jvm); jlong JNICALL jfr_host_total_swap_memory(JNIEnv* env, jclass jvm); +jlong JNICALL jfr_host_memory_usage(JNIEnv* env, jclass jvm); + void JNICALL jfr_emit_data_loss(JNIEnv* env, jclass jvm, jlong bytes); jlong JNICALL jfr_register_stack_filter(JNIEnv* env, jclass jvm, jobjectArray classes, jobjectArray methods); diff --git a/src/hotspot/share/jfr/jni/jfrJniMethodRegistration.cpp b/src/hotspot/share/jfr/jni/jfrJniMethodRegistration.cpp index 2979f5c5c2d..0813289e840 100644 --- a/src/hotspot/share/jfr/jni/jfrJniMethodRegistration.cpp +++ b/src/hotspot/share/jfr/jni/jfrJniMethodRegistration.cpp @@ -101,6 +101,7 @@ JfrJniMethodRegistration::JfrJniMethodRegistration(JNIEnv* env) { (char*)"isContainerized", (char*)"()Z", (void*) jfr_is_containerized, (char*)"hostTotalMemory", (char*)"()J", (void*) jfr_host_total_memory, (char*)"hostTotalSwapMemory", (char*)"()J", (void*) jfr_host_total_swap_memory, + (char*)"hostMemoryUsage", (char*)"()J", (void*) jfr_host_memory_usage, (char*)"emitDataLoss", (char*)"(J)V", (void*)jfr_emit_data_loss, (char*)"registerStackFilter", (char*)"([Ljava/lang/String;[Ljava/lang/String;)J", (void*)jfr_register_stack_filter, (char*)"unregisterStackFilter", (char*)"(J)V", (void*)jfr_unregister_stack_filter, diff --git a/src/jdk.jfr/share/classes/jdk/jfr/events/ContainerMemoryUsageEvent.java b/src/jdk.jfr/share/classes/jdk/jfr/events/ContainerMemoryUsageEvent.java index 285952d0c66..9a83877a967 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/events/ContainerMemoryUsageEvent.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/events/ContainerMemoryUsageEvent.java @@ -50,4 +50,9 @@ public final class ContainerMemoryUsageEvent extends AbstractPeriodicEvent { @Description("Amount of physical memory and swap space, in bytes, that is currently allocated in the current container") @DataAmount public long swapMemoryUsage; + + @Label("Host Memory Usage") + @Description("Amount of physical memory, in bytes, that is currently allocated in the host system") + @DataAmount + public long hostMemoryUsage; } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/JDKEvents.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/JDKEvents.java index 53d40c1e5e1..79bc614545e 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/JDKEvents.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/JDKEvents.java @@ -181,6 +181,7 @@ public final class JDKEvents { event.memoryFailCount = containerMetrics.getMemoryFailCount(); event.memoryUsage = containerMetrics.getMemoryUsage(); event.swapMemoryUsage = containerMetrics.getMemoryAndSwapUsage(); + event.hostMemoryUsage = JVM.hostMemoryUsage(); event.commit(); } } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/JVM.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/JVM.java index 24c92e81a4c..2aa7dfd6e97 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/JVM.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/JVM.java @@ -657,6 +657,12 @@ public final class JVM { */ public static native long hostTotalSwapMemory(); + /** + * Returns the amount of memory used in the host system whether or not this + * JVM runs in a container. + */ + public static native long hostMemoryUsage(); + /** * Emit a jdk.DataLoss event for the specified amount of bytes. * diff --git a/test/hotspot/jtreg/containers/docker/TestJFREvents.java b/test/hotspot/jtreg/containers/docker/TestJFREvents.java index d46c422723b..c3112310479 100644 --- a/test/hotspot/jtreg/containers/docker/TestJFREvents.java +++ b/test/hotspot/jtreg/containers/docker/TestJFREvents.java @@ -162,6 +162,7 @@ public class TestJFREvents { String memoryFailCountFld = "memoryFailCount"; String memoryUsageFld = "memoryUsage"; String swapMemoryUsageFld = "swapMemoryUsage"; + String hostMemoryUsageFld = "hostMemoryUsage"; DockerTestUtils.dockerRunJava( commonDockerOpts() @@ -169,7 +170,8 @@ public class TestJFREvents { .shouldHaveExitValue(0) .shouldContain(memoryFailCountFld) .shouldContain(memoryUsageFld) - .shouldContain(swapMemoryUsageFld); + .shouldContain(swapMemoryUsageFld) + .shouldContain(hostMemoryUsageFld); } private static void testIOUsage() throws Exception { From 0885a0c4c548532e87533467315b48465c8b6e20 Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Mon, 30 Mar 2026 06:35:55 +0000 Subject: [PATCH 089/359] 4696824: In Metal and other L&F Button.focusInputMap, CheckBox.focusInputMap ... are same Reviewed-by: tr, prr --- .../swing/plaf/motif/MotifLookAndFeel.java | 27 +++++----------- .../swing/plaf/metal/MetalLookAndFeel.java | 32 ++++++++----------- 2 files changed, 21 insertions(+), 38 deletions(-) diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifLookAndFeel.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifLookAndFeel.java index d254443b8d1..5263d248f45 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifLookAndFeel.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifLookAndFeel.java @@ -537,6 +537,10 @@ public class MotifLookAndFeel extends BasicLookAndFeel @SuppressWarnings("deprecation") final int metaMask = KeyEvent.META_MASK; + Object commonInputMap = new UIDefaults.LazyInputMap(new Object[] { + "SPACE", "pressed", + "released SPACE", "released" + }); Object[] defaults = { "Desktop.background", table.get("desktop"), @@ -593,20 +597,13 @@ public class MotifLookAndFeel extends BasicLookAndFeel "Button.foreground", table.get("controlText"), "Button.select", table.get("controlLightShadow"), "Button.font", dialogPlain12, - "Button.focusInputMap", new UIDefaults.LazyInputMap(new Object[] { - "SPACE", "pressed", - "released SPACE", "released" - }), + "Button.focusInputMap", commonInputMap, "CheckBox.textIconGap", 8, "CheckBox.margin", new InsetsUIResource(4, 2, 4, 2), "CheckBox.icon", checkBoxIcon, "CheckBox.focus", table.get("activeCaptionBorder"), - "CheckBox.focusInputMap", - new UIDefaults.LazyInputMap(new Object[] { - "SPACE", "pressed", - "released SPACE", "released" - }), + "CheckBox.focusInputMap", commonInputMap, "RadioButton.margin", new InsetsUIResource(4, 2, 4, 2), "RadioButton.textIconGap", 8, @@ -615,22 +612,14 @@ public class MotifLookAndFeel extends BasicLookAndFeel "RadioButton.icon", radioButtonIcon, "RadioButton.focus", table.get("activeCaptionBorder"), "RadioButton.icon", radioButtonIcon, - "RadioButton.focusInputMap", - new UIDefaults.LazyInputMap(new Object[] { - "SPACE", "pressed", - "released SPACE", "released" - }), + "RadioButton.focusInputMap", commonInputMap, "ToggleButton.border", toggleButtonBorder, "ToggleButton.background", table.get("control"), "ToggleButton.foreground", table.get("controlText"), "ToggleButton.focus", table.get("controlText"), "ToggleButton.select", table.get("controlLightShadow"), - "ToggleButton.focusInputMap", - new UIDefaults.LazyInputMap(new Object[] { - "SPACE", "pressed", - "released SPACE", "released" - }), + "ToggleButton.focusInputMap", commonInputMap, // Menus "Menu.border", menuMarginBorder, diff --git a/src/java.desktop/share/classes/javax/swing/plaf/metal/MetalLookAndFeel.java b/src/java.desktop/share/classes/javax/swing/plaf/metal/MetalLookAndFeel.java index 7c56c681423..461c597cc5f 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/metal/MetalLookAndFeel.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/metal/MetalLookAndFeel.java @@ -706,6 +706,11 @@ public class MetalLookAndFeel extends BasicLookAndFeel // DEFAULTS TABLE // + Object commonInputMap = new UIDefaults.LazyInputMap(new Object[] { + "SPACE", "pressed", + "released SPACE", "released" + }); + Object[] defaults = { // *** Auditory Feedback "AuditoryCues.defaultCueList", defaultCueList, @@ -791,6 +796,8 @@ public class MetalLookAndFeel extends BasicLookAndFeel }), + + // Buttons "Button.defaultButtonFollowsFocus", Boolean.FALSE, "Button.disabledText", inactiveControlTextColor, @@ -798,10 +805,8 @@ public class MetalLookAndFeel extends BasicLookAndFeel "Button.border", buttonBorder, "Button.font", controlTextValue, "Button.focus", focusColor, - "Button.focusInputMap", new UIDefaults.LazyInputMap(new Object[] { - "SPACE", "pressed", - "released SPACE", "released" - }), + "Button.focusInputMap", commonInputMap, + // Button default margin is (2, 14, 2, 14), defined in // BasicLookAndFeel via "Button.margin" UI property. @@ -810,11 +815,8 @@ public class MetalLookAndFeel extends BasicLookAndFeel "CheckBox.font", controlTextValue, "CheckBox.focus", focusColor, "CheckBox.icon",(LazyValue) t -> MetalIconFactory.getCheckBoxIcon(), - "CheckBox.focusInputMap", - new UIDefaults.LazyInputMap(new Object[] { - "SPACE", "pressed", - "released SPACE", "released" - }), + "CheckBox.focusInputMap", commonInputMap, + // margin is 2 all the way around, BasicBorders.RadioButtonBorder // (checkbox uses RadioButtonBorder) is 2 all the way around too. "CheckBox.totalInsets", new Insets(4, 4, 4, 4), @@ -824,11 +826,7 @@ public class MetalLookAndFeel extends BasicLookAndFeel "RadioButton.icon",(LazyValue) t -> MetalIconFactory.getRadioButtonIcon(), "RadioButton.font", controlTextValue, "RadioButton.focus", focusColor, - "RadioButton.focusInputMap", - new UIDefaults.LazyInputMap(new Object[] { - "SPACE", "pressed", - "released SPACE", "released" - }), + "RadioButton.focusInputMap", commonInputMap, // margin is 2 all the way around, BasicBorders.RadioButtonBorder // is 2 all the way around too. "RadioButton.totalInsets", new Insets(4, 4, 4, 4), @@ -838,11 +836,7 @@ public class MetalLookAndFeel extends BasicLookAndFeel "ToggleButton.focus", focusColor, "ToggleButton.border", toggleButtonBorder, "ToggleButton.font", controlTextValue, - "ToggleButton.focusInputMap", - new UIDefaults.LazyInputMap(new Object[] { - "SPACE", "pressed", - "released SPACE", "released" - }), + "ToggleButton.focusInputMap", commonInputMap, // File View From 45f9039513d08923e019b50ae5007d9339b9731f Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Mon, 30 Mar 2026 06:48:49 +0000 Subject: [PATCH 090/359] 8380030: [AIX] unify dladdr between hotspot and libawt Reviewed-by: dholmes, stuefe, erikj --- make/common/modules/LauncherCommon.gmk | 10 +-- src/hotspot/os/aix/porting_aix.cpp | 6 +- src/hotspot/os/posix/include/jvm_md.h | 15 +++- .../aix/native/libawt/porting_aix.c | 87 ------------------- .../aix/native/libawt/porting_aix.h | 40 --------- .../unix/native/libawt/awt/awt_LoadLibrary.c | 4 +- 6 files changed, 26 insertions(+), 136 deletions(-) delete mode 100644 src/java.desktop/aix/native/libawt/porting_aix.c delete mode 100644 src/java.desktop/aix/native/libawt/porting_aix.h diff --git a/make/common/modules/LauncherCommon.gmk b/make/common/modules/LauncherCommon.gmk index 859494861b2..8d45142ef4a 100644 --- a/make/common/modules/LauncherCommon.gmk +++ b/make/common/modules/LauncherCommon.gmk @@ -36,16 +36,16 @@ include $(TOPDIR)/make/ToolsJdk.gmk LAUNCHER_SRC := $(TOPDIR)/src/java.base/share/native/launcher -ifeq ($(call isTargetOs, aix), true) - ADD_PLATFORM_INCLUDE_DIR := -I$(TOPDIR)/src/java.base/aix/native/include -endif - LAUNCHER_CFLAGS += -I$(TOPDIR)/src/java.base/share/native/launcher \ -I$(TOPDIR)/src/java.base/share/native/libjli \ - $(ADD_PLATFORM_INCLUDE_DIR) \ -I$(TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS_TYPE)/native/libjli \ -I$(TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS)/native/libjli \ # + +ifeq ($(call isTargetOs, aix), true) + LAUNCHER_CFLAGS += -I$(TOPDIR)/src/java.base/aix/native/include +endif + MACOSX_PLIST_DIR := $(TOPDIR)/src/java.base/macosx/native/launcher JAVA_MANIFEST := $(TOPDIR)/src/java.base/windows/native/launcher/java.manifest diff --git a/src/hotspot/os/aix/porting_aix.cpp b/src/hotspot/os/aix/porting_aix.cpp index b3f878fbfdd..f0527136d90 100644 --- a/src/hotspot/os/aix/porting_aix.cpp +++ b/src/hotspot/os/aix/porting_aix.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2024 SAP SE. All rights reserved. + * Copyright (c) 2012, 2026 SAP SE. All rights reserved. * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -426,6 +426,10 @@ int dladdr(void* addr, Dl_info* info) { } +int JVM_dladdr(void* addr, Dl_info* info) { + return dladdr(addr, info); +} + ///////////////////////////////////////////////////////////////////////////// // Native callstack dumping diff --git a/src/hotspot/os/posix/include/jvm_md.h b/src/hotspot/os/posix/include/jvm_md.h index eb8e1f0d7e9..061ef17aaae 100644 --- a/src/hotspot/os/posix/include/jvm_md.h +++ b/src/hotspot/os/posix/include/jvm_md.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * 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,19 @@ #define JVM_X_OK X_OK #define JVM_F_OK F_OK +#if defined(AIX) +#include "jni_md.h" +#include "dl_info.h" + +#ifdef __cplusplus +extern "C" { +#endif +JNIEXPORT int JVM_dladdr(void* addr, Dl_info* info); +#ifdef __cplusplus +} +#endif +#endif + /* * File I/O */ diff --git a/src/java.desktop/aix/native/libawt/porting_aix.c b/src/java.desktop/aix/native/libawt/porting_aix.c deleted file mode 100644 index d8688c212d7..00000000000 --- a/src/java.desktop/aix/native/libawt/porting_aix.c +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2012, 2026 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. 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 -#include -#include -#include - -#include "porting_aix.h" - -static unsigned char dladdr_buffer[0x8000]; - -static void fill_dll_info(void) { - int rc = loadquery(L_GETINFO,dladdr_buffer, sizeof(dladdr_buffer)); - if (rc == -1) { - fprintf(stderr, "loadquery failed (%d %s)", errno, strerror(errno)); - fflush(stderr); - } -} - -static int dladdr_dont_reload(void* addr, Dl_info* info) { - const struct ld_info* p = (struct ld_info*) dladdr_buffer; - memset((void *)info, 0, sizeof(Dl_info)); - for (;;) { - if (addr >= p->ldinfo_textorg && - (char*)addr < (char*)(p->ldinfo_textorg) + p->ldinfo_textsize) { - info->dli_fname = p->ldinfo_filename; - return 1; - } - if (!p->ldinfo_next) { - break; - } - p = (struct ld_info*)(((char*)p) + p->ldinfo_next); - } - return 0; -} - -#ifdef __cplusplus -extern "C" -#endif -int dladdr(void *addr, Dl_info *info) { - static int loaded = 0; - if (!loaded) { - fill_dll_info(); - loaded = 1; - } - if (!addr) { - return 0; - } - /* Address could be AIX function descriptor? */ - void* const addr0 = *( (void**) addr ); - int rc = dladdr_dont_reload(addr, info); - if (rc == 0) { - rc = dladdr_dont_reload(addr0, info); - if (rc == 0) { - fill_dll_info(); /* refill, maybe loadquery info is outdated */ - rc = dladdr_dont_reload(addr, info); - if (rc == 0) { - rc = dladdr_dont_reload(addr0, info); - } - } - } - return rc; -} diff --git a/src/java.desktop/aix/native/libawt/porting_aix.h b/src/java.desktop/aix/native/libawt/porting_aix.h deleted file mode 100644 index 04d11590915..00000000000 --- a/src/java.desktop/aix/native/libawt/porting_aix.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2012, 2026 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. 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. - * - */ - -/* - * Aix' own version of dladdr(). - * This function tries to mimic dladdr(3) on Linux - * (see http://linux.die.net/man/3/dladdr) - * dladdr(3) is not POSIX but a GNU extension, and is not available on AIX. - * - */ - -#include "dl_info.h" - -#ifdef __cplusplus -extern "C" -#endif -int dladdr(void *addr, Dl_info *info); diff --git a/src/java.desktop/unix/native/libawt/awt/awt_LoadLibrary.c b/src/java.desktop/unix/native/libawt/awt/awt_LoadLibrary.c index cd07c347c9e..af50fdbb5c0 100644 --- a/src/java.desktop/unix/native/libawt/awt/awt_LoadLibrary.c +++ b/src/java.desktop/unix/native/libawt/awt/awt_LoadLibrary.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ #include #ifdef AIX -#include "porting_aix.h" /* For the 'dladdr' function. */ +#define dladdr JVM_dladdr #endif #ifdef DEBUG From cd9724565d295e125484fb2933c0479ceabbaabe Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Mon, 30 Mar 2026 08:37:25 +0000 Subject: [PATCH 091/359] 8381205: GHA: Upgrade Node.js 20 to 24 Reviewed-by: erikj --- .github/actions/build-jtreg/action.yml | 6 +++--- .github/actions/do-build/action.yml | 4 ++-- .github/actions/get-bootjdk/action.yml | 2 +- .github/actions/get-bundles/action.yml | 6 +++--- .github/actions/get-gtest/action.yml | 2 +- .github/actions/get-jtreg/action.yml | 2 +- .github/actions/get-msys2/action.yml | 2 +- .github/actions/upload-bundles/action.yml | 2 +- .github/workflows/build-alpine-linux.yml | 2 +- .github/workflows/build-cross-compile.yml | 4 ++-- .github/workflows/build-linux.yml | 2 +- .github/workflows/build-macos.yml | 2 +- .github/workflows/build-windows.yml | 2 +- .github/workflows/main.yml | 2 +- .github/workflows/test.yml | 6 +++--- 15 files changed, 23 insertions(+), 23 deletions(-) diff --git a/.github/actions/build-jtreg/action.yml b/.github/actions/build-jtreg/action.yml index a9c046e9dd9..334812e8341 100644 --- a/.github/actions/build-jtreg/action.yml +++ b/.github/actions/build-jtreg/action.yml @@ -37,13 +37,13 @@ runs: - name: 'Check cache for already built JTReg' id: get-cached - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: jtreg/installed key: jtreg-${{ steps.version.outputs.value }} - name: 'Checkout the JTReg source' - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: repository: openjdk/jtreg ref: jtreg-${{ steps.version.outputs.value }} @@ -61,7 +61,7 @@ runs: if: (steps.get-cached.outputs.cache-hit != 'true') - name: 'Upload JTReg artifact' - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: bundles-jtreg-${{ steps.version.outputs.value }} path: jtreg/installed diff --git a/.github/actions/do-build/action.yml b/.github/actions/do-build/action.yml index 6f2c2ce0218..6f6bbdabb68 100644 --- a/.github/actions/do-build/action.yml +++ b/.github/actions/do-build/action.yml @@ -66,7 +66,7 @@ runs: shell: bash - name: 'Upload build logs' - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: failure-logs-${{ inputs.platform }}${{ inputs.debug-suffix }} path: failure-logs @@ -74,7 +74,7 @@ runs: # This is the best way I found to abort the job with an error message - name: 'Notify about build failures' - uses: actions/github-script@v7 + uses: actions/github-script@v8 with: script: core.setFailed('Build failed. See summary for details.') if: steps.check.outputs.failure == 'true' diff --git a/.github/actions/get-bootjdk/action.yml b/.github/actions/get-bootjdk/action.yml index 312fb642c82..d531358b7dd 100644 --- a/.github/actions/get-bootjdk/action.yml +++ b/.github/actions/get-bootjdk/action.yml @@ -65,7 +65,7 @@ runs: - name: 'Check cache for BootJDK' id: get-cached-bootjdk - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: bootjdk/jdk key: boot-jdk-${{ inputs.platform }}-${{ steps.sha256.outputs.value }} diff --git a/.github/actions/get-bundles/action.yml b/.github/actions/get-bundles/action.yml index a356aa9fd8d..55fa0e842d2 100644 --- a/.github/actions/get-bundles/action.yml +++ b/.github/actions/get-bundles/action.yml @@ -54,14 +54,14 @@ runs: steps: - name: 'Download bundles artifact' id: download-bundles - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: name: bundles-${{ inputs.platform }}${{ inputs.debug-suffix }} path: bundles continue-on-error: true - name: 'Download bundles artifact (retry)' - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: name: bundles-${{ inputs.platform }}${{ inputs.debug-suffix }} path: bundles @@ -69,7 +69,7 @@ runs: - name: 'Download static bundles artifact' id: download-static-bundles - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: name: bundles-${{ inputs.platform }}${{ inputs.debug-suffix }}${{ inputs.static-suffix }} path: bundles diff --git a/.github/actions/get-gtest/action.yml b/.github/actions/get-gtest/action.yml index 7a329460a6e..bc53fa2a3b1 100644 --- a/.github/actions/get-gtest/action.yml +++ b/.github/actions/get-gtest/action.yml @@ -40,7 +40,7 @@ runs: var: GTEST_VERSION - name: 'Checkout GTest source' - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: repository: google/googletest ref: 'v${{ steps.version.outputs.value }}' diff --git a/.github/actions/get-jtreg/action.yml b/.github/actions/get-jtreg/action.yml index 36c895fc59d..8c75ae10c7f 100644 --- a/.github/actions/get-jtreg/action.yml +++ b/.github/actions/get-jtreg/action.yml @@ -41,7 +41,7 @@ runs: - name: 'Download JTReg artifact' id: download-jtreg - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: name: bundles-jtreg-${{ steps.version.outputs.value }} path: jtreg/installed diff --git a/.github/actions/get-msys2/action.yml b/.github/actions/get-msys2/action.yml index 308230ebf2e..7351a120ac4 100644 --- a/.github/actions/get-msys2/action.yml +++ b/.github/actions/get-msys2/action.yml @@ -31,7 +31,7 @@ runs: steps: - name: 'Install MSYS2' id: msys2 - uses: msys2/setup-msys2@v2.28.0 + uses: msys2/setup-msys2@v2.31.0 with: install: 'autoconf tar unzip zip make' path-type: minimal diff --git a/.github/actions/upload-bundles/action.yml b/.github/actions/upload-bundles/action.yml index 78fb0a94bfd..94308002ea7 100644 --- a/.github/actions/upload-bundles/action.yml +++ b/.github/actions/upload-bundles/action.yml @@ -87,7 +87,7 @@ runs: shell: bash - name: 'Upload bundles artifact' - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: bundles-${{ inputs.platform }}${{ inputs.debug-suffix }}${{ inputs.static-suffix }}${{ inputs.bundle-suffix }} path: bundles diff --git a/.github/workflows/build-alpine-linux.yml b/.github/workflows/build-alpine-linux.yml index c39962fa07f..6863da9016e 100644 --- a/.github/workflows/build-alpine-linux.yml +++ b/.github/workflows/build-alpine-linux.yml @@ -74,7 +74,7 @@ jobs: steps: - name: 'Checkout the JDK source' - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: 'Install toolchain and dependencies' run: | diff --git a/.github/workflows/build-cross-compile.yml b/.github/workflows/build-cross-compile.yml index a0642d469aa..99b6c40606c 100644 --- a/.github/workflows/build-cross-compile.yml +++ b/.github/workflows/build-cross-compile.yml @@ -94,7 +94,7 @@ jobs: steps: - name: 'Checkout the JDK source' - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: 'Get the BootJDK' id: bootjdk @@ -122,7 +122,7 @@ jobs: - name: 'Check cache for sysroot' id: get-cached-sysroot - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: sysroot key: sysroot-${{ matrix.debian-arch }}-${{ hashFiles('./.github/workflows/build-cross-compile.yml') }} diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index 791b53a3f04..c501670439e 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -84,7 +84,7 @@ jobs: steps: - name: 'Checkout the JDK source' - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: 'Get the BootJDK' id: bootjdk diff --git a/.github/workflows/build-macos.yml b/.github/workflows/build-macos.yml index 484e616fad7..435576f4afd 100644 --- a/.github/workflows/build-macos.yml +++ b/.github/workflows/build-macos.yml @@ -75,7 +75,7 @@ jobs: steps: - name: 'Checkout the JDK source' - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: 'Get the BootJDK' id: bootjdk diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index 4dafc016a99..3bb50a137ec 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -83,7 +83,7 @@ jobs: steps: - name: 'Checkout the JDK source' - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: 'Get MSYS2' uses: ./.github/actions/get-msys2 diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 85ec75f343c..20be196b128 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -75,7 +75,7 @@ jobs: steps: - name: 'Checkout the scripts' - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: sparse-checkout: | .github diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8f33454305e..b240b42fb97 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -128,7 +128,7 @@ jobs: steps: - name: 'Checkout the JDK source' - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: 'Get MSYS2' uses: ./.github/actions/get-msys2 @@ -239,7 +239,7 @@ jobs: if: always() - name: 'Upload test results' - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: path: results name: ${{ steps.package.outputs.artifact-name }} @@ -247,7 +247,7 @@ jobs: # This is the best way I found to abort the job with an error message - name: 'Notify about test failures' - uses: actions/github-script@v7 + uses: actions/github-script@v8 with: script: core.setFailed('${{ steps.run-tests.outputs.error-message }}') if: steps.run-tests.outputs.failure == 'true' From 29e1ee2eccd59e665827e0d42c490261002cf99e Mon Sep 17 00:00:00 2001 From: Martin Doerr Date: Mon, 30 Mar 2026 08:58:21 +0000 Subject: [PATCH 092/359] 8380565: PPC64: deoptimization stub should save vector registers Co-authored-by: Richard Reingruber Reviewed-by: rrich, dbriemann --- src/hotspot/cpu/ppc/registerMap_ppc.cpp | 46 ++ src/hotspot/cpu/ppc/registerMap_ppc.hpp | 8 +- src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp | 27 +- src/hotspot/cpu/ppc/vm_version_ppc.cpp | 3 +- .../vectorapi/TestVectorReallocation.java | 414 ++++++++++++++++++ 5 files changed, 483 insertions(+), 15 deletions(-) create mode 100644 src/hotspot/cpu/ppc/registerMap_ppc.cpp create mode 100644 test/hotspot/jtreg/compiler/vectorapi/TestVectorReallocation.java diff --git a/src/hotspot/cpu/ppc/registerMap_ppc.cpp b/src/hotspot/cpu/ppc/registerMap_ppc.cpp new file mode 100644 index 00000000000..2e7f8af89d3 --- /dev/null +++ b/src/hotspot/cpu/ppc/registerMap_ppc.cpp @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2026 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. + */ + +#include "runtime/registerMap.hpp" + +address RegisterMap::pd_location(VMReg base_reg, int slot_idx) const { + if (base_reg->is_VectorRegister()) { + // Not all physical slots belonging to a VectorRegister have corresponding + // valid VMReg locations in the RegisterMap. + // (See RegisterSaver::push_frame_reg_args_and_save_live_registers.) + // However, the slots are always saved to the stack in a contiguous region + // of memory so we can calculate the address of the upper slots by + // offsetting from the base address. + assert(base_reg->is_concrete(), "must pass base reg"); + address base_location = location(base_reg, nullptr); + if (base_location != nullptr) { + intptr_t offset_in_bytes = slot_idx * VMRegImpl::stack_slot_size; + return base_location + offset_in_bytes; + } else { + return nullptr; + } + } else { + return location(base_reg->next(slot_idx), nullptr); + } +} diff --git a/src/hotspot/cpu/ppc/registerMap_ppc.hpp b/src/hotspot/cpu/ppc/registerMap_ppc.hpp index 01eb642107c..607c712d10f 100644 --- a/src/hotspot/cpu/ppc/registerMap_ppc.hpp +++ b/src/hotspot/cpu/ppc/registerMap_ppc.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2013 SAP SE. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2026 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 @@ -35,9 +35,7 @@ // Since there is none, we just return null. address pd_location(VMReg reg) const { return nullptr; } - address pd_location(VMReg base_reg, int slot_idx) const { - return location(base_reg->next(slot_idx), nullptr); - } + address pd_location(VMReg base_reg, int slot_idx) const; // no PD state to clear or copy: void pd_clear() {} diff --git a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp index 5260ed978ff..53644210415 100644 --- a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp +++ b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp @@ -102,7 +102,7 @@ class RegisterSaver { // During deoptimization only the result registers need to be restored // all the other values have already been extracted. - static void restore_result_registers(MacroAssembler* masm, int frame_size_in_bytes); + static void restore_result_registers(MacroAssembler* masm, int frame_size_in_bytes, bool save_vectors); // Constants and data structures: @@ -349,7 +349,7 @@ OopMap* RegisterSaver::push_frame_reg_args_and_save_live_registers(MacroAssemble } // Note that generate_oop_map in the following loop is only used for the - // polling_page_vectors_safepoint_handler_blob. + // polling_page_vectors_safepoint_handler_blob and the deopt_blob. // The order in which the vector contents are stored depends on Endianess and // the utilized instructions (PowerArchitecturePPC64). assert(is_aligned(offset, StackAlignmentInBytes), "should be"); @@ -361,6 +361,7 @@ OopMap* RegisterSaver::push_frame_reg_args_and_save_live_registers(MacroAssemble __ stxvp(as_VectorRegister(reg_num).to_vsr(), offset, R1_SP); // Note: The contents were read in the same order (see loadV16_Power9 node in ppc.ad). + // RegisterMap::pd_location only uses the first VMReg for each VectorRegister. if (generate_oop_map) { map->set_callee_saved(VMRegImpl::stack2reg(offset >> 2), RegisterSaver_LiveVecRegs[i LITTLE_ENDIAN_ONLY(+1) ].vmreg); @@ -380,6 +381,7 @@ OopMap* RegisterSaver::push_frame_reg_args_and_save_live_registers(MacroAssemble __ stxvd2x(as_VectorRegister(reg_num)->to_vsr(), R31, R1_SP); } // Note: The contents were read in the same order (see loadV16_Power8 / loadV16_Power9 node in ppc.ad). + // RegisterMap::pd_location only uses the first VMReg for each VectorRegister. if (generate_oop_map) { VMReg vsr = RegisterSaver_LiveVecRegs[i].vmreg; map->set_callee_saved(VMRegImpl::stack2reg(offset >> 2), vsr); @@ -566,10 +568,14 @@ void RegisterSaver::restore_argument_registers_and_pop_frame(MacroAssembler*masm } // Restore the registers that might be holding a result. -void RegisterSaver::restore_result_registers(MacroAssembler* masm, int frame_size_in_bytes) { +void RegisterSaver::restore_result_registers(MacroAssembler* masm, int frame_size_in_bytes, bool save_vectors) { const int regstosave_num = sizeof(RegisterSaver_LiveRegs) / sizeof(RegisterSaver::LiveRegType); - const int register_save_size = regstosave_num * reg_size; // VS registers not relevant here. + const int vecregstosave_num = save_vectors ? (sizeof(RegisterSaver_LiveVecRegs) / + sizeof(RegisterSaver::LiveRegType)) + : 0; + const int register_save_size = regstosave_num * reg_size + vecregstosave_num * vec_reg_size; + const int register_save_offset = frame_size_in_bytes - register_save_size; // restore all result registers (ints and floats) @@ -598,7 +604,7 @@ void RegisterSaver::restore_result_registers(MacroAssembler* masm, int frame_siz offset += reg_size; } - assert(offset == frame_size_in_bytes, "consistency check"); + assert(offset == frame_size_in_bytes - (save_vectors ? vecregstosave_num * vec_reg_size : 0), "consistency check"); } // Is vector's size (in bytes) bigger than a size saved by default? @@ -2909,7 +2915,8 @@ void SharedRuntime::generate_deopt_blob() { map = RegisterSaver::push_frame_reg_args_and_save_live_registers(masm, &first_frame_size_in_bytes, /*generate_oop_map=*/ true, - RegisterSaver::return_pc_is_lr); + RegisterSaver::return_pc_is_lr, + /*save_vectors*/ SuperwordUseVSX); assert(map != nullptr, "OopMap must have been created"); __ li(exec_mode_reg, Deoptimization::Unpack_deopt); @@ -2943,7 +2950,8 @@ void SharedRuntime::generate_deopt_blob() { RegisterSaver::push_frame_reg_args_and_save_live_registers(masm, &first_frame_size_in_bytes, /*generate_oop_map=*/ false, - RegisterSaver::return_pc_is_pre_saved); + RegisterSaver::return_pc_is_pre_saved, + /*save_vectors*/ SuperwordUseVSX); // Deopt during an exception. Save exec mode for unpack_frames. __ li(exec_mode_reg, Deoptimization::Unpack_exception); @@ -2958,7 +2966,8 @@ void SharedRuntime::generate_deopt_blob() { RegisterSaver::push_frame_reg_args_and_save_live_registers(masm, &first_frame_size_in_bytes, /*generate_oop_map=*/ false, - RegisterSaver::return_pc_is_pre_saved); + RegisterSaver::return_pc_is_pre_saved, + /*save_vectors*/ SuperwordUseVSX); __ li(exec_mode_reg, Deoptimization::Unpack_reexecute); #endif @@ -2984,7 +2993,7 @@ void SharedRuntime::generate_deopt_blob() { // Restore only the result registers that have been saved // by save_volatile_registers(...). - RegisterSaver::restore_result_registers(masm, first_frame_size_in_bytes); + RegisterSaver::restore_result_registers(masm, first_frame_size_in_bytes, /*save_vectors*/ SuperwordUseVSX); // reload the exec mode from the UnrollBlock (it might have changed) __ lwz(exec_mode_reg, in_bytes(Deoptimization::UnrollBlock::unpack_kind_offset()), unroll_block_reg); diff --git a/src/hotspot/cpu/ppc/vm_version_ppc.cpp b/src/hotspot/cpu/ppc/vm_version_ppc.cpp index e471f5a6e4f..0b69ef7d25a 100644 --- a/src/hotspot/cpu/ppc/vm_version_ppc.cpp +++ b/src/hotspot/cpu/ppc/vm_version_ppc.cpp @@ -25,6 +25,7 @@ #include "asm/assembler.inline.hpp" #include "asm/macroAssembler.inline.hpp" +#include "compiler/compilerDefinitions.inline.hpp" #include "compiler/disassembler.hpp" #include "jvm.h" #include "memory/resourceArea.hpp" @@ -105,7 +106,7 @@ void VM_Version::initialize() { if (PowerArchitecturePPC64 >= 9) { // Performance is good since Power9. - if (FLAG_IS_DEFAULT(SuperwordUseVSX)) { + if (FLAG_IS_DEFAULT(SuperwordUseVSX) && CompilerConfig::is_c2_enabled()) { FLAG_SET_ERGO(SuperwordUseVSX, true); } } diff --git a/test/hotspot/jtreg/compiler/vectorapi/TestVectorReallocation.java b/test/hotspot/jtreg/compiler/vectorapi/TestVectorReallocation.java new file mode 100644 index 00000000000..1bdc6ea726d --- /dev/null +++ b/test/hotspot/jtreg/compiler/vectorapi/TestVectorReallocation.java @@ -0,0 +1,414 @@ +/* + * Copyright (c) 2026 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package compiler.vectorapi; + +import java.util.Arrays; + +import compiler.lib.ir_framework.*; + +import jdk.incubator.vector.ByteVector; +import jdk.incubator.vector.ShortVector; +import jdk.incubator.vector.IntVector; +import jdk.incubator.vector.LongVector; +import jdk.incubator.vector.FloatVector; +import jdk.incubator.vector.DoubleVector; +import jdk.incubator.vector.VectorSpecies; + +import static jdk.test.lib.Asserts.*; + +/** + * @test + * @bug 8380565 + * @library /test/lib / + * @summary Test deoptimization involving vector reallocation + * @modules jdk.incubator.vector + * @requires vm.opt.final.MaxVectorSize == null | vm.opt.final.MaxVectorSize >= 16 + * + * @run driver compiler.vectorapi.TestVectorReallocation + */ + +public class TestVectorReallocation { + + private static final VectorSpecies B_SPECIES = ByteVector.SPECIES_PREFERRED; + private static final VectorSpecies S_SPECIES = ShortVector.SPECIES_PREFERRED; + private static final VectorSpecies I_SPECIES = IntVector.SPECIES_PREFERRED; + private static final VectorSpecies L_SPECIES = LongVector.SPECIES_PREFERRED; + private static final VectorSpecies F_SPECIES = FloatVector.SPECIES_PREFERRED; + private static final VectorSpecies D_SPECIES = DoubleVector.SPECIES_PREFERRED; + private static final int B_LENGTH = B_SPECIES.length(); + private static final int S_LENGTH = S_SPECIES.length(); + private static final int I_LENGTH = I_SPECIES.length(); + private static final int L_LENGTH = L_SPECIES.length(); + private static final int F_LENGTH = F_SPECIES.length(); + private static final int D_LENGTH = D_SPECIES.length(); + + // The input arrays for the @Test methods match the length of the preferred species for each type + private static byte[] b_a; + private static short[] s_a; + private static int[] i_a; + private static long[] l_a; + private static float[] f_a; + private static double[] d_a; + + // The output arrays for the @Test methods + private static byte[] b_r; + private static short[] s_r; + private static int[] i_r; + private static long[] l_r; + private static float[] f_r; + private static double[] d_r; + + public static void main(String[] args) { + TestFramework.runWithFlags("--add-modules=jdk.incubator.vector"); + } + + // The test methods annotated with @Test are warmed up by the framework. The calls are indirect + // through the runner methods annotated with @Run. Note that each @Test method has its own instance of + // the test class TestVectorReallocation as receiver of the calls. + // + // The @Test methods just copy the elements of the input array (0, 1, 2, 3, ...) to the output array + // by means of a vector add operation. The added value is computed but actually always zero. The + // computation is done in a loop with a virtual call that is inlined based on class hierarchy analysis + // when the method gets compiled. + // + // The final call after warmup of the now compiled @Test method is performed concurrently in a second + // thread. Before the variable `loopIterations` is set very high such that the loop runs practically + // infinitely. While the loop is running, a class with an overridden version of the method `value` + // (called in the loop) is loaded. This invalidates the result of the class hierarchy analysis that + // there is just one implementation of the method and causes deoptimization where the vector `v0` used + // in the @Test method is reallocated from a register to the java heap. Finally it is verified that + // input and ouput arrays are equal. + // + // NB: each @Test needs its own Zero class for the desired result of the class hierarchy analysis. + + volatile boolean enteredLoop; + volatile long loopIterations; + + void sharedRunner(RunInfo runInfo, Runnable test, Runnable loadOverridingClass, Runnable verify) { + enteredLoop = false; + if (runInfo.isWarmUp()) { + loopIterations = 100; + test.run(); + } else { + loopIterations = 1L << 60; // basically infinite + Thread t = Thread.ofPlatform().start(test); + waitUntilLoopEntered(); + loadOverridingClass.run(); // invalidates inlining causing deoptimization/reallocation of v0 + loopIterations = 0; + waitUntilLoopLeft(); + joinThread(t); + verify.run(); // verify that input and ouput arrays are equal + } + } + + ///////////////////////////////////////////////////////////////////////////////////// + // byte + + static class ByteZero { + volatile byte zero; + byte value() { + return zero; + } + } + volatile ByteZero byteZero = new ByteZero(); + + @Run(test = "byteIdentityWithReallocation") + void byteIdentityWithReallocation_runner(RunInfo runInfo) { + sharedRunner(runInfo, () -> byteIdentityWithReallocation(), () -> { + // Loading the class with the overridden method will cause deoptimization and reallocation of v0 + byteZero = new ByteZero() { + @Override + byte value() { + return super.value(); // override but doing the same + } + }; + }, + () -> assertTrue(Arrays.equals(b_a, b_r), "Input/Output arrays differ")); + } + + @Test + @IR(counts = {IRNode.ADD_VB, " >0 "}) + void byteIdentityWithReallocation() { + ByteVector v0 = ByteVector.fromArray(B_SPECIES, b_a, 0); + byte zeroSum = 0; + enteredLoop = true; + for (long i = 0; i < loopIterations; i++) { + zeroSum += byteZero.value(); // inlined based on class hierarchy analysis + } + v0.add(zeroSum).intoArray(b_r, 0); + enteredLoop = false; + } + + ///////////////////////////////////////////////////////////////////////////////////// + // short + + static class ShortZero { + volatile short zero; + short value() { + return zero; + } + } + volatile ShortZero shortZero = new ShortZero(); + + @Run(test = "shortIdentityWithReallocation") + void shortIdentityWithReallocation_runner(RunInfo runInfo) { + sharedRunner(runInfo, () -> shortIdentityWithReallocation(), () -> { + // Loading the class with the overridden method will cause deoptimization and reallocation of v0 + shortZero = new ShortZero() { + @Override + short value() { + return super.value(); // override but doing the same + } + }; + }, + () -> assertTrue(Arrays.equals(s_a, s_r), "Input/Output arrays differ")); + } + + @Test + @IR(counts = {IRNode.ADD_VS, " >0 "}) + void shortIdentityWithReallocation() { + ShortVector v0 = ShortVector.fromArray(S_SPECIES, s_a, 0); + short zeroSum = 0; + enteredLoop = true; + for (long i = 0; i < loopIterations; i++) { + zeroSum += shortZero.value(); // inlined based on class hierarchy analysis + } + v0.add(zeroSum).intoArray(s_r, 0); + enteredLoop = false; + } + + ///////////////////////////////////////////////////////////////////////////////////// + // int + + static class IntZero { + volatile int zero; + int value() { + return zero; + } + } + volatile IntZero intZero = new IntZero(); + + @Run(test = "intIdentityWithReallocation") + void intIdentityWithReallocation_runner(RunInfo runInfo) { + sharedRunner(runInfo, () -> intIdentityWithReallocation(), () -> { + // Loading the class with the overridden method will cause deoptimization and reallocation of v0 + intZero = new IntZero() { + @Override + int value() { + return super.value(); // override but doing the same + } + }; + }, + () -> assertTrue(Arrays.equals(i_a, i_r), "Input/Output arrays differ")); + } + + @Test + @IR(counts = {IRNode.ADD_VI, " >0 "}) + void intIdentityWithReallocation() { + IntVector v0 = IntVector.fromArray(I_SPECIES, i_a, 0); + int zeroSum = 0; + enteredLoop = true; + for (long i = 0; i < loopIterations; i++) { + zeroSum += intZero.value(); // inlined based on class hierarchy analysis + } + v0.add(zeroSum).intoArray(i_r, 0); + enteredLoop = false; + } + + ///////////////////////////////////////////////////////////////////////////////////// + // long + + static class LongZero { + volatile long zero; + long value() { + return zero; + } + } + volatile LongZero longZero = new LongZero(); + + @Run(test = "longIdentityWithReallocation") + void longIdentityWithReallocation_runner(RunInfo runInfo) { + sharedRunner(runInfo, () -> longIdentityWithReallocation(), () -> { + // Loading the class with the overridden method will cause deoptimization and reallocation of v0 + longZero = new LongZero() { + @Override + long value() { + return super.value(); // override but doing the same + } + }; + }, + () -> assertTrue(Arrays.equals(l_a, l_r), "Input/Output arrays differ")); + } + + @Test + @IR(counts = {IRNode.ADD_VL, " >0 "}) + void longIdentityWithReallocation() { + LongVector v0 = LongVector.fromArray(L_SPECIES, l_a, 0); + long zeroSum = 0; + enteredLoop = true; + for (long i = 0; i < loopIterations; i++) { + zeroSum += longZero.value(); // inlined based on class hierarchy analysis + } + v0.add(zeroSum).intoArray(l_r, 0); + enteredLoop = false; + } + + ///////////////////////////////////////////////////////////////////////////////////// + // float + + static class FloatZero { + volatile float zero; + float value() { + return zero; + } + } + volatile FloatZero floatZero = new FloatZero(); + + @Run(test = "floatIdentityWithReallocation") + void floatIdentityWithReallocation_runner(RunInfo runInfo) { + sharedRunner(runInfo, () -> floatIdentityWithReallocation(), () -> { + // Loading the class with the overridden method will cause deoptimization and reallocation of v0 + floatZero = new FloatZero() { + @Override + float value() { + return super.value(); // override but doing the same + } + }; + }, + () -> assertTrue(Arrays.equals(f_a, f_r), "Input/Output arrays differ")); + } + + @Test + @IR(counts = {IRNode.ADD_VF, " >0 "}) + void floatIdentityWithReallocation() { + FloatVector v0 = FloatVector.fromArray(F_SPECIES, f_a, 0); + float zeroSum = 0; + enteredLoop = true; + for (long i = 0; i < loopIterations; i++) { + zeroSum += floatZero.value(); // inlined based on class hierarchy analysis + } + v0.add(zeroSum).intoArray(f_r, 0); + enteredLoop = false; + } + + ///////////////////////////////////////////////////////////////////////////////////// + // double + + static class DoubleZero { + volatile double zero; + double value() { + return zero; + } + } + volatile DoubleZero doubleZero = new DoubleZero(); + + @Run(test = "doubleIdentityWithReallocation") + void doubleIdentityWithReallocation_runner(RunInfo runInfo) { + sharedRunner(runInfo, () -> doubleIdentityWithReallocation(), () -> { + // Loading the class with the overridden method will cause deoptimization and reallocation of v0 + doubleZero = new DoubleZero() { + @Override + double value() { + return super.value(); // override but doing the same + } + }; + }, + () -> assertTrue(Arrays.equals(d_a, d_r), "Input/Output arrays differ")); + } + + @Test + @IR(counts = {IRNode.ADD_VD, " >0 "}) + void doubleIdentityWithReallocation() { + DoubleVector v0 = DoubleVector.fromArray(D_SPECIES, d_a, 0); + double zeroSum = 0; + enteredLoop = true; + for (long i = 0; i < loopIterations; i++) { + zeroSum += doubleZero.value(); // inlined based on class hierarchy analysis + } + v0.add(zeroSum).intoArray(d_r, 0); + enteredLoop = false; + } + + ///////////////////////////////////////////////////////////////////////////////////// + + private void waitUntilLoopEntered() { + while (!enteredLoop) { + sleep(10); + } + } + + private void waitUntilLoopLeft() { + while (enteredLoop) { + sleep(10); + } + } + + private static void sleep(int ms) { + try { + Thread.sleep(ms); + } catch (InterruptedException e) { /* ignore */ } + } + + private static void joinThread(Thread t) { + try { + t.join(); + } catch (InterruptedException e) { /* ignore */ } + } + + static { + b_a = new byte[B_LENGTH]; + s_a = new short[S_LENGTH]; + i_a = new int[I_LENGTH]; + l_a = new long[L_LENGTH]; + f_a = new float[F_LENGTH]; + d_a = new double[D_LENGTH]; + + b_r = new byte[B_LENGTH]; + s_r = new short[S_LENGTH]; + i_r = new int[I_LENGTH]; + l_r = new long[L_LENGTH]; + f_r = new float[F_LENGTH]; + d_r = new double[D_LENGTH]; + + for (int i = 0; i < b_a.length ; i++) { + b_a[i] = (byte)i; + } + for (int i = 0; i < s_a.length ; i++) { + s_a[i] = (short)i; + } + for (int i = 0; i < i_a.length ; i++) { + i_a[i] = i; + } + for (int i = 0; i < l_a.length ; i++) { + l_a[i] = i; + } + for (int i = 0; i < f_a.length ; i++) { + f_a[i] = i; + } + for (int i = 0; i < d_a.length ; i++) { + d_a[i] = i; + } + } +} From 4d7c13950954950201834e9d4afebdd36a522a81 Mon Sep 17 00:00:00 2001 From: Casper Norrbin Date: Mon, 30 Mar 2026 09:28:51 +0000 Subject: [PATCH 093/359] 8379415: Contended classes can leave unused alignment padding Reviewed-by: coleenp, fparain, lfoltan, liach --- .../share/classfile/fieldLayoutBuilder.cpp | 24 +- .../share/classfile/fieldLayoutBuilder.hpp | 4 +- .../runtime/contended/MixedPrimitives.java | 356 ++++++++++++++++++ 3 files changed, 376 insertions(+), 8 deletions(-) create mode 100644 test/hotspot/jtreg/runtime/contended/MixedPrimitives.java diff --git a/src/hotspot/share/classfile/fieldLayoutBuilder.cpp b/src/hotspot/share/classfile/fieldLayoutBuilder.cpp index a87e12edc96..8a9f5946091 100644 --- a/src/hotspot/share/classfile/fieldLayoutBuilder.cpp +++ b/src/hotspot/share/classfile/fieldLayoutBuilder.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -596,11 +596,13 @@ void FieldLayoutBuilder::regular_field_sorting() { } } -void FieldLayoutBuilder::insert_contended_padding(LayoutRawBlock* slot) { +LayoutRawBlock* FieldLayoutBuilder::insert_contended_padding(LayoutRawBlock* slot) { + LayoutRawBlock* padding = nullptr; if (ContendedPaddingWidth > 0) { - LayoutRawBlock* padding = new LayoutRawBlock(LayoutRawBlock::PADDING, ContendedPaddingWidth); + padding = new LayoutRawBlock(LayoutRawBlock::PADDING, ContendedPaddingWidth); _layout->insert(slot, padding); } + return padding; } // Computation of regular classes layout is an evolution of the previous default layout @@ -620,10 +622,14 @@ void FieldLayoutBuilder::compute_regular_layout() { regular_field_sorting(); if (_is_contended) { - _layout->set_start(_layout->last_block()); // insertion is currently easy because the current strategy doesn't try to fill holes // in super classes layouts => the _start block is by consequence the _last_block - insert_contended_padding(_layout->start()); + _layout->set_start(_layout->last_block()); + LayoutRawBlock* padding = insert_contended_padding(_layout->start()); + if (padding != nullptr) { + // Setting the padding block as start ensures we do not insert past it. + _layout->set_start(padding); + } need_tail_padding = true; } @@ -639,7 +645,13 @@ void FieldLayoutBuilder::compute_regular_layout() { for (int i = 0; i < _contended_groups.length(); i++) { FieldGroup* cg = _contended_groups.at(i); LayoutRawBlock* start = _layout->last_block(); - insert_contended_padding(start); + LayoutRawBlock* padding = insert_contended_padding(start); + + // Do not insert fields past the padding block. + if (padding != nullptr) { + start = padding; + } + _layout->add(cg->primitive_fields(), start); _layout->add(cg->oop_fields(), start); need_tail_padding = true; diff --git a/src/hotspot/share/classfile/fieldLayoutBuilder.hpp b/src/hotspot/share/classfile/fieldLayoutBuilder.hpp index 82bbaefc623..eab0b7d08a9 100644 --- a/src/hotspot/share/classfile/fieldLayoutBuilder.hpp +++ b/src/hotspot/share/classfile/fieldLayoutBuilder.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ class FieldLayoutBuilder : public ResourceObj { void build_layout(); void compute_regular_layout(); - void insert_contended_padding(LayoutRawBlock* slot); + LayoutRawBlock* insert_contended_padding(LayoutRawBlock* slot); private: void prologue(); diff --git a/test/hotspot/jtreg/runtime/contended/MixedPrimitives.java b/test/hotspot/jtreg/runtime/contended/MixedPrimitives.java new file mode 100644 index 00000000000..a7165578831 --- /dev/null +++ b/test/hotspot/jtreg/runtime/contended/MixedPrimitives.java @@ -0,0 +1,356 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.lang.Class; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import jdk.internal.misc.Unsafe; +import jdk.internal.vm.annotation.Contended; + +/* + * @test + * @summary \@Contended with different sized primitive types + * @modules java.base/jdk.internal.misc + * @modules java.base/jdk.internal.vm.annotation + * @run main/othervm -XX:-RestrictContended MixedPrimitives + */ +public class MixedPrimitives { + + private static final Unsafe U = Unsafe.getUnsafe(); + private static final int ADDRESS_SIZE; + private static final int HEADER_SIZE; + + static { + // When running with CompressedOops on 64-bit platform, the address size + // reported by Unsafe is still 8, while the real reference fields are 4 bytes long. + // Try to guess the reference field size with this naive trick. + try { + long off1 = U.objectFieldOffset(CompressedOopsClass.class.getField("obj1")); + long off2 = U.objectFieldOffset(CompressedOopsClass.class.getField("obj2")); + ADDRESS_SIZE = (int) Math.abs(off2 - off1); + HEADER_SIZE = (int) Math.min(off1, off2); + } catch (NoSuchFieldException e) { + throw new ExceptionInInitializerError(e); + } + } + + static class CompressedOopsClass { + public Object obj1; + public Object obj2; + } + + public static boolean arePaddedPairwise(Class klass, String field1, String field2) throws Exception { + Field f1 = klass.getDeclaredField(field1); + Field f2 = klass.getDeclaredField(field2); + + if (isStatic(f1) != isStatic(f2)) { + return true; // these guys are in naturally disjoint locations + } + + int diff = offset(f1) - offset(f2); + if (diff < 0) { + // f1 is first + return (offset(f2) - (offset(f1) + getSize(f1))) > 64; + } else { + // f2 is first + return (offset(f1) - (offset(f2) + getSize(f2))) > 64; + } + } + + public static boolean isPadded(Class klass, String field1) throws Exception { + Field f1 = klass.getDeclaredField(field1); + + if (isStatic(f1)) { + return offset(f1) > 128 + 64; + } + + return offset(f1) > 64; + } + + public static boolean sameLayout(Class klass1, Class klass2) throws Exception { + try { + for (Field f1 : klass1.getDeclaredFields()) { + Field f2 = klass2.getDeclaredField(f1.getName()); + if (offset(f1) != offset(f2)) { + return false; + } + } + + for (Field f2 : klass1.getDeclaredFields()) { + Field f1 = klass2.getDeclaredField(f2.getName()); + if (offset(f1) != offset(f2)) { + return false; + } + } + } catch (Exception e) { + System.err.println("Failed getting layout from class: " + e.getMessage()); + return false; + } + + return true; + } + + public static boolean isStatic(Field field) { + return Modifier.isStatic(field.getModifiers()); + } + + public static int offset(Field field) { + if (isStatic(field)) { + return (int) U.staticFieldOffset(field); + } else { + return (int) U.objectFieldOffset(field); + } + } + + public static int getSize(Field field) { + Class type = field.getType(); + if (type == byte.class) { return 1; } + if (type == boolean.class) { return 1; } + if (type == short.class) { return 2; } + if (type == char.class) { return 2; } + if (type == int.class) { return 4; } + if (type == float.class) { return 4; } + if (type == long.class) { return 8; } + if (type == double.class) { return 8; } + return ADDRESS_SIZE; + } + + public static void main(String[] args) throws Exception { + int failures = 0; + + failures += Test1.checkLayout(); + failures += Test2.checkLayout(); + failures += Test3.checkLayout(); + failures += Test4.checkLayout(); + failures += Test5.checkLayout(); + failures += Test6.checkLayout(); + failures += Test7.checkLayout(); + failures += Test8.checkLayout(); + failures += Test9.checkLayout(); + + if (!sameLayout(Test4.class, Test7.class)) { + System.err.println("Test4 and Test7 have different layouts"); + failures += 1; + } + + if (!sameLayout(Test5.class, Test6.class)) { + System.err.println("Test5 and Test6 have different layouts"); + failures += 1; + } + + if (!sameLayout(Test8.class, Test9.class)) { + System.err.println("Test8 and Test9 have different layouts"); + failures += 1; + } + + System.out.println(failures == 0 ? "Test PASSES" : "Test FAILS"); + if (failures > 0) { + throw new Error("Test failed. Incurred " + failures + " failures."); + } + } + + // naturally packed + public static class Test1 { + private long long1; + private int int1; + private short short1; + + public static int checkLayout() throws Exception { + if (arePaddedPairwise(Test1.class, "long1", "int1") || + arePaddedPairwise(Test1.class, "long1", "short1") || + arePaddedPairwise(Test1.class, "int1", "short1") || + isPadded(Test1.class, "long1") || + isPadded(Test1.class, "int1") || + isPadded(Test1.class, "short1")) { + System.err.println("Test1 failed"); + return 1; + } + return 0; + } + } + + // long1 is padded + public static class Test2 { + @Contended private long long1; + private int int1; + private short short1; + + public static int checkLayout() throws Exception { + if (!arePaddedPairwise(Test2.class, "long1", "int1") || + !arePaddedPairwise(Test2.class, "long1", "short1") || + arePaddedPairwise(Test2.class, "int1", "short1") || + !isPadded(Test2.class, "long1") || + isPadded(Test2.class, "int1") || + isPadded(Test2.class, "short1")) { + System.err.println("Test2 failed"); + return 1; + } + return 0; + } + } + + // both fields are padded + public static class Test3 { + @Contended private long long1; + @Contended private int int1; + @Contended private short short1; + + public static int checkLayout() throws Exception { + if (!arePaddedPairwise(Test3.class, "long1", "int1") || + !arePaddedPairwise(Test3.class, "long1", "short1") || + !arePaddedPairwise(Test3.class, "int1", "short1") || + !isPadded(Test3.class, "long1") || + !isPadded(Test3.class, "int1") || + !isPadded(Test3.class, "short1")) { + System.err.println("Test3 failed"); + return 1; + } + return 0; + } + } + + // fields are padded in the singular group + public static class Test4 { + @Contended("sameGroup") private long long1; + @Contended("sameGroup") private int int1; + @Contended("sameGroup") private short short1; + + public static int checkLayout() throws Exception { + if (arePaddedPairwise(Test4.class, "long1", "int1") || + arePaddedPairwise(Test4.class, "long1", "short1") || + arePaddedPairwise(Test4.class, "int1", "short1") || + !isPadded(Test4.class, "long1") || + !isPadded(Test4.class, "int1") || + !isPadded(Test4.class, "short1")) { + System.err.println("Test4 failed"); + return 1; + } + return 0; + } + } + + // fields are padded in disjoint groups + public static class Test5 { + @Contended("diffGroup1") private long long1; + @Contended("diffGroup2") private int int1; + @Contended("diffGroup3") private short short1; + + public static int checkLayout() throws Exception { + if (!arePaddedPairwise(Test5.class, "long1", "int1") || + !arePaddedPairwise(Test5.class, "long1", "short1") || + !arePaddedPairwise(Test5.class, "int1", "short1") || + !isPadded(Test5.class, "long1") || + !isPadded(Test5.class, "int1") || + !isPadded(Test5.class, "short1")) { + System.err.println("Test5 failed"); + return 1; + } + return 0; + } + } + + // fields are padded in disjoint groups + public static class Test6 { + @Contended private long long1; + @Contended("diffGroup2") private int int1; + @Contended("diffGroup3") private short short1; + + public static int checkLayout() throws Exception { + if (!arePaddedPairwise(Test6.class, "long1", "int1") || + !arePaddedPairwise(Test6.class, "long1", "short1") || + !arePaddedPairwise(Test6.class, "int1", "short1") || + !isPadded(Test6.class, "long1") || + !isPadded(Test6.class, "int1") || + !isPadded(Test6.class, "short1")) { + System.err.println("Test6 failed"); + return 1; + } + return 0; + } + } + + // fields are padded in the singular group + @Contended + public static class Test7 { + private long long1; + private int int1; + private short short1; + + public static int checkLayout() throws Exception { + if (arePaddedPairwise(Test7.class, "long1", "int1") || + arePaddedPairwise(Test7.class, "long1", "short1") || + arePaddedPairwise(Test7.class, "int1", "short1") || + !isPadded(Test7.class, "long1") || + !isPadded(Test7.class, "int1") || + !isPadded(Test7.class, "short1")) { + System.err.println("Test7 failed"); + return 1; + } + return 0; + } + } + + // all fields are padded as the group, and one field is padded specifically + @Contended + public static class Test8 { + @Contended private long long1; + private int int1; + private short short1; + + public static int checkLayout() throws Exception { + if (!arePaddedPairwise(Test8.class, "long1", "int1") || + !arePaddedPairwise(Test8.class, "long1", "short1") || + arePaddedPairwise(Test8.class, "int1", "short1") || + !isPadded(Test8.class, "long1") || + !isPadded(Test8.class, "int1") || + !isPadded(Test8.class, "short1")) { + System.err.println("Test8 failed"); + return 1; + } + return 0; + } + } + + // all fields are padded as the group, and one field is padded specifically + @Contended + public static class Test9 { + @Contended("group") private long long1; + private int int1; + private short short1; + + public static int checkLayout() throws Exception { + if (!arePaddedPairwise(Test9.class, "long1", "int1") || + !arePaddedPairwise(Test9.class, "long1", "short1") || + arePaddedPairwise(Test9.class, "int1", "short1") || + !isPadded(Test9.class, "long1") || + !isPadded(Test9.class, "int1") || + !isPadded(Test9.class, "short1")) { + System.err.println("Test9 failed"); + return 1; + } + return 0; + } + } + +} + From 3eaeb9b1ad82d165798a986a2d9378d52af0ca38 Mon Sep 17 00:00:00 2001 From: Christian Hagedorn Date: Mon, 30 Mar 2026 10:25:58 +0000 Subject: [PATCH 094/359] 8380945: [IR Framework] Test VM is finished before TestFrameworkSocket is ready to accept connection Reviewed-by: mchevalier, thartmann --- .../ir_framework/driver/TestVMProcess.java | 1 + .../shared/TestFrameworkSocket.java | 49 +++++++++++++++---- 2 files changed, 40 insertions(+), 10 deletions(-) diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/TestVMProcess.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/TestVMProcess.java index 00a9b93d124..bfffbdbec7e 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/TestVMProcess.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/TestVMProcess.java @@ -68,6 +68,7 @@ public class TestVMProcess { this.cmds = new ArrayList<>(); TestFrameworkSocket socket = new TestFrameworkSocket(); try (socket) { + socket.start(); prepareTestVMFlags(additionalFlags, socket, testClass, helperClasses, defaultWarmup, allowNotCompilable, testClassesOnBootClassPath); start(); diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/shared/TestFrameworkSocket.java b/test/hotspot/jtreg/compiler/lib/ir_framework/shared/TestFrameworkSocket.java index 77d560952f1..44063a4bd43 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/shared/TestFrameworkSocket.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/shared/TestFrameworkSocket.java @@ -42,9 +42,13 @@ public class TestFrameworkSocket implements AutoCloseable { private final int serverSocketPort; private final ServerSocket serverSocket; - private boolean running; - private final ExecutorService executor; - private Future javaFuture; + private final ExecutorService acceptExecutor; + private final ExecutorService clientExecutor; + + // Make these volatile such that the main thread can observe an update written by the worker threads in the executor + // services to avoid stale values. + private volatile boolean running; + private volatile Future javaFuture; public TestFrameworkSocket() { try { @@ -54,29 +58,53 @@ public class TestFrameworkSocket implements AutoCloseable { throw new TestFrameworkException("Failed to create TestFramework server socket", e); } serverSocketPort = serverSocket.getLocalPort(); - executor = Executors.newCachedThreadPool(); + acceptExecutor = Executors.newSingleThreadExecutor(); + clientExecutor = Executors.newCachedThreadPool(); if (TestFramework.VERBOSE) { System.out.println("TestFramework server socket uses port " + serverSocketPort); } - start(); } public String getPortPropertyFlag() { return "-D" + SERVER_PORT_PROPERTY + "=" + serverSocketPort; } - private void start() { + public void start() { running = true; - executor.submit(this::acceptLoop); + CountDownLatch calledAcceptLoopLatch = new CountDownLatch(1); + startAcceptLoop(calledAcceptLoopLatch); + } + + private void startAcceptLoop(CountDownLatch calledAcceptLoopLatch) { + acceptExecutor.submit(() -> acceptLoop(calledAcceptLoopLatch)); + waitUntilAcceptLoopRuns(calledAcceptLoopLatch); + } + + private void waitUntilAcceptLoopRuns(CountDownLatch calledAcceptLoopLatch) { + try { + if (!calledAcceptLoopLatch.await(10, TimeUnit.SECONDS)) { + throw new IllegalStateException("acceptLoop did not start in time"); + } + } catch (Exception e) { + throw new TestFrameworkException("Could not start TestFrameworkSocket", e); + } } /** * Main loop to wait for new client connections and handling them upon connection request. */ - private void acceptLoop() { + private void acceptLoop(CountDownLatch calledAcceptLoopLatch) { + calledAcceptLoopLatch.countDown(); while (running) { try { acceptNewClientConnection(); + } catch (SocketException e) { + if (!running || serverSocket.isClosed()) { + // Normal shutdown + return; + } + running = false; + throw new TestFrameworkException("Server socket error", e); } catch (TestFrameworkException e) { running = false; throw e; @@ -101,7 +129,7 @@ public class TestFrameworkSocket implements AutoCloseable { * over that connection. */ private void submitTask(Socket client, BufferedReader reader) { - javaFuture = executor.submit(new TestVmMessageReader(client, reader)); + javaFuture = clientExecutor.submit(new TestVmMessageReader(client, reader)); } @Override @@ -112,7 +140,8 @@ public class TestFrameworkSocket implements AutoCloseable { } catch (IOException e) { throw new TestFrameworkException("Could not close socket", e); } - executor.shutdown(); + acceptExecutor.shutdown(); + clientExecutor.shutdown(); } public TestVMData testVmData(String hotspotPidFileName, boolean allowNotCompilable) { From 6b9887b4f518c5b26d6a9700b7ae0dea8b140164 Mon Sep 17 00:00:00 2001 From: Yasumasa Suenaga Date: Mon, 30 Mar 2026 11:53:03 +0000 Subject: [PATCH 095/359] 8378902: Test compiler/vectorapi/TestVectorLibraryUnaryOpAndBinaryOp.java failed Reviewed-by: mbaesken, thartmann --- .../TestVectorLibraryUnaryOpAndBinaryOp.java | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/test/hotspot/jtreg/compiler/vectorapi/TestVectorLibraryUnaryOpAndBinaryOp.java b/test/hotspot/jtreg/compiler/vectorapi/TestVectorLibraryUnaryOpAndBinaryOp.java index f7837e1abfa..731c87e69f7 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/TestVectorLibraryUnaryOpAndBinaryOp.java +++ b/test/hotspot/jtreg/compiler/vectorapi/TestVectorLibraryUnaryOpAndBinaryOp.java @@ -26,12 +26,13 @@ package compiler.vectorapi; import compiler.lib.ir_framework.*; import jdk.incubator.vector.*; +import jtreg.SkippedException; /** * @test - * @bug 8378312 + * @bug 8378312 8378902 * @library /test/lib / - * @summary VectorAPI: libraryUnaryOp and libraryBinaryOp should be intrinsified. + * @summary VectorAPI: libraryUnaryOp and libraryBinaryOp should be intrinsified. This test would be run on SVML/SLEEF supported platforms only. * @modules jdk.incubator.vector * * @run driver compiler.vectorapi.TestVectorLibraryUnaryOpAndBinaryOp @@ -53,7 +54,24 @@ public class TestVectorLibraryUnaryOpAndBinaryOp { vec.lanewise(VectorOperators.HYPOT, 1.0f); } + private static void checkVectorMathLib() { + try { + // Check jsvml first + System.loadLibrary("jsvml"); + } catch (UnsatisfiedLinkError _) { + try { + // Check sleef if jsvml not found + System.loadLibrary("sleef"); + } catch (UnsatisfiedLinkError _) { + // This test is run on unsupported platform - should be skipped + throw new SkippedException("SVML / SLEEF not found"); + } + } + } + public static void main(String[] args) { + checkVectorMathLib(); + TestFramework testFramework = new TestFramework(); testFramework.addFlags("--add-modules=jdk.incubator.vector") .start(); From 7e0a1499ee5743cb8b36ad0150fa3a538b368e27 Mon Sep 17 00:00:00 2001 From: Koushik Thirupattur Date: Mon, 30 Mar 2026 12:50:42 +0000 Subject: [PATCH 096/359] 8345954: Revisit Class Initializers and Locking in X509TrustManagerImpl Reviewed-by: weijun --- .../sun/security/provider/X509Factory.java | 83 +++++++++++-------- 1 file changed, 49 insertions(+), 34 deletions(-) diff --git a/src/java.base/share/classes/sun/security/provider/X509Factory.java b/src/java.base/share/classes/sun/security/provider/X509Factory.java index f732c7c0455..4be83d629bb 100644 --- a/src/java.base/share/classes/sun/security/provider/X509Factory.java +++ b/src/java.base/share/classes/sun/security/provider/X509Factory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2026, Oracle and/or its affiliates. All rights reserved. * 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,9 +112,10 @@ public class X509Factory extends CertificateFactorySpi { if (cert != null) { return cert; } - cert = new X509CertImpl(encoding); - addToCache(certCache, cert.getEncodedInternal(), cert); - return cert; + // Build outside lock + X509CertImpl newCert = new X509CertImpl(encoding); + byte[] enc = newCert.getEncodedInternal(); + return addIfNotPresent(certCache, enc, newCert); } /** @@ -156,7 +157,7 @@ public class X509Factory extends CertificateFactorySpi { * @throws CertificateException if failures occur while obtaining the DER * encoding for certificate data. */ - public static synchronized X509CertImpl intern(X509Certificate c) + public static X509CertImpl intern(X509Certificate c) throws CertificateException { if (c == null) { return null; @@ -168,18 +169,23 @@ public class X509Factory extends CertificateFactorySpi { } else { encoding = c.getEncoded(); } - X509CertImpl newC = getFromCache(certCache, encoding); - if (newC != null) { - return newC; + // First check under per-cache lock + X509CertImpl cached = getFromCache(certCache, encoding); + if (cached != null) { + return cached; } + + // Build outside lock + X509CertImpl newC; + byte[] enc; if (isImpl) { - newC = (X509CertImpl)c; + newC = (X509CertImpl) c; + enc = encoding; } else { newC = new X509CertImpl(encoding); - encoding = newC.getEncodedInternal(); + enc = newC.getEncodedInternal(); } - addToCache(certCache, encoding, newC); - return newC; + return addIfNotPresent(certCache, enc, newC); } /** @@ -192,7 +198,7 @@ public class X509Factory extends CertificateFactorySpi { * @throws CRLException if failures occur while obtaining the DER * encoding for CRL data. */ - public static synchronized X509CRLImpl intern(X509CRL c) + public static X509CRLImpl intern(X509CRL c) throws CRLException { if (c == null) { return null; @@ -204,39 +210,47 @@ public class X509Factory extends CertificateFactorySpi { } else { encoding = c.getEncoded(); } - X509CRLImpl newC = getFromCache(crlCache, encoding); - if (newC != null) { - return newC; + X509CRLImpl cached = getFromCache(crlCache, encoding); + if (cached != null) { + return cached; } + + X509CRLImpl newC; + byte[] enc; if (isImpl) { - newC = (X509CRLImpl)c; + newC = (X509CRLImpl) c; + enc = encoding; } else { newC = new X509CRLImpl(encoding); - encoding = newC.getEncodedInternal(); + enc = newC.getEncodedInternal(); } - addToCache(crlCache, encoding, newC); - return newC; + return addIfNotPresent(crlCache, enc, newC); } /** * Get the X509CertImpl or X509CRLImpl from the cache. */ - private static synchronized V getFromCache(Cache cache, - byte[] encoding) { - Object key = new Cache.EqualByteArray(encoding); - return cache.get(key); + private static V getFromCache(Cache cache, byte[] encoding) { + return cache.get(new Cache.EqualByteArray(encoding)); } /** * Add the X509CertImpl or X509CRLImpl to the cache. */ - private static synchronized void addToCache(Cache cache, - byte[] encoding, V value) { + private static V addIfNotPresent(Cache cache, byte[] encoding, V value) { if (encoding.length > ENC_MAX_LENGTH) { - return; + return value; } Object key = new Cache.EqualByteArray(encoding); - cache.put(key, value); + // Synchronize only to make the "check + insert" decision atomic. + synchronized (cache) { + V existing = cache.get(key); + if (existing != null) { + return existing; + } + cache.put(key, value); + return value; + } } /** @@ -389,13 +403,14 @@ public class X509Factory extends CertificateFactorySpi { try { byte[] encoding = readOneBlock(is); if (encoding != null) { - X509CRLImpl crl = getFromCache(crlCache, encoding); - if (crl != null) { - return crl; + X509CRLImpl cached = getFromCache(crlCache, encoding); + if (cached != null) { + return cached; } - crl = new X509CRLImpl(encoding); - addToCache(crlCache, crl.getEncodedInternal(), crl); - return crl; + // Build outside lock + X509CRLImpl crl = new X509CRLImpl(encoding); + byte[] enc = crl.getEncodedInternal(); + return addIfNotPresent(crlCache, enc, crl); } else { throw new IOException("Empty input"); } From d58fb1e290cb8a28a04900e132ae09002ae62937 Mon Sep 17 00:00:00 2001 From: Daisuke Yamazaki Date: Mon, 30 Mar 2026 12:58:07 +0000 Subject: [PATCH 097/359] 8374202: Simplify significand normalization in BigDecimal(double, MathContext) constructor Reviewed-by: rgiulietti --- src/java.base/share/classes/java/math/BigDecimal.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/java.base/share/classes/java/math/BigDecimal.java b/src/java.base/share/classes/java/math/BigDecimal.java index 14d81d30c3d..6e651b4fde2 100644 --- a/src/java.base/share/classes/java/math/BigDecimal.java +++ b/src/java.base/share/classes/java/math/BigDecimal.java @@ -1026,12 +1026,11 @@ public class BigDecimal extends Number implements Comparable { return; } // Normalize - while ((significand & 1) == 0) { // i.e., significand is even - significand >>= 1; - exponent++; - } - int scl = 0; + int nTrailingZeros = Long.numberOfTrailingZeros(significand); + significand >>= nTrailingZeros; + exponent += nTrailingZeros; // Calculate intVal and scale + int scl = 0; BigInteger rb; long compactVal = sign * significand; if (exponent == 0) { From 40e6069ff0558b1d5d0e520df7f23e59369867db Mon Sep 17 00:00:00 2001 From: Dusan Balek Date: Mon, 30 Mar 2026 13:06:06 +0000 Subject: [PATCH 098/359] =?UTF-8?q?8371873:=20javac:=20U+001A=20(SUB=20/?= =?UTF-8?q?=20control-Z)=20after=20the=20last=20token=20makes=20the=20rest?= =?UTF-8?q?=20of=20the=20file=20silently=20ignored,=20which=20contradicts?= =?UTF-8?q?=20JLS=20=C2=A73.3=E2=80=93=C2=A73.5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: jlahoda --- .../sun/tools/javac/parser/JavaTokenizer.java | 4 +- .../tools/javac/lexer/AsciiSubCharTest.java | 116 ++++++++++++++++++ 2 files changed, 118 insertions(+), 2 deletions(-) create mode 100644 test/langtools/tools/javac/lexer/AsciiSubCharTest.java diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java index babe372e7dc..55f2f76e358 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1000,7 +1000,7 @@ public class JavaTokenizer extends UnicodeReader { scanIdent(); } else if (digit(pos, 10) >= 0) { scanNumber(pos, 10); - } else if (is((char)EOI) || !isAvailable()) { + } else if (is((char)EOI) && position() + 1 == length() || !isAvailable()) { tk = TokenKind.EOF; pos = position(); } else { diff --git a/test/langtools/tools/javac/lexer/AsciiSubCharTest.java b/test/langtools/tools/javac/lexer/AsciiSubCharTest.java new file mode 100644 index 00000000000..0c96b744d72 --- /dev/null +++ b/test/langtools/tools/javac/lexer/AsciiSubCharTest.java @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8371873 + * @summary Check for proper handling of trailing ASCII SUB character + * @library /tools/lib + * @modules + * jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * @build toolbox.ToolBox toolbox.JavacTask + * @run junit AsciiSubCharTest + */ + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.*; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInfo; + +import toolbox.JavacTask; +import toolbox.Task; +import toolbox.ToolBox; + +public class AsciiSubCharTest { + + ToolBox tb = new ToolBox(); + Path base; + + @Test + public void testTrailingAsciiSubIsIgnored() throws Exception { + Path classes = base.resolve("classes"); + Files.createDirectories(classes); + new JavacTask(tb) + .options("-d", classes.toString()) + .sources(""" + public class Test { + void main(String... args) { IO.println("\u001A"); } + } + \u001A""") + .run() + .writeAll(); + } + + @Test + public void testMultipleTrailingAsciiSubAreReported() throws Exception { + Path classes = base.resolve("classes"); + Files.createDirectories(classes); + List out = new JavacTask(tb) + .options("-d", classes.toString(), "-XDrawDiagnostics", "-nowarn") + .sources(""" + public class Test { + void main(String... args) { IO.println("\u001A"); } + } + \u001A\u001A""") + .run(Task.Expect.FAIL) + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + tb.checkEqual(out, List.of( + "Test.java:4:1: compiler.err.illegal.char: \\u001a", + "Test.java:4:2: compiler.err.premature.eof", + "2 errors")); + } + + @Test + public void test8371873() throws Exception { + Path classes = base.resolve("classes"); + Files.createDirectories(classes); + List out = new JavacTask(tb) + .options("-d", classes.toString(), "-XDrawDiagnostics", "-nowarn") + .sources(""" + public class Test { + void main(String... args) { IO.println("\u001A"); } + } + \u001A\u0001""") + .run(Task.Expect.FAIL) + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + tb.checkEqual(out, List.of( + "Test.java:4:1: compiler.err.illegal.char: \\u001a", + "Test.java:4:2: compiler.err.illegal.char: \\u0001", + "Test.java:4:3: compiler.err.premature.eof", + "3 errors")); + } + + @BeforeEach + public void setUp(TestInfo info) { + base = Paths.get(".") + .resolve(info.getTestMethod() + .orElseThrow() + .getName()); + } +} From 2449dc2e807c3a4708a89e52bb16434d4a85d3d2 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Mon, 30 Mar 2026 13:06:40 +0000 Subject: [PATCH 099/359] 8377004: Java Launcher incorrectly allows inheriting a package-private main from another package Reviewed-by: jpai, alanb --- .../jdk/internal/misc/MethodFinder.java | 19 +- test/jdk/tools/launcher/InstanceMainTest.java | 224 +++++++++++++++++- test/jdk/tools/launcher/MethodFinderTest.java | 196 +++++++++++++++ 3 files changed, 423 insertions(+), 16 deletions(-) create mode 100644 test/jdk/tools/launcher/MethodFinderTest.java diff --git a/src/java.base/share/classes/jdk/internal/misc/MethodFinder.java b/src/java.base/share/classes/jdk/internal/misc/MethodFinder.java index 60895b8115a..1ee608f2caf 100644 --- a/src/java.base/share/classes/jdk/internal/misc/MethodFinder.java +++ b/src/java.base/share/classes/jdk/internal/misc/MethodFinder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,7 @@ package jdk.internal.misc; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.util.Objects; import jdk.internal.access.JavaLangAccess; import jdk.internal.access.SharedSecrets; @@ -88,21 +89,27 @@ public class MethodFinder { mainMethod = JLA.findMethod(cls, false, "main", String[].class); } - if (mainMethod == null || !isValidMainMethod(mainMethod)) { + if (mainMethod == null || !isValidMainMethod(cls, mainMethod)) { mainMethod = JLA.findMethod(cls, false, "main"); } - if (mainMethod == null || !isValidMainMethod(mainMethod)) { + if (mainMethod == null || !isValidMainMethod(cls, mainMethod)) { return null; } return mainMethod; } - private static boolean isValidMainMethod(Method mainMethodCandidate) { + private static boolean isValidMainMethod(Class initialClass, Method mainMethodCandidate) { return mainMethodCandidate.getReturnType() == void.class && - !Modifier.isPrivate(mainMethodCandidate.getModifiers()); - + !Modifier.isPrivate(mainMethodCandidate.getModifiers()) && + (Modifier.isPublic(mainMethodCandidate.getModifiers()) || + Modifier.isProtected(mainMethodCandidate.getModifiers()) || + isInSameRuntimePackage(initialClass, mainMethodCandidate.getDeclaringClass())); } + private static boolean isInSameRuntimePackage(Class c1, Class c2) { + return Objects.equals(c1.getPackageName(), c2.getPackageName()) && + c1.getClassLoader() == c2.getClassLoader(); + } } diff --git a/test/jdk/tools/launcher/InstanceMainTest.java b/test/jdk/tools/launcher/InstanceMainTest.java index 273d56a86bd..3a2f8fe90c1 100644 --- a/test/jdk/tools/launcher/InstanceMainTest.java +++ b/test/jdk/tools/launcher/InstanceMainTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * 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,11 +28,12 @@ import java.util.function.Consumer; /** * @test - * @bug 8329420 + * @bug 8329420 8377004 * @summary test execution priority and behavior of main methods * @run main/timeout=480 InstanceMainTest */ public class InstanceMainTest extends TestHelper { + private static String JAVA_VERSION = System.getProperty("java.specification.version"); private static final String[] SOURCES = new String[] { // static dominating with args @@ -227,11 +228,7 @@ public class InstanceMainTest extends TestHelper { private static void testExecutionOrder() throws Exception { for (TestCase testCase : EXECUTION_ORDER) { performTest(testCase.sourceCode, testCase.enablePreview(), tr -> { - if (!Objects.equals(testCase.expectedOutput, tr.testOutput)) { - throw new AssertionError("Unexpected output, " + - "expected: " + testCase.expectedOutput + - ", actual: " + tr.testOutput); - } + assertEquals(testCase.expectedOutput, tr.testOutput); }); } } @@ -350,20 +347,227 @@ public class InstanceMainTest extends TestHelper { private static void performTest(String source, boolean enablePreview, Consumer validator) throws Exception { Path mainClass = Path.of("MainClass.java"); Files.writeString(mainClass, source); - var version = System.getProperty("java.specification.version"); var previewRuntime = enablePreview ? "--enable-preview" : "-DtestNoPreview"; var previewCompile = enablePreview ? "--enable-preview" : "-XDtestNoPreview"; - var trSource = doExec(javaCmd, previewRuntime, "--source", version, "MainClass.java"); + var trSource = doExec(javaCmd, previewRuntime, "--source", JAVA_VERSION, "MainClass.java"); validator.accept(trSource); - compile(previewCompile, "--source", version, "MainClass.java"); + compile(previewCompile, "--source", JAVA_VERSION, "MainClass.java"); String cp = mainClass.toAbsolutePath().getParent().toString(); var trCompile = doExec(javaCmd, previewRuntime, "--class-path", cp, "MainClass"); validator.accept(trCompile); } + private static void testInheritance() throws Exception { + Path testInheritance = Path.of("testInheritance"); + Path src = testInheritance.resolve("src"); + Path classes = testInheritance.resolve("classes"); + Path mainClass = src.resolve("Main.java"); + Path libClass = src.resolve("p").resolve("Lib.java"); + + Files.createDirectories(libClass.getParent()); + + Files.writeString(mainClass, + """ + import p.Lib; + + public class Main extends Lib { + public void main() { + System.err.println("Main!"); + } + } + """); + + { + Files.writeString(libClass, + """ + package p; + public class Lib { + void main(String... args) { + System.err.println("Lib!"); + } + } + """); + compile("--release", JAVA_VERSION, "-d", classes.toString(), mainClass.toString(), libClass.toString()); + var tr = doExec(javaCmd, "--class-path", classes.toString(), "Main"); + assertEquals(List.of("Main!"), tr.testOutput); + } + + { + Files.writeString(libClass, + """ + package p; + public class Lib { + protected void main(String... args) { + System.err.println("Lib!"); + } + } + """); + compile("--release", JAVA_VERSION, "-d", classes.toString(), mainClass.toString(), libClass.toString()); + var tr = doExec(javaCmd, "--class-path", classes.toString(), "Main"); + assertEquals(List.of("Lib!"), tr.testOutput); + } + + { + Files.writeString(libClass, + """ + package p; + public class Lib { + public void main(String... args) { + System.err.println("Lib!"); + } + } + """); + compile("--release", JAVA_VERSION, "-d", classes.toString(), mainClass.toString(), libClass.toString()); + var tr = doExec(javaCmd, "--class-path", classes.toString(), "Main"); + assertEquals(List.of("Lib!"), tr.testOutput); + } + + { + Files.writeString(mainClass, + """ + package p; + + public class Main extends Lib { + public void main() { + System.err.println("Main!"); + } + } + """); + + Files.writeString(libClass, + """ + package p; + public class Lib { + void main(String... args) { + System.err.println("Lib!"); + } + } + """); + compile("--release", JAVA_VERSION, "-d", classes.toString(), mainClass.toString(), libClass.toString()); + var tr = doExec(javaCmd, "--class-path", classes.toString(), "p.Main"); + assertEquals(List.of("Lib!"), tr.testOutput); + } + + { + Files.writeString(mainClass, + """ + package p; + + public class Main implements Lib { + public void main() { + System.err.println("Main!"); + } + } + """); + + Files.writeString(libClass, + """ + package p; + public interface Lib { + public default void main(String... args) { + System.err.println("Lib!"); + } + } + """); + compile("--release", JAVA_VERSION, "-d", classes.toString(), mainClass.toString(), libClass.toString()); + var tr = doExec(javaCmd, "--class-path", classes.toString(), "p.Main"); + assertEquals(List.of("Lib!"), tr.testOutput); + } + + { + Files.writeString(mainClass, + """ + package p; + + public class Main implements Lib { + public void main() { + System.err.println("Main!"); + } + } + """); + + Files.writeString(libClass, + """ + package p; + public interface Lib { + public static void main(String... args) { + System.err.println("Lib!"); + } + } + """); + compile("--release", JAVA_VERSION, "-d", classes.toString(), mainClass.toString(), libClass.toString()); + var tr = doExec(javaCmd, "--class-path", classes.toString(), "p.Main"); + assertEquals(List.of("Main!"), tr.testOutput); + } + + { + Files.writeString(mainClass, + """ + package p; + + public class Main extends AbstractClass implements Lib { + } + abstract class AbstractClass { + public void main(String... args) { + System.err.println("Correct."); + } + } + """); + + Files.writeString(libClass, + """ + package p; + public interface Lib { + default void main(String... args) { + System.err.println("Incorrect!"); + } + } + """); + compile("--release", JAVA_VERSION, "-d", classes.toString(), mainClass.toString(), libClass.toString()); + var tr = doExec(javaCmd, "--class-path", classes.toString(), "p.Main"); + assertEquals(List.of("Correct."), tr.testOutput); + } + + { + Files.writeString(mainClass, + """ + package p; + + public class Main extends AbstractClass implements Lib { + } + abstract class AbstractClass { + public void main() { + System.err.println("Incorrect!"); + } + } + """); + + Files.writeString(libClass, + """ + package p; + public interface Lib { + default void main(String... args) { + System.err.println("Correct."); + } + } + """); + compile("--release", JAVA_VERSION, "-d", classes.toString(), mainClass.toString(), libClass.toString()); + var tr = doExec(javaCmd, "--class-path", classes.toString(), "p.Main"); + assertEquals(List.of("Correct."), tr.testOutput); + } + } + + private static void assertEquals(List expected, List actual) { + if (!Objects.equals(expected, actual)) { + throw new AssertionError("Unexpected output, " + + "expected: " + expected + + ", actual: " + actual); + } + } public static void main(String... args) throws Exception { testMethodOrder(); testExecutionOrder(); testExecutionErrors(); + testInheritance(); } } diff --git a/test/jdk/tools/launcher/MethodFinderTest.java b/test/jdk/tools/launcher/MethodFinderTest.java new file mode 100644 index 00000000000..6e1e68d8225 --- /dev/null +++ b/test/jdk/tools/launcher/MethodFinderTest.java @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8377004 + * @summary Whitebox test for MethodFinder + * @modules java.base/jdk.internal.misc + * jdk.compiler + * jdk.zipfs + * @run junit MethodFinderTest + */ + +import java.lang.reflect.Method; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.Files; +import java.nio.file.Path; +import jdk.internal.misc.MethodFinder; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +public class MethodFinderTest { + + private static final String JAVA_VERSION = System.getProperty("java.specification.version"); + + @Test + public void testDistinctClassLoaders() throws Exception { + Path base = Path.of("testDistinctClassLoaders"); + Path libSrc = base.resolve("libSrc"); + Path libClasses = base.resolve("libClasses"); + Path libJava = libSrc.resolve("p").resolve("Lib.java"); + + Files.createDirectories(libJava.getParent()); + + Files.writeString(libJava, + """ + package p; + public class Lib { + void main(String... args) { + System.err.println("Lib!"); + } + } + """); + + TestHelper.compile("--release", JAVA_VERSION, "-d", libClasses.toString(), libJava.toString()); + + Path mainSrc = base.resolve("mainSrc"); + Path mainClasses = base.resolve("mainClasses"); + Path mainJava = mainSrc.resolve("p").resolve("Main.java"); + + Files.createDirectories(mainJava.getParent()); + + Files.writeString(mainJava, + """ + package p; + + public class Main extends Lib { + public void main() { + System.err.println("Main!"); + } + } + """); + + TestHelper.compile("--release", JAVA_VERSION, "--class-path", libClasses.toString(), "-d", mainClasses.toString(), mainJava.toString()); + + { + ClassLoader cl = new URLClassLoader(new URL[] { + libClasses.toUri().toURL(), + mainClasses.toUri().toURL() + }); + Class mainClass = cl.loadClass("p.Main"); + Method mainMethod = MethodFinder.findMainMethod(mainClass); + + //p.Main and p.Lib are in the same runtime package: + assertEquals("p.Lib", mainMethod.getDeclaringClass().getName()); + } + + { + ClassLoader libCl = new URLClassLoader(new URL[] { + libClasses.toUri().toURL(), + }); + ClassLoader mainCl = new URLClassLoader(new URL[] { + mainClasses.toUri().toURL() + }, libCl); + Class mainClass = mainCl.loadClass("p.Main"); + Method mainMethod = MethodFinder.findMainMethod(mainClass); + + //p.Main and p.Lib are in the different runtime packages: + assertEquals("p.Main", mainMethod.getDeclaringClass().getName()); + } + } + + @Test + public void testWrongEquals() throws Exception { + Path base = Path.of("testDistinctClassLoaders"); + Path libSrc = base.resolve("libSrc"); + Path libClasses = base.resolve("libClasses"); + Path libJava = libSrc.resolve("p").resolve("Lib.java"); + + Files.createDirectories(libJava.getParent()); + + Files.writeString(libJava, + """ + package p; + public class Lib { + void main(String... args) { + System.err.println("Lib!"); + } + } + """); + + TestHelper.compile("--release", JAVA_VERSION, "-d", libClasses.toString(), libJava.toString()); + + Path mainSrc = base.resolve("mainSrc"); + Path mainClasses = base.resolve("mainClasses"); + Path mainJava = mainSrc.resolve("p").resolve("Main.java"); + + Files.createDirectories(mainJava.getParent()); + + Files.writeString(mainJava, + """ + package p; + + public class Main extends Lib { + public void main() { + System.err.println("Main!"); + } + } + """); + + TestHelper.compile("--release", JAVA_VERSION, "--class-path", libClasses.toString(), "-d", mainClasses.toString(), mainJava.toString()); + + { + ClassLoader cl = new URLClassLoader(new URL[] { + libClasses.toUri().toURL(), + mainClasses.toUri().toURL() + }); + Class mainClass = cl.loadClass("p.Main"); + Method mainMethod = MethodFinder.findMainMethod(mainClass); + + //p.Main and p.Lib are in the same runtime package: + assertEquals("p.Lib", mainMethod.getDeclaringClass().getName()); + } + + { + class WrongEquals extends URLClassLoader { + + public WrongEquals(URL[] urls) { + super(urls); + } + + public WrongEquals(URL[] urls, ClassLoader parent) { + super(urls, parent); + } + + @Override + public boolean equals(Object obj) { + return obj instanceof WrongEquals; + } + } + ClassLoader libCl = new WrongEquals(new URL[] { + libClasses.toUri().toURL(), + }); + ClassLoader mainCl = new WrongEquals(new URL[] { + mainClasses.toUri().toURL() + }, libCl); + Class mainClass = mainCl.loadClass("p.Main"); + Method mainMethod = MethodFinder.findMainMethod(mainClass); + + //p.Main and p.Lib are in the different runtime packages: + assertEquals("p.Main", mainMethod.getDeclaringClass().getName()); + } + } +} From 88d4f1f7ce9662155f35197157abe341ba13c673 Mon Sep 17 00:00:00 2001 From: Liam Miller-Cushon Date: Mon, 30 Mar 2026 13:09:18 +0000 Subject: [PATCH 100/359] 8380795: Consider omitting type annotations from method arguments in diagnostics Co-authored-by: Liz Looney Reviewed-by: vromero --- .../com/sun/tools/javac/code/Printer.java | 43 +++++++++-------- .../failures/MethodArguments.java | 47 +++++++++++++++++++ .../failures/MethodArguments.out | 8 ++++ .../typeAnnotations/failures/p/A.java | 30 ++++++++++++ .../typeAnnotations/failures/p/B.java | 41 ++++++++++++++++ 5 files changed, 150 insertions(+), 19 deletions(-) create mode 100644 test/langtools/tools/javac/annotations/typeAnnotations/failures/MethodArguments.java create mode 100644 test/langtools/tools/javac/annotations/typeAnnotations/failures/MethodArguments.out create mode 100644 test/langtools/tools/javac/annotations/typeAnnotations/failures/p/A.java create mode 100644 test/langtools/tools/javac/annotations/typeAnnotations/failures/p/B.java diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Printer.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Printer.java index d9781f19c5d..acd8a35a894 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Printer.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Printer.java @@ -53,6 +53,7 @@ public abstract class Printer implements Type.Visitor, Symbol.Vi List seenCaptured = List.nil(); static final int PRIME = 997; // largest prime less than 1000 + private boolean printingMethodArgs; protected Printer() { } @@ -195,6 +196,9 @@ public abstract class Printer implements Type.Visitor, Symbol.Vi } private String printAnnotations(Type t, boolean prefix) { + if (printingMethodArgs) { + return ""; + } StringBuilder sb = new StringBuilder(); List annos = t.getAnnotationMirrors(); if (!annos.isEmpty()) { @@ -337,27 +341,28 @@ public abstract class Printer implements Type.Visitor, Symbol.Vi * @return localized string representation */ protected String printMethodArgs(List args, boolean varArgs, Locale locale) { - if (!varArgs) { - return visitTypes(args, locale); - } else { - StringBuilder buf = new StringBuilder(); - while (args.tail.nonEmpty()) { - buf.append(visit(args.head, locale)); - args = args.tail; - buf.append(','); - } - if (args.head.hasTag(TypeTag.ARRAY)) { - buf.append(visit(((ArrayType) args.head).elemtype, locale)); - if (args.head.getAnnotationMirrors().nonEmpty()) { - buf.append(' '); - buf.append(args.head.getAnnotationMirrors()); - buf.append(' '); - } - buf.append("..."); + boolean prev = printingMethodArgs; + printingMethodArgs = true; + try { + if (!varArgs) { + return visitTypes(args, locale); } else { - buf.append(visit(args.head, locale)); + StringBuilder buf = new StringBuilder(); + while (args.tail.nonEmpty()) { + buf.append(visit(args.head, locale)); + args = args.tail; + buf.append(','); + } + if (args.head.hasTag(TypeTag.ARRAY)) { + buf.append(visit(((ArrayType) args.head).elemtype, locale)); + buf.append("..."); + } else { + buf.append(visit(args.head, locale)); + } + return buf.toString(); } - return buf.toString(); + } finally { + printingMethodArgs = prev; } } diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/failures/MethodArguments.java b/test/langtools/tools/javac/annotations/typeAnnotations/failures/MethodArguments.java new file mode 100644 index 00000000000..e539721855b --- /dev/null +++ b/test/langtools/tools/javac/annotations/typeAnnotations/failures/MethodArguments.java @@ -0,0 +1,47 @@ +/* + * @test /nodynamiccopyright/ + * @summary Omit type-use annotations from diagnostics + * @compile/fail/ref=MethodArguments.out -XDrawDiagnostics MethodArguments.java p/A.java p/B.java + */ + +import java.util.List; +import p.A; +import p.B; + +public final class MethodArguments { + public static void main(String[] args) { + // error non-static.cant.be.ref: + // non-static ... cannot be referenced from a static context + B.one("bar"); + + B b = new B(); + + // error ref.ambiguous: + // reference to ... is ambiguous + // ... + // both ... and ... match + b.one(null); + + // error report.access: + // ... has private access in ... + b.two("foo"); + // ... has protected access in ... + b.three("foo"); + + // error not.def.public.cant.access: + // ... is not public in ... cannot be accessed from outside package + b.four("foo"); + } + + void five(@A String s) { + } + + void five(@A String s) { + } + + void six(List<@A String> s) { + } + + void six(List<@A String> s) { + } +} diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/failures/MethodArguments.out b/test/langtools/tools/javac/annotations/typeAnnotations/failures/MethodArguments.out new file mode 100644 index 00000000000..b4ecee21403 --- /dev/null +++ b/test/langtools/tools/javac/annotations/typeAnnotations/failures/MethodArguments.out @@ -0,0 +1,8 @@ +MethodArguments.java:39:8: compiler.err.already.defined: kindname.method, five(java.lang.String), kindname.class, MethodArguments +MethodArguments.java:45:8: compiler.err.already.defined: kindname.method, six(java.util.List), kindname.class, MethodArguments +MethodArguments.java:15:6: compiler.err.non-static.cant.be.ref: kindname.method, one(java.lang.String) +MethodArguments.java:23:6: compiler.err.ref.ambiguous: one, kindname.method, one(java.lang.String), p.B, kindname.method, one(java.lang.Integer), p.B +MethodArguments.java:27:6: compiler.err.report.access: two(java.lang.String), private, p.B +MethodArguments.java:29:6: compiler.err.report.access: three(java.lang.String), protected, p.B +MethodArguments.java:33:6: compiler.err.not.def.public.cant.access: four(java.lang.String), p.B +7 errors diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/failures/p/A.java b/test/langtools/tools/javac/annotations/typeAnnotations/failures/p/A.java new file mode 100644 index 00000000000..9e3bb15dab5 --- /dev/null +++ b/test/langtools/tools/javac/annotations/typeAnnotations/failures/p/A.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2026, Google LLC. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Target; + +@Target(ElementType.TYPE_USE) +public @interface A {} diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/failures/p/B.java b/test/langtools/tools/javac/annotations/typeAnnotations/failures/p/B.java new file mode 100644 index 00000000000..4dfe16b312d --- /dev/null +++ b/test/langtools/tools/javac/annotations/typeAnnotations/failures/p/B.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2026, Google LLC. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p; + +public class B { + public void one(@A String s) { + } + + public void one(@A Integer i) { + } + + private void two(@A String s) { + } + + protected void three(@A String s) { + } + + void four(@A String s) { + } +} From 783f8f1adc4ea3ef7fd4c5ca5473aad76dfc7ed1 Mon Sep 17 00:00:00 2001 From: Christian Hagedorn Date: Mon, 30 Mar 2026 14:06:05 +0000 Subject: [PATCH 101/359] 8381320: Problemlist compiler/vectorapi/TestVectorReallocation.java Reviewed-by: thartmann --- test/hotspot/jtreg/ProblemList.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index 3b871d9f4b6..7580ce4d165 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -56,6 +56,7 @@ compiler/c2/irTests/TestDuplicateBackedge.java 8318904 generic-all compiler/codecache/jmx/PoolsIndependenceTest.java 8264632 macosx-all +compiler/vectorapi/TestVectorReallocation.java 8381315 generic-x64 compiler/vectorapi/reshape/TestVectorReinterpret.java 8320897,8348519 aix-ppc64,linux-ppc64le,linux-s390x compiler/vectorapi/VectorRebracket128Test.java 8330538 generic-all From ab83702428d8d73335aa57f2d6a27797b8afa687 Mon Sep 17 00:00:00 2001 From: Matias Saavedra Silva Date: Mon, 30 Mar 2026 16:43:00 +0000 Subject: [PATCH 102/359] 8366020: Assert that java code is not executed during the AOT assembly phase Co-authored-by: Ioi Lam Reviewed-by: kvn, coleenp, iklam --- src/hotspot/share/cds/aotClassInitializer.cpp | 33 +++++++++++++++++++ test/lib/jdk/test/lib/cds/CDSTestUtils.java | 2 +- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/cds/aotClassInitializer.cpp b/src/hotspot/share/cds/aotClassInitializer.cpp index 41fdeb537cc..9ef96282aeb 100644 --- a/src/hotspot/share/cds/aotClassInitializer.cpp +++ b/src/hotspot/share/cds/aotClassInitializer.cpp @@ -59,6 +59,39 @@ bool AOTClassInitializer::can_archive_initialized_mirror(InstanceKlass* ik) { return false; } +#ifdef ASSERT + // If code in ik is executed, then ik must be in the state of being_initialized or + // fully_initialized. + // + // Check that no user code is executed during the assembly phase. Otherwise the user + // code may introduce undesirable environment dependencies into the heap image. + // If any of these two flags are set, we allow user code to be executed + // in the assembly phase. Note that these flags are strictly for the purpose + // of testing HotSpot and are not available in product builds. + if (AOTInitTestClass == nullptr && ArchiveHeapTestClass == nullptr) { + if (ik->defined_by_boot_loader()) { + // We allow boot classes to be AOT-initialized, except for classes from + // -Xbootclasspath (cp index >= 1) be AOT-initialized, as such classes may be + // provided by the user application. + assert(ik->shared_classpath_index() <= 0, + "only boot classed loaded from the modules image can be AOT-initialized"); + } else { + assert(ik->defined_by_platform_loader() || ik->defined_by_app_loader(), + "cannot AOT-initialized classed loaded by other loaders"); + + // Hidden classes from platform/app loaders need to be AOT-initialized to + // support AOT-linking of lambdas. These hidden classes are generated by the + // VM and do not contain user code. + if (!ik->is_hidden()) { + // OK: ik is an interface used by a lambda. When AOT-linking lambdas, we only + // support interfaces that are not interface_needs_clinit_execution_as_super(). + // See AOTConstantPoolResolver::check_lambda_metafactory_signature(). + assert(ik->is_interface() && !ik->interface_needs_clinit_execution_as_super(), "cannot execute Java code in assembly phase"); + } + } + } +#endif // ASSERT + // About "static field that may hold a different value" errors: // // Automatic selection for aot-inited classes diff --git a/test/lib/jdk/test/lib/cds/CDSTestUtils.java b/test/lib/jdk/test/lib/cds/CDSTestUtils.java index 1c51a693907..59e4a1bbbde 100644 --- a/test/lib/jdk/test/lib/cds/CDSTestUtils.java +++ b/test/lib/jdk/test/lib/cds/CDSTestUtils.java @@ -324,7 +324,7 @@ public class CDSTestUtils { public static void checkCommonExecExceptions(OutputAnalyzer output, Exception e) throws Exception { if (output.getStdout().contains("https://bugreport.java.com/bugreport/crash.jsp")) { - throw new RuntimeException("Hotspot crashed"); + throw new RuntimeException(getCrashMessage(output.getStdout())); } if (output.getStdout().contains("TEST FAILED")) { throw new RuntimeException("Test Failed"); From 73501b274faef43829ea8e2ec89706c72fcd2e68 Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Mon, 30 Mar 2026 16:49:09 +0000 Subject: [PATCH 103/359] 8380848: jdk/nio/zipfs/ZipFSTester.java fails after JDK-8378884 Reviewed-by: lancea, syan --- test/jdk/jdk/nio/zipfs/ZipFSTester.java | 46 +++++++++++++++---------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/test/jdk/jdk/nio/zipfs/ZipFSTester.java b/test/jdk/jdk/nio/zipfs/ZipFSTester.java index 84135fd0d7d..9d70350272f 100644 --- a/test/jdk/jdk/nio/zipfs/ZipFSTester.java +++ b/test/jdk/jdk/nio/zipfs/ZipFSTester.java @@ -21,6 +21,7 @@ * questions. */ +import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -97,14 +98,21 @@ public class ZipFSTester { // create JAR file for test, actual contents don't matter static Path jarFile; + static String[] jarContents = new String[]{ + "META-INF/MANIFEST.MF", + "dir1/foo", + "dir2/bar", + "dir1/dir3/fooo" + }; @BeforeAll static void setup() throws Exception { - jarFile = Utils.createJarFile("tester.jar", - "META-INF/MANIFEST.MF", - "dir1/foo", - "dir2/bar", - "dir1/dir3/fooo"); + jarFile = Utils.createJarFile("tester.jar", jarContents); + } + + @AfterAll + static void cleanup() throws IOException { + Files.deleteIfExists(jarFile); } @Test @@ -583,19 +591,18 @@ public class ZipFSTester { // test file stamp @Test void testTime() throws Exception { + var jar = Utils.createJarFile(System.currentTimeMillis() + ".jar", jarContents); BasicFileAttributes attrs = Files - .getFileAttributeView(jarFile, BasicFileAttributeView.class) + .getFileAttributeView(jar, BasicFileAttributeView.class) .readAttributes(); // create a new filesystem, copy this file into it - Map env = new HashMap(); - env.put("create", "true"); Path fsPath = getTempPath(); - try (FileSystem fs = newZipFileSystem(fsPath, env)) { + try (FileSystem fs = FileSystems.newFileSystem(fsPath, Map.of("create", "true"))) { System.out.println("test copy with timestamps..."); // copyin - Path dst = getPathWithParents(fs, "me"); - Files.copy(jarFile, dst, COPY_ATTRIBUTES); - checkEqual(jarFile, dst); + Path dst = fs.getPath("me"); + Files.copy(jar, dst, COPY_ATTRIBUTES); + checkEqual(jar, dst); System.out.println("mtime: " + attrs.lastModifiedTime()); System.out.println("ctime: " + attrs.creationTime()); System.out.println("atime: " + attrs.lastAccessTime()); @@ -608,14 +615,15 @@ public class ZipFSTester { System.out.println("atime: " + dstAttrs.lastAccessTime()); // 1-second granularity - assertFalse(attrs.lastModifiedTime().to(TimeUnit.SECONDS) != - dstAttrs.lastModifiedTime().to(TimeUnit.SECONDS) || - attrs.lastAccessTime().to(TimeUnit.SECONDS) != - dstAttrs.lastAccessTime().to(TimeUnit.SECONDS) || - attrs.creationTime().to(TimeUnit.SECONDS) != - dstAttrs.creationTime().to(TimeUnit.SECONDS), "Timestamp Copy Failed!"); + assertEquals(attrs.lastModifiedTime().to(TimeUnit.SECONDS), + dstAttrs.lastModifiedTime().to(TimeUnit.SECONDS), "Last modified time incorrect"); + assertEquals(attrs.lastAccessTime().to(TimeUnit.SECONDS), + dstAttrs.lastAccessTime().to(TimeUnit.SECONDS), "Last access time incorrect"); + assertEquals(attrs.creationTime().to(TimeUnit.SECONDS), + dstAttrs.creationTime().to(TimeUnit.SECONDS), "Last creation time incorrect"); } finally { - Files.delete(fsPath); + Files.deleteIfExists(fsPath); + Files.deleteIfExists(jar); } } From 0c4156d599868992cce34605bc5bd1b9a072b502 Mon Sep 17 00:00:00 2001 From: Alexander Matveev Date: Mon, 30 Mar 2026 22:02:48 +0000 Subject: [PATCH 104/359] 8380634: [macos] Remove macOS version restrictions on start with zero and limit to three components Reviewed-by: asemenyuk --- .../jpackage/internal/CFBundleVersion.java | 25 +++++-------------- .../resources/MacResources.properties | 4 +-- .../resources/MacResources_de.properties | 2 -- .../resources/MacResources_ja.properties | 2 -- .../resources/MacResources_zh_CN.properties | 2 -- .../internal/PlatformVersionTest.java | 10 ++------ .../cli/OptionsValidationFailTest.excludes | 2 -- .../tools/jpackage/share/AppVersionTest.java | 22 +++++++++++++--- test/jdk/tools/jpackage/share/ErrorTest.java | 6 ----- 9 files changed, 27 insertions(+), 48 deletions(-) diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/CFBundleVersion.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/CFBundleVersion.java index 17c310dbe56..30b79b563da 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/CFBundleVersion.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/CFBundleVersion.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 @@ */ package jdk.jpackage.internal; -import java.math.BigInteger; import jdk.jpackage.internal.model.DottedVersion; @@ -33,25 +32,13 @@ final class CFBundleVersion { * Parse the given string as OSX CFBundleVersion. * CFBundleVersion (String - iOS, OS X) specifies the build version number of * the bundle, which identifies an iteration (released or unreleased) of the - * bundle. The build version number should be a string comprised of at most three - * non-negative, period-separated integers with the first integer being greater - * than zero. + * bundle. The build version number should be a string comprised of non-negative, + * period-separated integers. macOS will ignore anything after 3 components, but + * it acceptable to have more then 3 components. + * * @throws IllegalArgumentException */ static DottedVersion of(String value) { - DottedVersion ver = DottedVersion.greedy(value); - - BigInteger[] components = ver.getComponents(); - if (components.length > 3) { - throw new IllegalArgumentException(I18N.getString( - "message.version-string-too-many-components")); - } - - if (BigInteger.ZERO.equals(components[0])) { - throw new IllegalArgumentException(I18N.getString( - "message.version-string-first-number-not-zero")); - } - - return ver; + return DottedVersion.greedy(value); } } 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 2ed1f740805..f181bbf79af 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 @@ -23,7 +23,7 @@ # questions. # # -error.invalid-cfbundle-version.advice=Set a compatible 'app-version' value. Valid versions are one to three integers separated by dots. +error.invalid-cfbundle-version.advice=Set a compatible 'app-version' value. Valid version is a string comprised of non-negative, period-separated integers. error.certificate.outside-validity-period=The certificate "{0}" is outside its validity period error.cert.not.found=No certificate found matching [{0}] using keychain [{1}] error.multiple.certs.found=Multiple certificates matching name [{0}] found in keychain [{1}] @@ -56,8 +56,6 @@ resource.launchd-plist-file=launchd plist file message.bundle-name-too-long-warning={0} is set to ''{1}'', which is longer than 16 characters. For a better Mac experience consider shortening it. message.preparing-info-plist=Preparing Info.plist: {0}. message.icon-not-icns= The specified icon "{0}" is not an ICNS file and will not be used. The default icon will be used in it's place. -message.version-string-too-many-components='app-version' may have between 1 and 3 numbers: 1, 1.2, 1.2.3. -message.version-string-first-number-not-zero=The first number in an app-version cannot be zero or negative. message.keychain.error=Unable to get keychain list. message.derived-bundle-identifier=Derived bundle identifier: {0} message.preparing-dmg-setup=Preparing dmg setup: {0}. diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_de.properties b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_de.properties index 367f3216f85..02e8c029ec6 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_de.properties +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_de.properties @@ -54,8 +54,6 @@ resource.launchd-plist-file=launchd-PLIST-Datei message.bundle-name-too-long-warning={0} ist auf "{1}" gesetzt. Dies ist länger als 16 Zeichen. Kürzen Sie den Wert, um die Mac-Nutzungserfahrung zu verbessern. message.preparing-info-plist=Info.plist wird vorbereitet: {0}. message.icon-not-icns= Das angegebene Symbol "{0}" ist keine ICNS-Datei und wird nicht verwendet. Stattdessen wird das Standardsymbol verwendet. -message.version-string-too-many-components="app-version" darf ein bis drei Zahlen aufweisen: 1, 1.2, 1.2.3. -message.version-string-first-number-not-zero=Die erste Zahl in app-version darf nicht null oder negativ sein. message.keychain.error=Schlüsselbundliste kann nicht abgerufen werden. message.invalid-identifier=Ungültige Mac-Bundle-ID [{0}]. message.invalid-identifier.advice=Geben Sie die ID mit "--mac-package-identifier" an. diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_ja.properties b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_ja.properties index ba2497d30dd..c9de142d796 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_ja.properties +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_ja.properties @@ -54,8 +54,6 @@ resource.launchd-plist-file=launchd plistファイル message.bundle-name-too-long-warning={0}が16文字を超える''{1}''に設定されています。Macでの操作性をより良くするために短くすることを検討してください。 message.preparing-info-plist=Info.plistを準備しています: {0}。 message.icon-not-icns= 指定したアイコン"{0}"はICNSファイルではなく、使用されません。デフォルト・アイコンがその位置に使用されます。 -message.version-string-too-many-components='app-version'には、1、1.2、1.2.3など1から3の数字を使用できます。 -message.version-string-first-number-not-zero=pp-versionの最初の数字は、ゼロまたは負の値にできません。 message.keychain.error=キーチェーン・リストを取得できません。 message.invalid-identifier=macバンドル識別子[{0}]が無効です。 message.invalid-identifier.advice="--mac-package-identifier"で識別子を指定してください。 diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_zh_CN.properties b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_zh_CN.properties index f855a31caae..9a925859af5 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_zh_CN.properties +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_zh_CN.properties @@ -54,8 +54,6 @@ resource.launchd-plist-file=launchd plist 文件 message.bundle-name-too-long-warning={0}已设置为 ''{1}'', 其长度超过了 16 个字符。为了获得更好的 Mac 体验, 请考虑将其缩短。 message.preparing-info-plist=正在准备 Info.plist: {0}。 message.icon-not-icns= 指定的图标 "{0}" 不是 ICNS 文件, 不会使用。将使用默认图标代替。 -message.version-string-too-many-components='app-version' 可以包含 1 到 3 个数字:1、1.2、1.2.3。 -message.version-string-first-number-not-zero=app-version 中的第一个数字不能为零或负数。 message.keychain.error=无法获取密钥链列表。 message.invalid-identifier=mac 包标识符 [{0}] 无效。 message.invalid-identifier.advice=请使用 "--mac-package-identifier" 指定标识符。 diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/PlatformVersionTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/PlatformVersionTest.java index 5e3e27caced..60933214c59 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/PlatformVersionTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/PlatformVersionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * 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,17 +62,11 @@ public class PlatformVersionTest { } @ParameterizedTest - @ValueSource(strings = {"1", "1.2", "1.2.3"}) + @ValueSource(strings = {"0", "0.1", "1", "1.2", "1.2.3", "1.2.3.4"}) public void testValidCfBundleVersion(String version) { testImpl(PlatformVersion.MAC_CFBUNDLE_VERSION_CLASS, version, true); } - @ParameterizedTest - @ValueSource(strings = {"0", "0.1", "1.2.3.4"}) - public void testInvalidCfBundleVersion(String version) { - testImpl(PlatformVersion.MAC_CFBUNDLE_VERSION_CLASS, version, false); - } - private static void testImpl(PlatformVersion parser, String version, boolean valid) { assumeTrue(parser.parser != null); if (valid) { diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/OptionsValidationFailTest.excludes b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/OptionsValidationFailTest.excludes index a7a65402b9c..52da229afa7 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/OptionsValidationFailTest.excludes +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/OptionsValidationFailTest.excludes @@ -1,5 +1,3 @@ -ErrorTest.test(IMAGE; app-desc=Hello; args-add=[--app-version, 0.2]; errors=[message.error-header+[message.version-string-first-number-not-zero], message.advice-header+[error.invalid-cfbundle-version.advice]]) -ErrorTest.test(IMAGE; app-desc=Hello; args-add=[--app-version, 1.2.3.4]; errors=[message.error-header+[message.version-string-too-many-components], message.advice-header+[error.invalid-cfbundle-version.advice]]) ErrorTest.test(IMAGE; app-desc=Hello; args-add=[--app-version, 1.]; errors=[message.error-header+[error.version-string-zero-length-component, 1.], message.advice-header+[error.invalid-cfbundle-version.advice]]) ErrorTest.test(IMAGE; app-desc=Hello; args-add=[--app-version, 1.]; errors=[message.error-header+[error.version-string-zero-length-component, 1.]]) ErrorTest.test(IMAGE; app-desc=Hello; args-add=[--app-version, 1.b.3]; errors=[message.error-header+[error.version-string-invalid-component, 1.b.3, b.3], message.advice-header+[error.invalid-cfbundle-version.advice]]) diff --git a/test/jdk/tools/jpackage/share/AppVersionTest.java b/test/jdk/tools/jpackage/share/AppVersionTest.java index 598ee1551b3..2dab3c7387b 100644 --- a/test/jdk/tools/jpackage/share/AppVersionTest.java +++ b/test/jdk/tools/jpackage/share/AppVersionTest.java @@ -47,6 +47,7 @@ import java.util.Set; import java.util.function.Consumer; import java.util.function.Predicate; import jdk.internal.util.OperatingSystem; +import jdk.jpackage.internal.model.DottedVersion; import jdk.jpackage.internal.util.MacBundle; import jdk.jpackage.internal.util.RuntimeReleaseFile; import jdk.jpackage.internal.util.Slot; @@ -173,6 +174,16 @@ public final class AppVersionTest { AppTestSpec.create(builder, testCases::add); } + if (TKit.isOSX()) { + // Ensure "0.1" is a valid version on macOS. + AppTestSpec.create("Hello", TestSpec.build() + .versionFromCmdline("0.1"), testCases::add); + + // Ensure "1.2.3.4.5" is a valid version on macOS. + AppTestSpec.create("Hello", TestSpec.build() + .versionFromCmdline("1.2.3.4.5"), testCases::add); + } + return testCases.stream().map(v -> { return new Object[] {v}; }).toList(); @@ -484,10 +495,13 @@ public final class AppVersionTest { : cmd.pathToUnpackedPackageFile(cmd.appInstallationDirectory()); var plist = MacHelper.readPListFromAppImage(bundleRoot); var expectedVersion = expected.get(cmd.packageType()).version(); - for (var prop : List.of("CFBundleVersion", "CFBundleShortVersionString")) { - TKit.assertEquals(expectedVersion, plist.queryValue(prop), - String.format("Check the value of '%s' property in [%s] bundle", prop, bundleRoot)); - } + TKit.assertEquals(expectedVersion, plist.queryValue("CFBundleVersion"), + String.format("Check the value of '%s' property in [%s] bundle", + "CFBundleVersion", bundleRoot)); + TKit.assertEquals(DottedVersion.lazy(expectedVersion).trim(3).toComponentsString(), + plist.queryValue("CFBundleShortVersionString"), + String.format("Check the value of '%s' property in [%s] bundle", + "CFBundleShortVersionString", bundleRoot)); }); } } diff --git a/test/jdk/tools/jpackage/share/ErrorTest.java b/test/jdk/tools/jpackage/share/ErrorTest.java index ed5865024fa..ba0f5663d45 100644 --- a/test/jdk/tools/jpackage/share/ErrorTest.java +++ b/test/jdk/tools/jpackage/share/ErrorTest.java @@ -1002,12 +1002,6 @@ public final class ErrorTest { final List testCases = new ArrayList<>(); testCases.addAll(Stream.of( - testSpec().addArgs("--app-version", "0.2") - .error("message.version-string-first-number-not-zero") - .advice("error.invalid-cfbundle-version.advice"), - testSpec().addArgs("--app-version", "1.2.3.4") - .error("message.version-string-too-many-components") - .advice("error.invalid-cfbundle-version.advice"), testSpec().invalidTypeArg("--mac-installer-sign-identity", "foo"), testSpec().type(PackageType.MAC_DMG).invalidTypeArg("--mac-installer-sign-identity", "foo"), testSpec().invalidTypeArg("--mac-dmg-content", "foo"), From 6350c3641e2a6cbb15aaaf2f62ebd2007eca3954 Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Mon, 30 Mar 2026 23:14:13 +0000 Subject: [PATCH 105/359] 8377703: Assert that all AOT heap objects have valid classes Reviewed-by: kvn, eosterlund --- src/hotspot/share/cds/archiveUtils.hpp | 38 +++++++++++++++++++++++++- src/hotspot/share/cds/heapShared.cpp | 25 +++++++++++++++++ 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/cds/archiveUtils.hpp b/src/hotspot/share/cds/archiveUtils.hpp index 84ad8e6bdf3..42455adedd0 100644 --- a/src/hotspot/share/cds/archiveUtils.hpp +++ b/src/hotspot/share/cds/archiveUtils.hpp @@ -36,6 +36,8 @@ #include "runtime/semaphore.hpp" #include "utilities/bitMap.hpp" #include "utilities/exceptions.hpp" +#include "utilities/growableArray.hpp" +#include "utilities/hashTable.hpp" #include "utilities/macros.hpp" class BootstrapInfo; @@ -44,7 +46,6 @@ class ReservedSpace; class VirtualSpace; template class Array; -template class GrowableArray; // ArchivePtrMarker is used to mark the location of pointers embedded in a CDS archive. E.g., when an // InstanceKlass k is dumped, we mark the location of the k->_name pointer by effectively calling @@ -401,4 +402,39 @@ public: void run_task(ArchiveWorkerTask* task); }; +// A utility class for writing an array of unique items into the +// AOT cache. For determinism, the order of the array is the same +// as calls to add(). I.e., if items are added in the order +// of A, B, A, C, B, D, then the array will be written as {A, B, C, D} +template +class ArchivableTable : public AnyObj { + using Table = HashTable; + Table* _seen_items; + GrowableArray* _ordered_array; +public: + ArchivableTable() { + _seen_items = new (mtClassShared)Table(); + _ordered_array = new (mtClassShared)GrowableArray(128, mtClassShared); + } + + ~ArchivableTable() { + delete _seen_items; + delete _ordered_array; + } + + void add(T t) { + bool created; + _seen_items->put_if_absent(t, &created); + if (created) { + _ordered_array->append(t); + } + } + + Array* write_ordered_array() { + return ArchiveUtils::archive_array(_ordered_array); + } +}; + +using ArchivableKlassTable = ArchivableTable; + #endif // SHARE_CDS_ARCHIVEUTILS_HPP diff --git a/src/hotspot/share/cds/heapShared.cpp b/src/hotspot/share/cds/heapShared.cpp index 3d10e7e1f88..f721b4b370c 100644 --- a/src/hotspot/share/cds/heapShared.cpp +++ b/src/hotspot/share/cds/heapShared.cpp @@ -112,6 +112,11 @@ static Klass* _test_class = nullptr; static const ArchivedKlassSubGraphInfoRecord* _test_class_record = nullptr; #endif +#ifdef ASSERT +// All classes that have at least one instance in the cached heap. +static ArchivableKlassTable* _dumptime_classes_with_cached_oops = nullptr; +static Array* _runtime_classes_with_cached_oops = nullptr; +#endif // // If you add new entries to the following tables, you should know what you're doing! @@ -391,6 +396,21 @@ void HeapShared::initialize_streaming() { } void HeapShared::enable_gc() { +#ifdef ASSERT + // At this point, a GC may start and will be able to see some or all + // of the cached oops. The class of each oop seen by the GC must have + // already been loaded. One function with such a requirement is + // ClaimMetadataVisitingOopIterateClosure::do_klass(). + if (is_archived_heap_in_use()) { + Array* klasses = _runtime_classes_with_cached_oops; + + for (int i = 0; i < klasses->length(); i++) { + assert(klasses->at(i)->class_loader_data() != nullptr, + "class of cached oop must have been loaded"); + } + } +#endif + if (AOTStreamedHeapLoader::is_in_use()) { AOTStreamedHeapLoader::enable_gc(); } @@ -567,6 +587,7 @@ bool HeapShared::archive_object(oop obj, oop referrer, KlassSubGraphInfo* subgra AOTArtifactFinder::add_cached_class(obj->klass()); AOTOopChecker::check(obj); // Make sure contents of this oop are safe. count_allocation(obj->size()); + DEBUG_ONLY(_dumptime_classes_with_cached_oops->add(obj->klass())); if (HeapShared::is_writing_streaming_mode()) { AOTStreamedHeapWriter::add_source_obj(obj); @@ -686,6 +707,7 @@ void HeapShared::init_dumping() { _scratch_objects_table = new (mtClass)MetaspaceObjToOopHandleTable(); _pending_roots = new GrowableArrayCHeap(500); _pending_roots->append(nullptr); // root index 0 represents a null oop + DEBUG_ONLY(_dumptime_classes_with_cached_oops = new (mtClassShared)ArchivableKlassTable()); } void HeapShared::init_scratch_objects_for_basic_type_mirrors(TRAPS) { @@ -967,6 +989,8 @@ void HeapShared::write_heap(AOTMappedHeapInfo* mapped_heap_info, AOTStreamedHeap ArchiveBuilder::OtherROAllocMark mark; write_subgraph_info_table(); + DEBUG_ONLY(_runtime_classes_with_cached_oops = _dumptime_classes_with_cached_oops->write_ordered_array()); + delete _pending_roots; _pending_roots = nullptr; @@ -1278,6 +1302,7 @@ void HeapShared::serialize_tables(SerializeClosure* soc) { _run_time_subgraph_info_table.serialize_header(soc); soc->do_ptr(&_run_time_special_subgraph); + DEBUG_ONLY(soc->do_ptr(&_runtime_classes_with_cached_oops)); } static void verify_the_heap(Klass* k, const char* which) { From 6649eee753760d192ee6be10d0e7b0ca09179bff Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 31 Mar 2026 00:03:46 +0000 Subject: [PATCH 106/359] 8381367: [lworld] tools/jpackage/share/AppVersionTest.java timed out while reporting errors Reviewed-by: almatvee --- .../tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java | 6 +++--- test/jdk/tools/jpackage/share/AppVersionTest.java | 5 +---- 2 files changed, 4 insertions(+), 7 deletions(-) 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 1372058d440..4e0d57631b9 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java @@ -557,10 +557,10 @@ public final class MacHelper { final var unpackedRuntimeBundleDir = runtimeBundleWorkDir.resolve("unpacked"); - // Preferably create a DMG bundle, fallback to PKG if DMG packaging is disabled. + // Preferably create a PKG bundle, fallback to DMG if PKG packaging is disabled. new PackageTest().forTypes(Stream.of( - PackageType.MAC_DMG, - PackageType.MAC_PKG + PackageType.MAC_PKG, + PackageType.MAC_DMG ).filter(PackageType::isEnabled).findFirst().orElseThrow(PackageType::throwSkippedExceptionIfNativePackagingUnavailable)) .addInitializer(cmd -> { cmd.useToolProvider(true) diff --git a/test/jdk/tools/jpackage/share/AppVersionTest.java b/test/jdk/tools/jpackage/share/AppVersionTest.java index 2dab3c7387b..2ef7f95398e 100644 --- a/test/jdk/tools/jpackage/share/AppVersionTest.java +++ b/test/jdk/tools/jpackage/share/AppVersionTest.java @@ -71,7 +71,7 @@ import jdk.jpackage.test.TKit; * @library /test/jdk/tools/jpackage/helpers * @build jdk.jpackage.test.* * @compile -Xlint:all -Werror AppVersionTest.java - * @run main/othervm/timeout=1440 -Xmx512m jdk.jpackage.test.Main + * @run main/othervm/timeout=2880 -Xmx512m jdk.jpackage.test.Main * --jpt-run=AppVersionTest */ @@ -1003,9 +1003,6 @@ public final class AppVersionTest { }); yield MacBundle.fromPath(predefinedRuntimeDir).orElseThrow().homeDir(); } - default -> { - throw new AssertionError(); - } }; releaseFileVersion.ifPresent(ver -> { From 2eec71a500e8df02f5abc7d1e65bdf06da5a2efc Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Tue, 31 Mar 2026 01:19:46 +0000 Subject: [PATCH 107/359] 8380422: Fix Formatting issues missed in JDK-8380125 Reviewed-by: dnguyen, serb --- .../classes/javax/swing/AbstractButton.java | 2 +- .../swing/ActionPropertyChangeListener.java | 2 +- .../classes/javax/swing/AncestorNotifier.java | 2 +- .../share/classes/javax/swing/ArrayTable.java | 8 +- .../share/classes/javax/swing/JComboBox.java | 4 +- .../share/classes/javax/swing/JList.java | 2 +- .../share/classes/javax/swing/JTextField.java | 4 +- .../share/classes/javax/swing/JTree.java | 2 +- .../classes/javax/swing/KeyboardManager.java | 2 +- .../share/classes/javax/swing/UIDefaults.java | 4 +- .../swing/plaf/basic/BasicComboPopup.java | 76 +++++++++---------- .../javax/swing/plaf/basic/BasicListUI.java | 2 +- .../swing/plaf/basic/BasicMenuBarUI.java | 8 +- .../swing/plaf/basic/BasicPopupMenuUI.java | 2 +- .../swing/plaf/basic/BasicSpinnerUI.java | 2 +- .../swing/plaf/basic/BasicTabbedPaneUI.java | 26 +++---- .../swing/plaf/basic/BasicToolBarUI.java | 2 +- .../javax/swing/plaf/basic/BasicTreeUI.java | 2 +- .../plaf/nimbus/AbstractRegionPainter.java | 2 +- .../swing/plaf/nimbus/NimbusLookAndFeel.java | 2 +- .../swing/plaf/nimbus/SynthPainterImpl.java | 2 +- .../swing/plaf/synth/SynthComboBoxUI.java | 2 +- .../swing/plaf/synth/SynthScrollPaneUI.java | 2 +- .../classes/javax/swing/text/TextAction.java | 2 +- .../swing/tree/DefaultTreeCellEditor.java | 2 +- 25 files changed, 83 insertions(+), 83 deletions(-) diff --git a/src/java.desktop/share/classes/javax/swing/AbstractButton.java b/src/java.desktop/share/classes/javax/swing/AbstractButton.java index a1961acce29..ad5f0eba3de 100644 --- a/src/java.desktop/share/classes/javax/swing/AbstractButton.java +++ b/src/java.desktop/share/classes/javax/swing/AbstractButton.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/java.desktop/share/classes/javax/swing/ActionPropertyChangeListener.java b/src/java.desktop/share/classes/javax/swing/ActionPropertyChangeListener.java index 19b9152a1b5..7d33e936b7b 100644 --- a/src/java.desktop/share/classes/javax/swing/ActionPropertyChangeListener.java +++ b/src/java.desktop/share/classes/javax/swing/ActionPropertyChangeListener.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/java.desktop/share/classes/javax/swing/AncestorNotifier.java b/src/java.desktop/share/classes/javax/swing/AncestorNotifier.java index a3ed463d2d5..3606bdc9c0b 100644 --- a/src/java.desktop/share/classes/javax/swing/AncestorNotifier.java +++ b/src/java.desktop/share/classes/javax/swing/AncestorNotifier.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/java.desktop/share/classes/javax/swing/ArrayTable.java b/src/java.desktop/share/classes/javax/swing/ArrayTable.java index 282bd3454ca..4941264c0fe 100644 --- a/src/java.desktop/share/classes/javax/swing/ArrayTable.java +++ b/src/java.desktop/share/classes/javax/swing/ArrayTable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * 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,7 +148,7 @@ class ArrayTable implements Cloneable { if (table != null) { if (isArray()) { Object[] array = (Object[])table; - for (int i = 0; i Class[] types = null; if (args != null) { types = new Class[args.length]; - for (int i = 0; i< args.length; i++) { + for (int i = 0; i < args.length; i++) { /* PENDING(ges): At present only the primitive types used are handled correctly; this should eventually handle all primitive types */ diff --git a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicComboPopup.java b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicComboPopup.java index 42791772c2d..d825dd73e9c 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicComboPopup.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicComboPopup.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2026, Oracle and/or its affiliates. All rights reserved. * 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,8 +243,8 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup { public void hide() { MenuSelectionManager manager = MenuSelectionManager.defaultManager(); MenuElement [] selection = manager.getSelectedPath(); - for ( int i = 0 ; i < selection.length ; i++ ) { - if ( selection[i] == this ) { + for (int i = 0 ; i < selection.length; i++ ) { + if (selection[i] == this) { manager.clearSelectedPath(); break; } @@ -924,7 +924,7 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup { if (!SwingUtilities.isLeftMouseButton(e) || !comboBox.isEnabled() || !comboBox.isShowing()) return; - if ( comboBox.isEditable() ) { + if (comboBox.isEditable()) { Component comp = comboBox.getEditor().getEditorComponent(); if ((!(comp instanceof JComponent)) || ((JComponent)comp).isRequestFocusEnabled()) { comp.requestFocus(FocusEvent.Cause.MOUSE_EVENT); @@ -957,12 +957,12 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup { Component source = (Component)e.getSource(); Dimension size = source.getSize(); Rectangle bounds = new Rectangle( 0, 0, size.width, size.height); - if ( !bounds.contains( e.getPoint() ) ) { + if (!bounds.contains(e.getPoint())) { MouseEvent newEvent = convertMouseEvent( e ); Point location = newEvent.getPoint(); Rectangle r = new Rectangle(); list.computeVisibleRect( r ); - if ( r.contains( location ) ) { + if (r.contains(location)) { if (comboBox.getSelectedIndex() == list.getSelectedIndex()) { comboBox.getEditor().setItem(list.getSelectedValue()); } @@ -989,7 +989,7 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup { Point location = anEvent.getPoint(); Rectangle r = new Rectangle(); list.computeVisibleRect( r ); - if ( r.contains( location ) ) { + if (r.contains(location)) { updateListBoxSelectionForEvent( anEvent, false ); } } @@ -999,34 +999,34 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup { if (e.getSource() == list) { return; } - if ( isVisible() ) { + if (isVisible()) { MouseEvent newEvent = convertMouseEvent( e ); Rectangle r = new Rectangle(); list.computeVisibleRect( r ); - if ( newEvent.getPoint().y >= r.y && newEvent.getPoint().y <= r.y + r.height - 1 ) { + if (newEvent.getPoint().y >= r.y && newEvent.getPoint().y <= r.y + r.height - 1) { hasEntered = true; - if ( isAutoScrolling ) { + if (isAutoScrolling) { stopAutoScrolling(); } Point location = newEvent.getPoint(); - if ( r.contains( location ) ) { + if (r.contains(location)) { updateListBoxSelectionForEvent( newEvent, false ); } } else { - if ( hasEntered ) { + if (hasEntered) { int directionToScroll = newEvent.getPoint().y < r.y ? SCROLL_UP : SCROLL_DOWN; - if ( isAutoScrolling && scrollDirection != directionToScroll ) { + if (isAutoScrolling && scrollDirection != directionToScroll) { stopAutoScrolling(); startAutoScrolling( directionToScroll ); } - else if ( !isAutoScrolling ) { + else if (!isAutoScrolling) { startAutoScrolling( directionToScroll ); } } else { - if ( e.getPoint().y < 0 ) { + if (e.getPoint().y < 0) { hasEntered = true; startAutoScrolling( SCROLL_UP ); } @@ -1043,7 +1043,7 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup { JComboBox comboBox = (JComboBox)e.getSource(); String propertyName = e.getPropertyName(); - if ( propertyName == "model" ) { + if (propertyName == "model") { @SuppressWarnings("unchecked") ComboBoxModel oldModel = (ComboBoxModel)e.getOldValue(); @SuppressWarnings("unchecked") @@ -1053,13 +1053,13 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup { list.setModel(newModel); - if ( isVisible() ) { + if (isVisible()) { hide(); } } - else if ( propertyName == "renderer" ) { + else if (propertyName == "renderer") { list.setCellRenderer( comboBox.getRenderer() ); - if ( isVisible() ) { + if (isVisible()) { hide(); } } @@ -1067,18 +1067,18 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup { // Pass along the new component orientation // to the list and the scroller - ComponentOrientation o =(ComponentOrientation)e.getNewValue(); + ComponentOrientation o = (ComponentOrientation)e.getNewValue(); JList list = getList(); - if (list != null && list.getComponentOrientation()!=o) { + if (list != null && list.getComponentOrientation() != o) { list.setComponentOrientation(o); } - if (scroller != null && scroller.getComponentOrientation()!=o) { + if (scroller != null && scroller.getComponentOrientation() != o) { scroller.setComponentOrientation(o); } - if (o!=getComponentOrientation()) { + if (o != getComponentOrientation()) { setComponentOrientation(o); } } @@ -1134,13 +1134,13 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup { protected void startAutoScrolling( int direction ) { // XXX - should be a private method within InvocationMouseMotionHandler // if possible. - if ( isAutoScrolling ) { + if (isAutoScrolling) { autoscrollTimer.stop(); } isAutoScrolling = true; - if ( direction == SCROLL_UP ) { + if (direction == SCROLL_UP) { scrollDirection = SCROLL_UP; Point convertedPoint = SwingUtilities.convertPoint( scroller, new Point( 1, 1 ), list ); int top = list.locationToIndex( convertedPoint ); @@ -1149,7 +1149,7 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup { autoscrollTimer = new Timer( 100, new AutoScrollActionHandler( SCROLL_UP) ); } - else if ( direction == SCROLL_DOWN ) { + else if (direction == SCROLL_DOWN) { scrollDirection = SCROLL_DOWN; Dimension size = scroller.getSize(); Point convertedPoint = SwingUtilities.convertPoint( scroller, @@ -1171,7 +1171,7 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup { protected void stopAutoScrolling() { isAutoScrolling = false; - if ( autoscrollTimer != null ) { + if (autoscrollTimer != null) { autoscrollTimer.stop(); autoscrollTimer = null; } @@ -1183,7 +1183,7 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup { */ protected void autoScrollUp() { int index = list.getSelectedIndex(); - if ( index > 0 ) { + if (index > 0) { list.setSelectedIndex( index - 1 ); list.ensureIndexIsVisible( index - 1 ); } @@ -1196,7 +1196,7 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup { protected void autoScrollDown() { int index = list.getSelectedIndex(); int lastItem = list.getModel().getSize() - 1; - if ( index < lastItem ) { + if (index < lastItem) { list.setSelectedIndex( index + 1 ); list.ensureIndexIsVisible( index + 1 ); } @@ -1234,7 +1234,7 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup { * @param e a mouse event */ protected void delegateFocus( MouseEvent e ) { - if ( comboBox.isEditable() ) { + if (comboBox.isEditable()) { Component comp = comboBox.getEditor().getEditorComponent(); if ((!(comp instanceof JComponent)) || ((JComponent)comp).isRequestFocusEnabled()) { if (e != null) { @@ -1258,7 +1258,7 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup { * visible. */ protected void togglePopup() { - if ( isVisible() ) { + if (isVisible()) { hide(); } else { @@ -1274,7 +1274,7 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup { * @param selectedIndex the index to set the list */ private void setListSelection(int selectedIndex) { - if ( selectedIndex == -1 ) { + if (selectedIndex == -1) { list.clearSelection(); } else { @@ -1325,7 +1325,7 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup { ListCellRenderer renderer = list.getCellRenderer(); Object value = null; - for ( int i = 0; i < minRowCount; ++i ) { + for (int i = 0; i < minRowCount; ++i) { value = list.getModel().getElementAt( i ); Component c = renderer.getListCellRendererComponent( list, value, i, false, false ); height += c.getPreferredSize().height; @@ -1439,18 +1439,18 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup { // XXX - only seems to be called from this class. shouldScroll flag is // never true Point location = anEvent.getPoint(); - if ( list == null ) + if (list == null) return; int index = list.locationToIndex(location); - if ( index == -1 ) { - if ( location.y < 0 ) + if (index == -1) { + if (location.y < 0) index = 0; else index = comboBox.getModel().getSize() - 1; } - if ( list.getSelectedIndex() != index ) { + if (list.getSelectedIndex() != index) { list.setSelectedIndex(index); - if ( shouldScroll ) + if (shouldScroll) list.ensureIndexIsVisible(index); } } diff --git a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicListUI.java b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicListUI.java index ab5fdb12c5a..37bcbec2156 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicListUI.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicListUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicMenuBarUI.java b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicMenuBarUI.java index b7310b56aef..a9abaee0129 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicMenuBarUI.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicMenuBarUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -237,10 +237,10 @@ public class BasicMenuBarUI extends MenuBarUI { // ChangeListener // public void stateChanged(ChangeEvent e) { - int i,c; - for(i=0,c = menuBar.getMenuCount() ; i < c ; i++) { + final int c = menuBar.getMenuCount(); + for (int i = 0; i < c; i++) { JMenu menu = menuBar.getMenu(i); - if(menu != null && menu.isSelected()) { + if (menu != null && menu.isSelected()) { menuBar.getSelectionModel().setSelectedIndex(i); break; } diff --git a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicPopupMenuUI.java b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicPopupMenuUI.java index b72a2d8a140..a3ffb034b4b 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicPopupMenuUI.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicPopupMenuUI.java @@ -908,7 +908,7 @@ public class BasicPopupMenuUI extends PopupMenuUI { } boolean isInPopup(Component src) { - for (Component c=src; c != null; c=c.getParent()) { + for (Component c = src; c != null; c = c.getParent()) { if (c instanceof Window) { break; } else if (c instanceof JPopupMenu) { diff --git a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicSpinnerUI.java b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicSpinnerUI.java index 7080fa3aac1..b523f8c7bd3 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicSpinnerUI.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicSpinnerUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTabbedPaneUI.java b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTabbedPaneUI.java index 6e0d0101b9c..de23dbab29a 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTabbedPaneUI.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTabbedPaneUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -504,7 +504,7 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants { tabPane.addFocusListener(focusListener); } tabPane.addContainerListener(getHandler()); - if (tabPane.getTabCount()>0) { + if (tabPane.getTabCount() > 0) { Boolean htmlDisabled = (Boolean) tabPane.getClientProperty("html.disable"); if (!(Boolean.TRUE.equals(htmlDisabled))) { @@ -949,8 +949,8 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants { // Paint tabRuns of tabs from back to front for (int i = runCount - 1; i >= 0; i--) { int start = tabRuns[i]; - int next = tabRuns[(i == runCount - 1)? 0 : i + 1]; - int end = (next != 0? next - 1: tabCount - 1); + int next = tabRuns[(i == runCount - 1) ? 0 : i + 1]; + int end = (next != 0 ? next - 1 : tabCount - 1); for (int j = start; j <= end; j++) { if (j != selectedIndex && rects[j].intersects(clipRect)) { paintTab(g, tabPlacement, rects, j, iconRect, textRect); @@ -1118,7 +1118,7 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants { int xx = x; g.setColor(shadow); while(xx <= x+rects[tabIndex].width) { - for (int i=0; i < xCropLen.length; i+=2) { + for (int i = 0; i < xCropLen.length; i += 2) { g.drawLine(xx+yCropLen[i],y-xCropLen[i], xx+yCropLen[i+1]-1,y-xCropLen[i+1]); } @@ -1133,7 +1133,7 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants { int yy = y; g.setColor(shadow); while(yy <= y+rects[tabIndex].height) { - for (int i=0; i < xCropLen.length; i+=2) { + for (int i = 0; i < xCropLen.length; i += 2) { g.drawLine(x-xCropLen[i],yy+yCropLen[i], x-xCropLen[i+1],yy+yCropLen[i+1]-1); } @@ -1549,7 +1549,7 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants { protected void paintContentBorderTopEdge(Graphics g, int tabPlacement, int selectedIndex, int x, int y, int w, int h) { - Rectangle selRect = selectedIndex < 0? null : + Rectangle selRect = selectedIndex < 0 ? null : getTabBounds(selectedIndex, calcRect); g.setColor(lightHighlight); @@ -1588,7 +1588,7 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants { protected void paintContentBorderLeftEdge(Graphics g, int tabPlacement, int selectedIndex, int x, int y, int w, int h) { - Rectangle selRect = selectedIndex < 0? null : + Rectangle selRect = selectedIndex < 0 ? null : getTabBounds(selectedIndex, calcRect); g.setColor(lightHighlight); @@ -1624,7 +1624,7 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants { protected void paintContentBorderBottomEdge(Graphics g, int tabPlacement, int selectedIndex, int x, int y, int w, int h) { - Rectangle selRect = selectedIndex < 0? null : + Rectangle selRect = selectedIndex < 0 ? null : getTabBounds(selectedIndex, calcRect); g.setColor(shadow); @@ -1667,7 +1667,7 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants { protected void paintContentBorderRightEdge(Graphics g, int tabPlacement, int selectedIndex, int x, int y, int w, int h) { - Rectangle selRect = selectedIndex < 0? null : + Rectangle selRect = selectedIndex < 0 ? null : getTabBounds(selectedIndex, calcRect); g.setColor(shadow); @@ -4090,7 +4090,7 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants { setHtmlView(v, inserted, index); } } else { // Not HTML - if (htmlViews != null) { // Add placeholder + if (htmlViews != null) { // Add placeholder setHtmlView(null, inserted, index); } // else nada! } @@ -4336,8 +4336,8 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants { private Vector createHTMLVector() { Vector htmlViews = new Vector(); int count = tabPane.getTabCount(); - if (count>0) { - for (int i=0 ; i 0) { + for (int i = 0 ; i < count; i++) { String title = tabPane.getTitleAt(i); if (BasicHTML.isHTMLString(title)) { htmlViews.addElement(BasicHTML.createHTMLView(tabPane, title)); diff --git a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicToolBarUI.java b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicToolBarUI.java index 1bcd4a9be8d..9c07b6a03d1 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicToolBarUI.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicToolBarUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTreeUI.java b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTreeUI.java index 096fe7cc5f7..19a25005be9 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTreeUI.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTreeUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/java.desktop/share/classes/javax/swing/plaf/nimbus/AbstractRegionPainter.java b/src/java.desktop/share/classes/javax/swing/plaf/nimbus/AbstractRegionPainter.java index cfcc014940a..d06406d69d6 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/nimbus/AbstractRegionPainter.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/nimbus/AbstractRegionPainter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/java.desktop/share/classes/javax/swing/plaf/nimbus/NimbusLookAndFeel.java b/src/java.desktop/share/classes/javax/swing/plaf/nimbus/NimbusLookAndFeel.java index 05fa3bbc9b6..7ef7beb5d1c 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/nimbus/NimbusLookAndFeel.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/nimbus/NimbusLookAndFeel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/java.desktop/share/classes/javax/swing/plaf/nimbus/SynthPainterImpl.java b/src/java.desktop/share/classes/javax/swing/plaf/nimbus/SynthPainterImpl.java index 1842073588b..fd761ac4730 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/nimbus/SynthPainterImpl.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/nimbus/SynthPainterImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthComboBoxUI.java b/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthComboBoxUI.java index ad10e70a837..0c373483153 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthComboBoxUI.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthComboBoxUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthScrollPaneUI.java b/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthScrollPaneUI.java index 0c3a17fbdbb..c07feb8b56d 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthScrollPaneUI.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthScrollPaneUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/java.desktop/share/classes/javax/swing/text/TextAction.java b/src/java.desktop/share/classes/javax/swing/text/TextAction.java index d05f7e24a6b..00da7bad93e 100644 --- a/src/java.desktop/share/classes/javax/swing/text/TextAction.java +++ b/src/java.desktop/share/classes/javax/swing/text/TextAction.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/java.desktop/share/classes/javax/swing/tree/DefaultTreeCellEditor.java b/src/java.desktop/share/classes/javax/swing/tree/DefaultTreeCellEditor.java index 3f3721dd30a..7595638dc66 100644 --- a/src/java.desktop/share/classes/javax/swing/tree/DefaultTreeCellEditor.java +++ b/src/java.desktop/share/classes/javax/swing/tree/DefaultTreeCellEditor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it From 5fec4ed37a7acb42e290ba8d60565b20603195aa Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Tue, 31 Mar 2026 03:46:23 +0000 Subject: [PATCH 108/359] 8379679: java/foreign/TestConcurrentClose.java awaitTermination times out on Windows debug builds Reviewed-by: alanb --- .../jdk/java/foreign/TestConcurrentClose.java | 38 +++++++++---------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/test/jdk/java/foreign/TestConcurrentClose.java b/test/jdk/java/foreign/TestConcurrentClose.java index 82bb2492acf..74f0ca2a877 100644 --- a/test/jdk/java/foreign/TestConcurrentClose.java +++ b/test/jdk/java/foreign/TestConcurrentClose.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. * 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,13 +49,11 @@ import java.lang.reflect.Method; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; import static java.lang.foreign.ValueLayout.JAVA_BYTE; import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertTrue; public class TestConcurrentClose { static final WhiteBox WB = WhiteBox.getWhiteBox(); @@ -72,7 +70,6 @@ public class TestConcurrentClose { static final int ITERATIONS = 5; static final int SEGMENT_SIZE = 10_000; - static final int MAX_EXECUTOR_WAIT_SECONDS = 60; static final int NUM_ACCESSORS = 50; static final AtomicLong start = new AtomicLong(); @@ -82,25 +79,24 @@ public class TestConcurrentClose { public void testHandshake() throws InterruptedException { for (int it = 0; it < ITERATIONS; it++) { System.out.println("ITERATION " + it + " - starting"); - ExecutorService accessExecutor = Executors.newCachedThreadPool(); - start.set(System.currentTimeMillis()); - started.set(false); - CountDownLatch startClosureLatch = new CountDownLatch(1); + try (ExecutorService accessExecutor = Executors.newCachedThreadPool()) { + start.set(System.currentTimeMillis()); + started.set(false); + CountDownLatch startClosureLatch = new CountDownLatch(1); - for (int i = 0; i < NUM_ACCESSORS ; i++) { - Arena arena = Arena.ofShared(); - MemorySegment segment = arena.allocate(SEGMENT_SIZE, 1); - accessExecutor.execute(new SegmentAccessor(i, segment)); - accessExecutor.execute(new Closer(i, startClosureLatch, arena)); + for (int i = 0; i < NUM_ACCESSORS; i++) { + Arena arena = Arena.ofShared(); + MemorySegment segment = arena.allocate(SEGMENT_SIZE, 1); + accessExecutor.execute(new SegmentAccessor(i, segment)); + accessExecutor.execute(new Closer(i, startClosureLatch, arena)); + } + + awaitCompilation(); + + long closeDelay = System.currentTimeMillis() - start.get(); + System.out.println("Starting closers after delay of " + closeDelay + " millis"); + startClosureLatch.countDown(); } - - awaitCompilation(); - - long closeDelay = System.currentTimeMillis() - start.get(); - System.out.println("Starting closers after delay of " + closeDelay + " millis"); - startClosureLatch.countDown(); - accessExecutor.shutdown(); - assertTrue(accessExecutor.awaitTermination(MAX_EXECUTOR_WAIT_SECONDS, TimeUnit.SECONDS)); long finishDelay = System.currentTimeMillis() - start.get(); System.out.println("ITERATION " + it + " - finished, after " + finishDelay + "milis"); } From 3aab51828582a48a9c7ee2729284fea8763050c6 Mon Sep 17 00:00:00 2001 From: Kirill Shirokov Date: Tue, 31 Mar 2026 05:07:04 +0000 Subject: [PATCH 109/359] 8380074: Reflection::areNestMates should be used by Class::isNestmateOf Reviewed-by: liach, dholmes --- src/java.base/share/classes/java/lang/Class.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/java.base/share/classes/java/lang/Class.java b/src/java.base/share/classes/java/lang/Class.java index 8a2f722f3dd..f15291827d5 100644 --- a/src/java.base/share/classes/java/lang/Class.java +++ b/src/java.base/share/classes/java/lang/Class.java @@ -3841,7 +3841,7 @@ public final class Class implements java.io.Serializable, return false; } - return getNestHost() == c.getNestHost(); + return Reflection.areNestMates(this, c); } private native Class[] getNestMembers0(); From 77cfead6fe84e254133681ee22d81fa190e0e371 Mon Sep 17 00:00:00 2001 From: Jayathirth D V Date: Tue, 31 Mar 2026 05:32:33 +0000 Subject: [PATCH 110/359] 8380959: Update Libpng to 1.6.56 Reviewed-by: erikj, aivanov, honkar, prr --- .../java.desktop/lib/ClientLibraries.gmk | 3 +- src/java.desktop/share/legal/libpng.md | 5 +- .../native/libsplashscreen/libpng/CHANGES | 31 ++++++++ .../native/libsplashscreen/libpng/README | 2 +- .../share/native/libsplashscreen/libpng/png.c | 16 ++-- .../share/native/libsplashscreen/libpng/png.h | 16 ++-- .../native/libsplashscreen/libpng/pngconf.h | 2 +- .../libsplashscreen/libpng/pnglibconf.h | 2 +- .../native/libsplashscreen/libpng/pngpriv.h | 4 +- .../native/libsplashscreen/libpng/pngread.c | 68 +++++++++-------- .../native/libsplashscreen/libpng/pngrtran.c | 30 +++++++- .../native/libsplashscreen/libpng/pngrutil.c | 42 ++++------- .../native/libsplashscreen/libpng/pngset.c | 73 ++++++++++++------- .../native/libsplashscreen/libpng/pngstruct.h | 6 +- .../native/libsplashscreen/libpng/pngtrans.c | 40 ++++++++-- 15 files changed, 218 insertions(+), 122 deletions(-) diff --git a/make/modules/java.desktop/lib/ClientLibraries.gmk b/make/modules/java.desktop/lib/ClientLibraries.gmk index 13a74ab409f..3e37fe79643 100644 --- a/make/modules/java.desktop/lib/ClientLibraries.gmk +++ b/make/modules/java.desktop/lib/ClientLibraries.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2026, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -257,6 +257,7 @@ ifeq ($(ENABLE_HEADLESS_ONLY), false) DISABLED_WARNINGS_microsoft_dgif_lib.c := 4018 4267, \ DISABLED_WARNINGS_microsoft_splashscreen_impl.c := 4018 4267 4244, \ DISABLED_WARNINGS_microsoft_splashscreen_png.c := 4267, \ + DISABLED_WARNINGS_microsoft_pngread.c := 4146, \ DISABLED_WARNINGS_microsoft_splashscreen_sys.c := 4267 4244, \ LDFLAGS := $(ICONV_LDFLAGS), \ LDFLAGS_windows := -delayload:user32.dll, \ diff --git a/src/java.desktop/share/legal/libpng.md b/src/java.desktop/share/legal/libpng.md index a2ffcca1974..034de22bf25 100644 --- a/src/java.desktop/share/legal/libpng.md +++ b/src/java.desktop/share/legal/libpng.md @@ -1,4 +1,4 @@ -## libpng v1.6.55 +## libpng v1.6.56 ### libpng License
@@ -168,6 +168,7 @@ Authors, for copyright and licensing purposes.
  * Glenn Randers-Pehrson
  * Greg Roelofs
  * Guy Eric Schalnat
+ * Halil Oktay
  * James Yu
  * John Bowler
  * Joshua Inscoe
@@ -187,12 +188,14 @@ Authors, for copyright and licensing purposes.
  * Sam Bushell
  * Samuel Williams
  * Simon-Pierre Cadieux
+ * Taegu Ha (하태구)
  * Tim Wegner
  * Tobias Stoeckmann
  * Tom Lane
  * Tom Tanner
  * Vadim Barkov
  * Willem van Schaik
+ * Yuelin Wang (王跃林)
  * Zhijie Liang
  * Apple Inc.
     - Zixu Wang (王子旭)
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/CHANGES b/src/java.desktop/share/native/libsplashscreen/libpng/CHANGES
index af9fcff6eb3..673d4d50420 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/CHANGES
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/CHANGES
@@ -6337,6 +6337,37 @@ Version 1.6.55 [February 9, 2026]
   Resolved an oss-fuzz build issue involving nalloc.
     (Contributed by Philippe Antoine.)
 
+Version 1.6.56 [March 25, 2026]
+  Fixed CVE-2026-33416 (high severity):
+    Use-after-free via pointer aliasing in `png_set_tRNS` and `png_set_PLTE`.
+    (Reported by Halil Oktay and Ryo Shimada;
+    fixed by Halil Oktay and Cosmin Truta.)
+  Fixed CVE-2026-33636 (high severity):
+    Out-of-bounds read/write in the palette expansion on ARM Neon.
+    (Reported by Taegu Ha; fixed by Taegu Ha and Cosmin Truta.)
+  Fixed uninitialized reads beyond `num_trans` in `trans_alpha` buffers.
+    (Contributed by Halil Oktay.)
+  Fixed stale `info_ptr->palette` after in-place gamma and background
+    transforms.
+  Fixed wrong channel indices in `png_image_read_and_map` RGB_ALPHA path.
+    (Contributed by Yuelin Wang.)
+  Fixed wrong background color in colormap read.
+    (Contributed by Yuelin Wang.)
+  Fixed dead loop in sPLT write.
+    (Contributed by Yuelin Wang.)
+  Added missing null pointer checks in four public API functions.
+    (Contributed by Yuelin Wang.)
+  Validated shift bit depths in `png_set_shift` to prevent infinite loop.
+    (Contributed by Yuelin Wang.)
+  Avoided undefined behavior in library and tests.
+  Deprecated the hardly-ever-tested POINTER_INDEXING config option.
+  Added negative-stride test coverage for the simplified API.
+  Fixed memory leaks and API misuse in oss-fuzz.
+    (Contributed by Owen Sanzas.)
+  Implemented various fixes and improvements in oss-fuzz.
+    (Contributed by Bob Friesenhahn and Philippe Antoine.)
+  Performed various refactorings and cleanups.
+
 Send comments/corrections/commendations to png-mng-implement at lists.sf.net.
 Subscription is required; visit
 
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/README b/src/java.desktop/share/native/libsplashscreen/libpng/README
index 6e0d1e33137..d0b085f7933 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/README
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/README
@@ -1,4 +1,4 @@
-README for libpng version 1.6.55
+README for libpng version 1.6.56
 ================================
 
 See the note about version numbers near the top of `png.h`.
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/png.c b/src/java.desktop/share/native/libsplashscreen/libpng/png.c
index 955fda8dd7e..fd095b515b9 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/png.c
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/png.c
@@ -42,7 +42,7 @@
 #include "pngpriv.h"
 
 /* Generate a compiler error if there is an old png.h in the search path. */
-typedef png_libpng_version_1_6_55 Your_png_h_is_not_version_1_6_55;
+typedef png_libpng_version_1_6_56 Your_png_h_is_not_version_1_6_56;
 
 /* Sanity check the chunks definitions - PNG_KNOWN_CHUNKS from pngpriv.h and the
  * corresponding macro definitions.  This causes a compile time failure if
@@ -849,7 +849,7 @@ png_get_copyright(png_const_structrp png_ptr)
    return PNG_STRING_COPYRIGHT
 #else
    return PNG_STRING_NEWLINE \
-      "libpng version 1.6.55" PNG_STRING_NEWLINE \
+      "libpng version 1.6.56" PNG_STRING_NEWLINE \
       "Copyright (c) 2018-2026 Cosmin Truta" PNG_STRING_NEWLINE \
       "Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson" \
       PNG_STRING_NEWLINE \
@@ -1199,7 +1199,7 @@ png_xy_from_XYZ(png_xy *xy, const png_XYZ *XYZ)
       return 1;
 
    /* The reference white is simply the sum of the end-point (X,Y,Z) vectors so
-    * the fillowing calculates (X+Y+Z) of the reference white (media white,
+    * the following calculates (X+Y+Z) of the reference white (media white,
     * encoding white) itself:
     */
    d = dblue;
@@ -1244,9 +1244,9 @@ png_XYZ_from_xy(png_XYZ *XYZ, const png_xy *xy)
     * (-0.0770) because the PNG spec itself requires the xy values to be
     * unsigned.  whitey is also required to be 5 or more to avoid overflow.
     *
-    * Instead the upper limits have been relaxed to accomodate ACES AP1 where
+    * Instead the upper limits have been relaxed to accommodate ACES AP1 where
     * redz ends up as -600 (-0.006).  ProPhotoRGB was already "in range."
-    * The new limit accomodates the AP0 and AP1 ranges for z but not AP0 redy.
+    * The new limit accommodates the AP0 and AP1 ranges for z but not AP0 redy.
     */
    const png_fixed_point fpLimit = PNG_FP_1+(PNG_FP_1/10);
    if (xy->redx   < 0 || xy->redx > fpLimit) return 1;
@@ -1357,7 +1357,7 @@ png_XYZ_from_xy(png_XYZ *XYZ, const png_xy *xy)
     *    red-scale + green-scale + blue-scale = 1/white-y = white-scale
     *
     * So now we have a Cramer's rule solution where the determinants are just
-    * 3x3 - far more tractible.  Unfortunately 3x3 determinants still involve
+    * 3x3 - far more tractable.  Unfortunately 3x3 determinants still involve
     * multiplication of three coefficients so we can't guarantee to avoid
     * overflow in the libpng fixed point representation.  Using Cramer's rule in
     * floating point is probably a good choice here, but it's not an option for
@@ -1726,7 +1726,7 @@ png_icc_check_header(png_const_structrp png_ptr, png_const_charp name,
     * into R, G and B channels.
     *
     * Previously it was suggested that an RGB profile on grayscale data could be
-    * handled.  However it it is clear that using an RGB profile in this context
+    * handled.  However it is clear that using an RGB profile in this context
     * must be an error - there is no specification of what it means.  Thus it is
     * almost certainly more correct to ignore the profile.
     */
@@ -2944,7 +2944,7 @@ png_gamma_significant(png_fixed_point gamma_val)
     *
     *    2.2/(2+51/256) == 1.00035524
     *
-    * I.e. vanishly small (<4E-4) but still detectable in 16-bit linear (+/-
+    * I.e. vanishingly small (<4E-4) but still detectable in 16-bit linear (+/-
     * 23).  Note that the Adobe choice seems to be something intended to give an
     * exact number with 8 binary fractional digits - it is the closest to 2.2
     * that is possible a base 2 .8p representation.
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/png.h b/src/java.desktop/share/native/libsplashscreen/libpng/png.h
index e95c0444399..56ec204cd1a 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/png.h
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/png.h
@@ -29,7 +29,7 @@
  * However, the following notice accompanied the original version of this
  * file and, per its terms, should not be removed:
  *
- * libpng version 1.6.55
+ * libpng version 1.6.56
  *
  * Copyright (c) 2018-2026 Cosmin Truta
  * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
@@ -43,7 +43,7 @@
  *   libpng versions 0.89, June 1996, through 0.96, May 1997: Andreas Dilger
  *   libpng versions 0.97, January 1998, through 1.6.35, July 2018:
  *     Glenn Randers-Pehrson
- *   libpng versions 1.6.36, December 2018, through 1.6.55, February 2026:
+ *   libpng versions 1.6.36, December 2018, through 1.6.56, March 2026:
  *     Cosmin Truta
  *   See also "Contributing Authors", below.
  */
@@ -267,7 +267,7 @@
  *    ...
  *    1.5.30                  15    10530  15.so.15.30[.0]
  *    ...
- *    1.6.55                  16    10655  16.so.16.55[.0]
+ *    1.6.56                  16    10656  16.so.16.56[.0]
  *
  *    Henceforth the source version will match the shared-library major and
  *    minor numbers; the shared-library major version number will be used for
@@ -303,7 +303,7 @@
  */
 
 /* Version information for png.h - this should match the version in png.c */
-#define PNG_LIBPNG_VER_STRING "1.6.55"
+#define PNG_LIBPNG_VER_STRING "1.6.56"
 #define PNG_HEADER_VERSION_STRING " libpng version " PNG_LIBPNG_VER_STRING "\n"
 
 /* The versions of shared library builds should stay in sync, going forward */
@@ -314,7 +314,7 @@
 /* These should match the first 3 components of PNG_LIBPNG_VER_STRING: */
 #define PNG_LIBPNG_VER_MAJOR   1
 #define PNG_LIBPNG_VER_MINOR   6
-#define PNG_LIBPNG_VER_RELEASE 55
+#define PNG_LIBPNG_VER_RELEASE 56
 
 /* This should be zero for a public release, or non-zero for a
  * development version.
@@ -345,7 +345,7 @@
  * From version 1.0.1 it is:
  * XXYYZZ, where XX=major, YY=minor, ZZ=release
  */
-#define PNG_LIBPNG_VER 10655 /* 1.6.55 */
+#define PNG_LIBPNG_VER 10656 /* 1.6.56 */
 
 /* Library configuration: these options cannot be changed after
  * the library has been built.
@@ -455,7 +455,7 @@ extern "C" {
 /* This triggers a compiler error in png.c, if png.c and png.h
  * do not agree upon the version number.
  */
-typedef char *png_libpng_version_1_6_55;
+typedef char *png_libpng_version_1_6_56;
 
 /* Basic control structions.  Read libpng-manual.txt or libpng.3 for more info.
  *
@@ -2370,7 +2370,7 @@ PNG_EXPORT(162, int, png_get_text,
 #endif
 
 /* Note while png_set_text() will accept a structure whose text,
- * language, and  translated keywords are NULL pointers, the structure
+ * language, and translated keywords are NULL pointers, the structure
  * returned by png_get_text will always contain regular
  * zero-terminated C strings.  They might be empty strings but
  * they will never be NULL pointers.
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngconf.h b/src/java.desktop/share/native/libsplashscreen/libpng/pngconf.h
index b957f8b5061..5772e6ebb1c 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pngconf.h
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngconf.h
@@ -29,7 +29,7 @@
  * However, the following notice accompanied the original version of this
  * file and, per its terms, should not be removed:
  *
- * libpng version 1.6.55
+ * libpng version 1.6.56
  *
  * Copyright (c) 2018-2026 Cosmin Truta
  * Copyright (c) 1998-2002,2004,2006-2016,2018 Glenn Randers-Pehrson
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pnglibconf.h b/src/java.desktop/share/native/libsplashscreen/libpng/pnglibconf.h
index ae1ab462072..4a7e51d112d 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pnglibconf.h
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pnglibconf.h
@@ -31,7 +31,7 @@
  * However, the following notice accompanied the original version of this
  * file and, per its terms, should not be removed:
  */
-/* libpng version 1.6.55 */
+/* libpng version 1.6.56 */
 
 /* Copyright (c) 2018-2026 Cosmin Truta */
 /* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson */
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngpriv.h b/src/java.desktop/share/native/libsplashscreen/libpng/pngpriv.h
index ee91f58d4ba..086a2f76ee6 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pngpriv.h
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngpriv.h
@@ -986,7 +986,7 @@
  *
  * At present these index values are not exported (not part of the public API)
  * so can be changed at will.  For convenience the names are in lexical sort
- * order but with the critical chunks at the start in the order of occurence in
+ * order but with the critical chunks at the start in the order of occurrence in
  * a PNG.
  *
  * PNG_INFO_ values do not exist for every one of these chunk handles; for
@@ -2115,7 +2115,7 @@ PNG_INTERNAL_FUNCTION(void, png_ascii_from_fixed,
  * not valid it will be the index of a character in the supposed number.
  *
  * The format of a number is defined in the PNG extensions specification
- * and this API is strictly conformant to that spec, not anyone elses!
+ * and this API is strictly conformant to that spec, not anyone else's!
  *
  * The format as a regular expression is:
  *
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngread.c b/src/java.desktop/share/native/libsplashscreen/libpng/pngread.c
index 79fd9ad6a82..70df18926f5 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pngread.c
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngread.c
@@ -720,7 +720,7 @@ png_read_end(png_structrp png_ptr, png_inforp info_ptr)
       png_read_finish_IDAT(png_ptr);
 
 #ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED
-   /* Report invalid palette index; added at libng-1.5.10 */
+   /* Report invalid palette index; added at libpng-1.5.10 */
    if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&
        png_ptr->num_palette_max >= png_ptr->num_palette)
       png_benign_error(png_ptr, "Read palette index exceeding num_palette");
@@ -808,21 +808,19 @@ png_read_destroy(png_structrp png_ptr)
    png_ptr->quantize_index = NULL;
 #endif
 
-   if ((png_ptr->free_me & PNG_FREE_PLTE) != 0)
-   {
-      png_zfree(png_ptr, png_ptr->palette);
-      png_ptr->palette = NULL;
-   }
-   png_ptr->free_me &= ~PNG_FREE_PLTE;
+   /* png_ptr->palette is always independently allocated (not aliased
+    * with info_ptr->palette), so free it unconditionally.
+    */
+   png_free(png_ptr, png_ptr->palette);
+   png_ptr->palette = NULL;
 
 #if defined(PNG_tRNS_SUPPORTED) || \
     defined(PNG_READ_EXPAND_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
-   if ((png_ptr->free_me & PNG_FREE_TRNS) != 0)
-   {
-      png_free(png_ptr, png_ptr->trans_alpha);
-      png_ptr->trans_alpha = NULL;
-   }
-   png_ptr->free_me &= ~PNG_FREE_TRNS;
+   /* png_ptr->trans_alpha is always independently allocated (not aliased
+    * with info_ptr->trans_alpha), so free it unconditionally.
+    */
+   png_free(png_ptr, png_ptr->trans_alpha);
+   png_ptr->trans_alpha = NULL;
 #endif
 
    inflateEnd(&png_ptr->zstream);
@@ -1285,7 +1283,7 @@ png_image_is_not_sRGB(png_const_structrp png_ptr)
     * png_struct::chromaticities always exists since the simplified API
     * requires rgb-to-gray.  The mDCV, cICP and cHRM chunks may all set it to
     * a non-sRGB value, so it needs to be checked but **only** if one of
-    * those chunks occured in the file.
+    * those chunks occurred in the file.
     */
    /* Highest priority: check to be safe. */
    if (png_has_chunk(png_ptr, cICP) || png_has_chunk(png_ptr, mDCV))
@@ -2625,7 +2623,7 @@ png_image_read_colormap(png_voidp argument)
                   {
                      r = back_r;
                      g = back_g;
-                     b = back_g;
+                     b = back_b;
                   }
 
                   /* Compare the newly-created color-map entry with the one the
@@ -2903,9 +2901,9 @@ png_image_read_and_map(png_voidp argument)
          {
             png_bytep inrow = png_voidcast(png_bytep, display->local_row);
             png_bytep outrow = first_row + y * row_step;
-            png_const_bytep end_row = outrow + width;
+            png_const_bytep row_end = outrow + width;
 
-            /* Read read the libpng data into the temporary buffer. */
+            /* Read the libpng data into the temporary buffer. */
             png_read_row(png_ptr, inrow, NULL);
 
             /* Now process the row according to the processing option, note
@@ -2916,7 +2914,7 @@ png_image_read_and_map(png_voidp argument)
             switch (proc)
             {
                case PNG_CMAP_GA:
-                  for (; outrow < end_row; outrow += stepx)
+                  for (; outrow < row_end; outrow += stepx)
                   {
                      /* The data is always in the PNG order */
                      unsigned int gray = *inrow++;
@@ -2945,7 +2943,7 @@ png_image_read_and_map(png_voidp argument)
                   break;
 
                case PNG_CMAP_TRANS:
-                  for (; outrow < end_row; outrow += stepx)
+                  for (; outrow < row_end; outrow += stepx)
                   {
                      png_byte gray = *inrow++;
                      png_byte alpha = *inrow++;
@@ -2962,7 +2960,7 @@ png_image_read_and_map(png_voidp argument)
                   break;
 
                case PNG_CMAP_RGB:
-                  for (; outrow < end_row; outrow += stepx)
+                  for (; outrow < row_end; outrow += stepx)
                   {
                      *outrow = PNG_RGB_INDEX(inrow[0], inrow[1], inrow[2]);
                      inrow += 3;
@@ -2970,7 +2968,7 @@ png_image_read_and_map(png_voidp argument)
                   break;
 
                case PNG_CMAP_RGB_ALPHA:
-                  for (; outrow < end_row; outrow += stepx)
+                  for (; outrow < row_end; outrow += stepx)
                   {
                      unsigned int alpha = inrow[3];
 
@@ -3007,10 +3005,10 @@ png_image_read_and_map(png_voidp argument)
                          */
                         if (inrow[0] & 0x80) back_i += 9; /* red */
                         if (inrow[0] & 0x40) back_i += 9;
-                        if (inrow[0] & 0x80) back_i += 3; /* green */
-                        if (inrow[0] & 0x40) back_i += 3;
-                        if (inrow[0] & 0x80) back_i += 1; /* blue */
-                        if (inrow[0] & 0x40) back_i += 1;
+                        if (inrow[1] & 0x80) back_i += 3; /* green */
+                        if (inrow[1] & 0x40) back_i += 3;
+                        if (inrow[2] & 0x80) back_i += 1; /* blue */
+                        if (inrow[2] & 0x40) back_i += 1;
 
                         *outrow = (png_byte)back_i;
                      }
@@ -3277,18 +3275,18 @@ png_image_read_composite(png_voidp argument)
          {
             png_bytep inrow = png_voidcast(png_bytep, display->local_row);
             png_bytep outrow;
-            png_const_bytep end_row;
+            png_const_bytep row_end;
 
             /* Read the row, which is packed: */
             png_read_row(png_ptr, inrow, NULL);
 
             outrow = png_voidcast(png_bytep, display->first_row);
             outrow += y * row_step;
-            end_row = outrow + width * channels;
+            row_end = outrow + width * channels;
 
             /* Now do the composition on each pixel in this row. */
             outrow += startx;
-            for (; outrow < end_row; outrow += stepx)
+            for (; outrow < row_end; outrow += stepx)
             {
                png_byte alpha = inrow[channels];
 
@@ -3461,14 +3459,14 @@ png_image_read_background(png_voidp argument)
                      png_bytep inrow = png_voidcast(png_bytep,
                          display->local_row);
                      png_bytep outrow = first_row + y * row_step;
-                     png_const_bytep end_row = outrow + width;
+                     png_const_bytep row_end = outrow + width;
 
                      /* Read the row, which is packed: */
                      png_read_row(png_ptr, inrow, NULL);
 
                      /* Now do the composition on each pixel in this row. */
                      outrow += startx;
-                     for (; outrow < end_row; outrow += stepx)
+                     for (; outrow < row_end; outrow += stepx)
                      {
                         png_byte alpha = inrow[1];
 
@@ -3506,14 +3504,14 @@ png_image_read_background(png_voidp argument)
                      png_bytep inrow = png_voidcast(png_bytep,
                          display->local_row);
                      png_bytep outrow = first_row + y * row_step;
-                     png_const_bytep end_row = outrow + width;
+                     png_const_bytep row_end = outrow + width;
 
                      /* Read the row, which is packed: */
                      png_read_row(png_ptr, inrow, NULL);
 
                      /* Now do the composition on each pixel in this row. */
                      outrow += startx;
-                     for (; outrow < end_row; outrow += stepx)
+                     for (; outrow < row_end; outrow += stepx)
                      {
                         png_byte alpha = inrow[1];
 
@@ -3596,7 +3594,7 @@ png_image_read_background(png_voidp argument)
                {
                   png_const_uint_16p inrow;
                   png_uint_16p outrow = first_row + y * row_step;
-                  png_uint_16p end_row = outrow + width * outchannels;
+                  png_uint_16p row_end = outrow + width * outchannels;
 
                   /* Read the row, which is packed: */
                   png_read_row(png_ptr, png_voidcast(png_bytep,
@@ -3606,7 +3604,7 @@ png_image_read_background(png_voidp argument)
                   /* Now do the pre-multiplication on each pixel in this row.
                    */
                   outrow += startx;
-                  for (; outrow < end_row; outrow += stepx)
+                  for (; outrow < row_end; outrow += stepx)
                   {
                      png_uint_32 component = inrow[0];
                      png_uint_16 alpha = inrow[1];
@@ -4142,7 +4140,7 @@ png_image_finish_read(png_imagep image, png_const_colorp background,
             row_stride = (png_int_32)/*SAFE*/png_row_stride;
 
          if (row_stride < 0)
-            check = (png_uint_32)(-row_stride);
+            check = -(png_uint_32)row_stride;
 
          else
             check = (png_uint_32)row_stride;
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngrtran.c b/src/java.desktop/share/native/libsplashscreen/libpng/pngrtran.c
index fcce80da1cb..f0972ba9bef 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pngrtran.c
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngrtran.c
@@ -259,7 +259,7 @@ png_set_strip_alpha(png_structrp png_ptr)
  *
  * Terminology (assuming power law, "gamma", encodings):
  *    "screen" gamma: a power law imposed by the output device when digital
- *    samples are converted to visible light output.  The EOTF - volage to
+ *    samples are converted to visible light output.  The EOTF - voltage to
  *    luminance on output.
  *
  *    "file" gamma: a power law used to encode luminance levels from the input
@@ -524,6 +524,9 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
    if (png_rtran_ok(png_ptr, 0) == 0)
       return;
 
+   if (palette == NULL)
+      return;
+
    png_ptr->transformations |= PNG_QUANTIZE;
 
    if (full_quantize == 0)
@@ -840,7 +843,13 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
    }
    if (png_ptr->palette == NULL)
    {
-      png_ptr->palette = palette;
+      /* Allocate an owned copy rather than aliasing the caller's pointer,
+       * so that png_read_destroy can free png_ptr->palette unconditionally.
+       */
+      png_ptr->palette = png_voidcast(png_colorp, png_calloc(png_ptr,
+          PNG_MAX_PALETTE_LENGTH * (sizeof (png_color))));
+      memcpy(png_ptr->palette, palette, (unsigned int)num_palette *
+          (sizeof (png_color)));
    }
    png_ptr->num_palette = (png_uint_16)num_palette;
 
@@ -1393,7 +1402,7 @@ png_resolve_file_gamma(png_const_structrp png_ptr)
    if (file_gamma != 0)
       return file_gamma;
 
-   /* If png_reciprocal oveflows it returns 0 which indicates to the caller that
+   /* If png_reciprocal overflows, it returns 0, indicating to the caller that
     * there is no usable file gamma.  (The checks added to png_set_gamma and
     * png_set_alpha_mode should prevent a screen_gamma which would overflow.)
     */
@@ -2090,6 +2099,21 @@ png_read_transform_info(png_structrp png_ptr, png_inforp info_ptr)
 {
    png_debug(1, "in png_read_transform_info");
 
+   if (png_ptr->transformations != 0)
+   {
+      if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&
+          info_ptr->palette != NULL && png_ptr->palette != NULL)
+      {
+         /* Sync info_ptr->palette with png_ptr->palette.
+          * The function png_init_read_transformations may have modified
+          * png_ptr->palette in place (e.g. for gamma correction or for
+          * background compositing).
+          */
+         memcpy(info_ptr->palette, png_ptr->palette,
+             PNG_MAX_PALETTE_LENGTH * (sizeof (png_color)));
+      }
+   }
+
 #ifdef PNG_READ_EXPAND_SUPPORTED
    if ((png_ptr->transformations & PNG_EXPAND) != 0)
    {
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngrutil.c b/src/java.desktop/share/native/libsplashscreen/libpng/pngrutil.c
index 01bb0c8bedc..4712dfd418a 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pngrutil.c
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngrutil.c
@@ -465,7 +465,7 @@ png_inflate_claim(png_structrp png_ptr, png_uint_32 owner)
     * be gained by using this when it is known *if* the zlib stream itself does
     * not record the number; however, this is an illusion: the original writer
     * of the PNG may have selected a lower window size, and we really must
-    * follow that because, for systems with with limited capabilities, we
+    * follow that because, for systems with limited capabilities, we
     * would otherwise reject the application's attempts to use a smaller window
     * size (zlib doesn't have an interface to say "this or lower"!).
     *
@@ -1035,7 +1035,7 @@ png_handle_PLTE(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
     * in the case of an 8-bit display with a decoder which controls the palette.
     *
     * The alternative here is to ignore the error and store the palette anyway;
-    * destroying the tRNS will definately cause problems.
+    * destroying the tRNS will definitely cause problems.
     *
     * NOTE: the case of PNG_COLOR_TYPE_PALETTE need not be considered because
     * the png_handle_ routines for the three 'after PLTE' chunks tRNS, bKGD and
@@ -1082,19 +1082,6 @@ png_handle_PLTE(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
       /* A valid PLTE chunk has been read */
       png_ptr->mode |= PNG_HAVE_PLTE;
 
-      /* TODO: png_set_PLTE has the side effect of setting png_ptr->palette to
-       * its own copy of the palette.  This has the side effect that when
-       * png_start_row is called (this happens after any call to
-       * png_read_update_info) the info_ptr palette gets changed.  This is
-       * extremely unexpected and confusing.
-       *
-       * REVIEW: there have been consistent bugs in the past about gamma and
-       * similar transforms to colour mapped images being useless because the
-       * modified palette cannot be accessed because of the above.
-       *
-       * CONSIDER: Fix this by not sharing the palette in this way.  But does
-       * this completely fix the problem?
-       */
       png_set_PLTE(png_ptr, info_ptr, palette, num);
       return handled_ok;
    }
@@ -1296,7 +1283,7 @@ png_handle_cHRM(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
 
    /* png_set_cHRM may complain about some of the values but this doesn't matter
     * because it was a cHRM and it did have vaguely (if, perhaps, ridiculous)
-    * values.  Ridiculousity will be checked if the values are used later.
+    * values.  Ridiculosity will be checked if the values are used later.
     */
    png_set_cHRM_fixed(png_ptr, info_ptr, xy.whitex, xy.whitey, xy.redx, xy.redy,
          xy.greenx, xy.greeny, xy.bluex, xy.bluey);
@@ -1593,7 +1580,8 @@ static png_handle_result_code /* PRIVATE */
 png_handle_sPLT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
 /* Note: this does not properly handle chunks that are > 64K under DOS */
 {
-   png_bytep entry_start, buffer;
+   png_bytep buffer;
+   png_bytep entry_start;
    png_sPLT_t new_palette;
    png_sPLT_entryp pp;
    png_uint_32 data_length;
@@ -1800,10 +1788,6 @@ png_handle_tRNS(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
       return handled_error;
    }
 
-   /* TODO: this is a horrible side effect in the palette case because the
-    * png_struct ends up with a pointer to the tRNS buffer owned by the
-    * png_info.  Fix this.
-    */
    png_set_tRNS(png_ptr, info_ptr, readbuf, png_ptr->num_trans,
        &(png_ptr->trans_color));
    return handled_ok;
@@ -2062,7 +2046,7 @@ png_handle_eXIf(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
       return handled_error;
 
    /* PNGv3: the code used to check the byte order mark at the start for MM or
-    * II, however PNGv3 states that the the first 4 bytes should be checked.
+    * II, however PNGv3 states that the first 4 bytes should be checked.
     * The caller ensures that there are four bytes available.
     */
    {
@@ -2184,9 +2168,13 @@ png_handle_oFFs(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
 static png_handle_result_code /* PRIVATE */
 png_handle_pCAL(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
 {
+   png_bytep buffer;
+   png_bytep buf;
+   png_bytep endptr;
    png_int_32 X0, X1;
-   png_byte type, nparams;
-   png_bytep buffer, buf, units, endptr;
+   png_byte type;
+   png_byte nparams;
+   png_byte *units;
    png_charpp params;
    int i;
 
@@ -3040,7 +3028,7 @@ static const struct
    png_uint_32 max_length :12; /* Length min, max in bytes */
    png_uint_32 min_length :8;
       /* Length errors on critical chunks have special handling to preserve the
-       * existing behaviour in libpng 1.6.  Anciallary chunks are checked below
+       * existing behaviour in libpng 1.6.  Ancillary chunks are checked below
        * and produce a 'benign' error.
        */
    png_uint_32 pos_before :4; /* PNG_HAVE_ values chunk must precede */
@@ -3048,7 +3036,7 @@ static const struct
       /* NOTE: PLTE, tRNS and bKGD require special handling which depends on
        * the colour type of the base image.
        */
-   png_uint_32 multiple   :1; /* Multiple occurences permitted */
+   png_uint_32 multiple   :1; /* Multiple occurrences permitted */
       /* This is enabled for PLTE because PLTE may, in practice, be optional */
 }
 read_chunks[PNG_INDEX_unknown] =
@@ -3082,7 +3070,7 @@ read_chunks[PNG_INDEX_unknown] =
 #  define CDIHDR      13U,   13U,  hIHDR,     0,        0
 #  define CDPLTE  NoCheck,    0U,      0, hIHDR,        1
       /* PLTE errors are only critical for colour-map images, consequently the
-       * hander does all the checks.
+       * handler does all the checks.
        */
 #  define CDIDAT  NoCheck,    0U,  aIDAT, hIHDR,        1
 #  define CDIEND  NoCheck,    0U,      0, aIDAT,        0
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngset.c b/src/java.desktop/share/native/libsplashscreen/libpng/pngset.c
index 0b2844f1864..05d18cd06b7 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pngset.c
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngset.c
@@ -29,7 +29,7 @@
  * However, the following notice accompanied the original version of this
  * file and, per its terms, should not be removed:
  *
- * Copyright (c) 2018-2025 Cosmin Truta
+ * Copyright (c) 2018-2026 Cosmin Truta
  * Copyright (c) 1998-2018 Glenn Randers-Pehrson
  * Copyright (c) 1996-1997 Andreas Dilger
  * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -362,7 +362,8 @@ png_set_eXIf_1(png_const_structrp png_ptr, png_inforp info_ptr,
    png_debug1(1, "in %s storage function", "eXIf");
 
    if (png_ptr == NULL || info_ptr == NULL ||
-       (png_ptr->mode & PNG_WROTE_eXIf) != 0)
+       (png_ptr->mode & PNG_WROTE_eXIf) != 0 ||
+       exif == NULL)
       return;
 
    new_exif = png_voidcast(png_bytep, png_malloc_warn(png_ptr, num_exif));
@@ -417,7 +418,7 @@ png_set_hIST(png_const_structrp png_ptr, png_inforp info_ptr,
 
    png_debug1(1, "in %s storage function", "hIST");
 
-   if (png_ptr == NULL || info_ptr == NULL)
+   if (png_ptr == NULL || info_ptr == NULL || hist == NULL)
       return;
 
    if (info_ptr->num_palette == 0 || info_ptr->num_palette
@@ -804,28 +805,38 @@ png_set_PLTE(png_structrp png_ptr, png_inforp info_ptr,
       png_error(png_ptr, "Invalid palette");
    }
 
-   /* It may not actually be necessary to set png_ptr->palette here;
-    * we do it for backward compatibility with the way the png_handle_tRNS
-    * function used to do the allocation.
-    *
-    * 1.6.0: the above statement appears to be incorrect; something has to set
-    * the palette inside png_struct on read.
-    */
    png_free_data(png_ptr, info_ptr, PNG_FREE_PLTE, 0);
 
    /* Changed in libpng-1.2.1 to allocate PNG_MAX_PALETTE_LENGTH instead
     * of num_palette entries, in case of an invalid PNG file or incorrect
     * call to png_set_PLTE() with too-large sample values.
+    *
+    * Allocate independent buffers for info_ptr and png_ptr so that the
+    * lifetime of png_ptr->palette is decoupled from the lifetime of
+    * info_ptr->palette.  Previously, these two pointers were aliased,
+    * which caused a use-after-free vulnerability if png_free_data freed
+    * info_ptr->palette while png_ptr->palette was still in use by the
+    * row transform functions (e.g. png_do_expand_palette).
+    *
+    * Both buffers are allocated with png_calloc to zero-fill, because
+    * the ARM NEON palette riffle reads all 256 entries unconditionally,
+    * regardless of num_palette.
     */
+   png_free(png_ptr, png_ptr->palette);
    png_ptr->palette = png_voidcast(png_colorp, png_calloc(png_ptr,
        PNG_MAX_PALETTE_LENGTH * (sizeof (png_color))));
+   info_ptr->palette = png_voidcast(png_colorp, png_calloc(png_ptr,
+       PNG_MAX_PALETTE_LENGTH * (sizeof (png_color))));
+   png_ptr->num_palette = info_ptr->num_palette = (png_uint_16)num_palette;
 
    if (num_palette > 0)
+   {
+      memcpy(info_ptr->palette, palette, (unsigned int)num_palette *
+          (sizeof (png_color)));
       memcpy(png_ptr->palette, palette, (unsigned int)num_palette *
           (sizeof (png_color)));
+   }
 
-   info_ptr->palette = png_ptr->palette;
-   info_ptr->num_palette = png_ptr->num_palette = (png_uint_16)num_palette;
    info_ptr->free_me |= PNG_FREE_PLTE;
    info_ptr->valid |= PNG_INFO_PLTE;
 }
@@ -1183,28 +1194,40 @@ png_set_tRNS(png_structrp png_ptr, png_inforp info_ptr,
 
    if (trans_alpha != NULL)
    {
-       /* It may not actually be necessary to set png_ptr->trans_alpha here;
-        * we do it for backward compatibility with the way the png_handle_tRNS
-        * function used to do the allocation.
-        *
-        * 1.6.0: The above statement is incorrect; png_handle_tRNS effectively
-        * relies on png_set_tRNS storing the information in png_struct
-        * (otherwise it won't be there for the code in pngrtran.c).
-        */
-
        png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, 0);
 
        if (num_trans > 0 && num_trans <= PNG_MAX_PALETTE_LENGTH)
        {
-         /* Changed from num_trans to PNG_MAX_PALETTE_LENGTH in version 1.2.1 */
+          /* Allocate info_ptr's copy of the transparency data.
+           * Initialize all entries to fully opaque (0xff), then overwrite
+           * the first num_trans entries with the actual values.
+           */
           info_ptr->trans_alpha = png_voidcast(png_bytep,
               png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH));
+          memset(info_ptr->trans_alpha, 0xff, PNG_MAX_PALETTE_LENGTH);
           memcpy(info_ptr->trans_alpha, trans_alpha, (size_t)num_trans);
-
           info_ptr->free_me |= PNG_FREE_TRNS;
           info_ptr->valid |= PNG_INFO_tRNS;
+
+          /* Allocate an independent copy for png_struct, so that the
+           * lifetime of png_ptr->trans_alpha is decoupled from the
+           * lifetime of info_ptr->trans_alpha.  Previously these two
+           * pointers were aliased, which caused a use-after-free if
+           * png_free_data freed info_ptr->trans_alpha while
+           * png_ptr->trans_alpha was still in use by the row transform
+           * functions (e.g. png_do_expand_palette).
+           */
+          png_free(png_ptr, png_ptr->trans_alpha);
+          png_ptr->trans_alpha = png_voidcast(png_bytep,
+              png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH));
+          memset(png_ptr->trans_alpha, 0xff, PNG_MAX_PALETTE_LENGTH);
+          memcpy(png_ptr->trans_alpha, trans_alpha, (size_t)num_trans);
+       }
+       else
+       {
+          png_free(png_ptr, png_ptr->trans_alpha);
+          png_ptr->trans_alpha = NULL;
        }
-       png_ptr->trans_alpha = info_ptr->trans_alpha;
    }
 
    if (trans_color != NULL)
@@ -1902,7 +1925,7 @@ png_set_benign_errors(png_structrp png_ptr, int allowed)
 #endif /* BENIGN_ERRORS */
 
 #ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED
-   /* Whether to report invalid palette index; added at libng-1.5.10.
+   /* Whether to report invalid palette index; added at libpng-1.5.10.
     * It is possible for an indexed (color-type==3) PNG file to contain
     * pixels with invalid (out-of-range) indexes if the PLTE chunk has
     * fewer entries than the image's bit-depth would allow. We recover
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngstruct.h b/src/java.desktop/share/native/libsplashscreen/libpng/pngstruct.h
index 8edb4bc393a..f02365e8d8e 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pngstruct.h
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngstruct.h
@@ -29,7 +29,7 @@
  * However, the following notice accompanied the original version of this
  * file and, per its terms, should not be removed:
  *
- * Copyright (c) 2018-2025 Cosmin Truta
+ * Copyright (c) 2018-2026 Cosmin Truta
  * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
  * Copyright (c) 1996-1997 Andreas Dilger
  * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -135,7 +135,7 @@ typedef enum
  * TODO: C23: convert these macros to C23 inlines (which are static).
  */
 #define png_chunk_flag_from_index(i) (0x80000000U >> (31 - (i)))
-   /* The flag coresponding to the given png_index enum value.  This is defined
+   /* The flag corresponding to the given png_index enum value.  This is defined
     * for png_unknown as well (until it reaches the value 32) but this should
     * not be relied on.
     */
@@ -144,7 +144,7 @@ typedef enum
    (((png_ptr)->chunks & png_chunk_flag_from_index(i)) != 0)
    /* The chunk has been recorded in png_struct */
 
-#define png_file_add_chunk(pnt_ptr, i)\
+#define png_file_add_chunk(png_ptr, i)\
    ((void)((png_ptr)->chunks |= png_chunk_flag_from_index(i)))
    /* Record the chunk in the png_struct */
 
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngtrans.c b/src/java.desktop/share/native/libsplashscreen/libpng/pngtrans.c
index b9f6cb5d437..86ff2812e23 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pngtrans.c
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngtrans.c
@@ -29,7 +29,7 @@
  * However, the following notice accompanied the original version of this
  * file and, per its terms, should not be removed:
  *
- * Copyright (c) 2018-2024 Cosmin Truta
+ * Copyright (c) 2018-2026 Cosmin Truta
  * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
  * Copyright (c) 1996-1997 Andreas Dilger
  * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -113,9 +113,38 @@ png_set_shift(png_structrp png_ptr, png_const_color_8p true_bits)
 {
    png_debug(1, "in png_set_shift");
 
-   if (png_ptr == NULL)
+   if (png_ptr == NULL || true_bits == NULL)
       return;
 
+   /* Check the shift values before passing them on to png_do_shift. */
+   {
+      png_byte bit_depth = png_ptr->bit_depth;
+      int invalid = 0;
+
+      if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0)
+      {
+         if (true_bits->red == 0 || true_bits->red > bit_depth ||
+             true_bits->green == 0 || true_bits->green > bit_depth ||
+             true_bits->blue == 0 || true_bits->blue > bit_depth)
+            invalid = 1;
+      }
+      else
+      {
+         if (true_bits->gray == 0 || true_bits->gray > bit_depth)
+            invalid = 1;
+      }
+
+      if ((png_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0 &&
+          (true_bits->alpha == 0 || true_bits->alpha > bit_depth))
+         invalid = 1;
+
+      if (invalid)
+      {
+         png_app_error(png_ptr, "png_set_shift: invalid shift values");
+         return;
+      }
+   }
+
    png_ptr->transformations |= PNG_SHIFT;
    png_ptr->shift = *true_bits;
 }
@@ -486,10 +515,9 @@ png_do_packswap(png_row_infop row_info, png_bytep row)
 
    if (row_info->bit_depth < 8)
    {
+      png_const_bytep table;
       png_bytep rp;
-      png_const_bytep end, table;
-
-      end = row + row_info->rowbytes;
+      png_bytep row_end = row + row_info->rowbytes;
 
       if (row_info->bit_depth == 1)
          table = onebppswaptable;
@@ -503,7 +531,7 @@ png_do_packswap(png_row_infop row_info, png_bytep row)
       else
          return;
 
-      for (rp = row; rp < end; rp++)
+      for (rp = row; rp < row_end; rp++)
          *rp = table[*rp];
    }
 }

From ee0d6cd9aedc0d4c4232dccab310de188af4bebc Mon Sep 17 00:00:00 2001
From: Jatin Bhateja 
Date: Tue, 31 Mar 2026 05:52:16 +0000
Subject: [PATCH 111/359] 8378250: C2 VectorAPI : wrong result with MUL
 reduction at various AVX levels

Reviewed-by: epeter
---
 src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp |   9 +-
 .../vectorapi/TestMultiplyReductionByte.java  | 133 ++++++++++++++++++
 .../incubator/vector/ByteVector128Tests.java  |   4 +
 .../incubator/vector/ByteVector256Tests.java  |   4 +
 .../incubator/vector/ByteVector512Tests.java  |   4 +
 .../incubator/vector/ByteVector64Tests.java   |   4 +
 .../incubator/vector/ByteVectorMaxTests.java  |   4 +
 .../vector/DoubleVector128Tests.java          |   4 +
 .../vector/DoubleVector256Tests.java          |   4 +
 .../vector/DoubleVector512Tests.java          |   4 +
 .../incubator/vector/DoubleVector64Tests.java |   4 +
 .../vector/DoubleVectorMaxTests.java          |   4 +
 .../incubator/vector/FloatVector128Tests.java |   4 +
 .../incubator/vector/FloatVector256Tests.java |   4 +
 .../incubator/vector/FloatVector512Tests.java |   4 +
 .../incubator/vector/FloatVector64Tests.java  |   4 +
 .../incubator/vector/FloatVectorMaxTests.java |   4 +
 .../incubator/vector/IntVector128Tests.java   |   4 +
 .../incubator/vector/IntVector256Tests.java   |   4 +
 .../incubator/vector/IntVector512Tests.java   |   4 +
 .../incubator/vector/IntVector64Tests.java    |   4 +
 .../incubator/vector/IntVectorMaxTests.java   |   4 +
 .../incubator/vector/LongVector128Tests.java  |   4 +
 .../incubator/vector/LongVector256Tests.java  |   4 +
 .../incubator/vector/LongVector512Tests.java  |   4 +
 .../incubator/vector/LongVector64Tests.java   |   4 +
 .../incubator/vector/LongVectorMaxTests.java  |   4 +
 .../incubator/vector/ShortVector128Tests.java |   4 +
 .../incubator/vector/ShortVector256Tests.java |   4 +
 .../incubator/vector/ShortVector512Tests.java |   4 +
 .../incubator/vector/ShortVector64Tests.java  |   4 +
 .../incubator/vector/ShortVectorMaxTests.java |   4 +
 .../vector/templates/Unit-header.template     |   4 +
 33 files changed, 263 insertions(+), 3 deletions(-)
 create mode 100644 test/hotspot/jtreg/compiler/vectorapi/TestMultiplyReductionByte.java

diff --git a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp
index 23b9a77844d..f36c816dd5e 100644
--- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp
+++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp
@@ -2150,8 +2150,8 @@ void C2_MacroAssembler::mulreduce16B(int opcode, Register dst, Register src1, XM
   } else {
     pmovsxbw(vtmp2, src2);
     reduce8S(opcode, dst, src1, vtmp2, vtmp1, vtmp2);
-    pshufd(vtmp2, src2, 0x1);
-    pmovsxbw(vtmp2, src2);
+    pshufd(vtmp2, src2, 0xe);
+    pmovsxbw(vtmp2, vtmp2);
     reduce8S(opcode, dst, dst, vtmp2, vtmp1, vtmp2);
   }
 }
@@ -2160,7 +2160,7 @@ void C2_MacroAssembler::mulreduce32B(int opcode, Register dst, Register src1, XM
   if (UseAVX > 2 && VM_Version::supports_avx512bw()) {
     int vector_len = Assembler::AVX_512bit;
     vpmovsxbw(vtmp1, src2, vector_len);
-    reduce32S(opcode, dst, src1, vtmp1, vtmp1, vtmp2);
+    reduce32S(opcode, dst, src1, vtmp1, vtmp2, vtmp1);
   } else {
     assert(UseAVX >= 2,"Should not reach here.");
     mulreduce16B(opcode, dst, src1, src2, vtmp1, vtmp2);
@@ -2207,6 +2207,7 @@ void C2_MacroAssembler::reduce8S(int opcode, Register dst, Register src1, XMMReg
     }
     phaddw(vtmp1, src2);
   } else {
+    assert_different_registers(src2, vtmp1);
     pshufd(vtmp1, src2, 0xE);
     reduce_operation_128(T_SHORT, opcode, vtmp1, src2);
   }
@@ -2219,6 +2220,7 @@ void C2_MacroAssembler::reduce16S(int opcode, Register dst, Register src1, XMMRe
     vphaddw(vtmp2, src2, src2, vector_len);
     vpermq(vtmp2, vtmp2, 0xD8, vector_len);
   } else {
+    assert_different_registers(src2, vtmp2);
     vextracti128_high(vtmp2, src2);
     reduce_operation_128(T_SHORT, opcode, vtmp2, src2);
   }
@@ -2226,6 +2228,7 @@ void C2_MacroAssembler::reduce16S(int opcode, Register dst, Register src1, XMMRe
 }
 
 void C2_MacroAssembler::reduce32S(int opcode, Register dst, Register src1, XMMRegister src2, XMMRegister vtmp1, XMMRegister vtmp2) {
+  assert_different_registers(src2, vtmp1);
   int vector_len = Assembler::AVX_256bit;
   vextracti64x4_high(vtmp1, src2);
   reduce_operation_256(T_SHORT, opcode, vtmp1, vtmp1, src2);
diff --git a/test/hotspot/jtreg/compiler/vectorapi/TestMultiplyReductionByte.java b/test/hotspot/jtreg/compiler/vectorapi/TestMultiplyReductionByte.java
new file mode 100644
index 00000000000..13eafd8dc26
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/vectorapi/TestMultiplyReductionByte.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please 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 java.util.Arrays;
+
+import jdk.incubator.vector.ByteVector;
+import jdk.incubator.vector.VectorOperators;
+
+import jdk.test.lib.Asserts;
+import jdk.test.lib.Utils;
+
+/**
+ * @test
+ * @bug 8378250
+ * @summary Verify correctness of byte vector MUL reduction across all species.
+ *          A register aliasing bug in mulreduce32B caused the upper half of
+ *          sign-extended data to overwrite the source, producing wrong results
+ *          when most lanes are 1 and a single lane differs.
+ * @library /test/lib /
+ * @modules jdk.incubator.vector
+ * @run driver ${test.main.class}
+ */
+public class TestMultiplyReductionByte {
+
+    static byte[] input = new byte[64];
+
+    static int pos = Utils.getRandomInstance().nextInt(input.length);
+
+    static {
+        Arrays.fill(input, (byte) 1);
+        input[pos] = -3;
+    }
+
+    @Test
+    @IR(counts = {IRNode.MUL_REDUCTION_VI, ">=1"},
+        applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"},
+        applyIf = {"MaxVectorSize", ">=8"})
+    static byte testMulReduce64() {
+        return ByteVector.fromArray(ByteVector.SPECIES_64, input, 0)
+                         .reduceLanes(VectorOperators.MUL);
+    }
+
+    @Run(test = "testMulReduce64")
+    static void runMulReduce64() {
+        input[pos] = 1;
+        pos = (pos + 1) % ByteVector.SPECIES_64.length();
+        input[pos] = -3;
+        byte result = testMulReduce64();
+        Asserts.assertEquals((byte) -3, result, "MUL reduction (64-bit), pos=" + pos);
+    }
+
+    @Test
+    @IR(counts = {IRNode.MUL_REDUCTION_VI, ">=1"},
+        applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"},
+        applyIf = {"MaxVectorSize", ">=16"})
+    static byte testMulReduce128() {
+        return ByteVector.fromArray(ByteVector.SPECIES_128, input, 0)
+                         .reduceLanes(VectorOperators.MUL);
+    }
+
+    @Run(test = "testMulReduce128")
+    static void runMulReduce128() {
+        input[pos] = 1;
+        pos = (pos + 1) % ByteVector.SPECIES_128.length();
+        input[pos] = -3;
+        byte result = testMulReduce128();
+        Asserts.assertEquals((byte) -3, result, "MUL reduction (128-bit), pos=" + pos);
+    }
+
+    @Test
+    @IR(counts = {IRNode.MUL_REDUCTION_VI, ">=1"},
+        applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true"},
+        applyIf = {"MaxVectorSize", ">=32"})
+    static byte testMulReduce256() {
+        return ByteVector.fromArray(ByteVector.SPECIES_256, input, 0)
+                         .reduceLanes(VectorOperators.MUL);
+    }
+
+    @Run(test = "testMulReduce256")
+    static void runMulReduce256() {
+        input[pos] = 1;
+        pos = (pos + 1) % ByteVector.SPECIES_256.length();
+        input[pos] = -3;
+        byte result = testMulReduce256();
+        Asserts.assertEquals((byte) -3, result, "MUL reduction (256-bit), pos=" + pos);
+    }
+
+    @Test
+    @IR(counts = {IRNode.MUL_REDUCTION_VI, ">=1"},
+        applyIfCPUFeatureOr = {"avx512f", "true", "asimd", "true"},
+        applyIf = {"MaxVectorSize", ">=64"})
+    static byte testMulReduce512() {
+        return ByteVector.fromArray(ByteVector.SPECIES_512, input, 0)
+                         .reduceLanes(VectorOperators.MUL);
+    }
+
+    @Run(test = "testMulReduce512")
+    static void runMulReduce512() {
+        input[pos] = 1;
+        pos = (pos + 1) % ByteVector.SPECIES_512.length();
+        input[pos] = -3;
+        byte result = testMulReduce512();
+        Asserts.assertEquals((byte) -3, result, "MUL reduction (512-bit), pos=" + pos);
+    }
+
+    public static void main(String[] args) {
+        TestFramework.runWithFlags("--add-modules=jdk.incubator.vector");
+    }
+}
diff --git a/test/jdk/jdk/incubator/vector/ByteVector128Tests.java b/test/jdk/jdk/incubator/vector/ByteVector128Tests.java
index ca6fa537ac4..b605182e496 100644
--- a/test/jdk/jdk/incubator/vector/ByteVector128Tests.java
+++ b/test/jdk/jdk/incubator/vector/ByteVector128Tests.java
@@ -1114,6 +1114,10 @@ public class ByteVector128Tests extends AbstractVectorTest {
                 return fill(s * BUFFER_REPS,
                             i -> (((byte)(i + 1) == 0) ? 1 : (byte)(i + 1)));
             }),
+            withToString("byte[smallOddValue(i)]", (int s) -> {
+                return fill(s * BUFFER_REPS,
+                            i -> (byte)(i % 7 == 0 ? -3 : (i % 3 == 0 ? -1 : 1)));
+            }),
             withToString("byte[cornerCaseValue(i)]", (int s) -> {
                 return fill(s * BUFFER_REPS,
                             i -> cornerCaseValue(i));
diff --git a/test/jdk/jdk/incubator/vector/ByteVector256Tests.java b/test/jdk/jdk/incubator/vector/ByteVector256Tests.java
index 5c32d4a7f74..bc05a0bd6ca 100644
--- a/test/jdk/jdk/incubator/vector/ByteVector256Tests.java
+++ b/test/jdk/jdk/incubator/vector/ByteVector256Tests.java
@@ -1114,6 +1114,10 @@ public class ByteVector256Tests extends AbstractVectorTest {
                 return fill(s * BUFFER_REPS,
                             i -> (((byte)(i + 1) == 0) ? 1 : (byte)(i + 1)));
             }),
+            withToString("byte[smallOddValue(i)]", (int s) -> {
+                return fill(s * BUFFER_REPS,
+                            i -> (byte)(i % 7 == 0 ? -3 : (i % 3 == 0 ? -1 : 1)));
+            }),
             withToString("byte[cornerCaseValue(i)]", (int s) -> {
                 return fill(s * BUFFER_REPS,
                             i -> cornerCaseValue(i));
diff --git a/test/jdk/jdk/incubator/vector/ByteVector512Tests.java b/test/jdk/jdk/incubator/vector/ByteVector512Tests.java
index 094f3bbebdc..45038c53824 100644
--- a/test/jdk/jdk/incubator/vector/ByteVector512Tests.java
+++ b/test/jdk/jdk/incubator/vector/ByteVector512Tests.java
@@ -1114,6 +1114,10 @@ public class ByteVector512Tests extends AbstractVectorTest {
                 return fill(s * BUFFER_REPS,
                             i -> (((byte)(i + 1) == 0) ? 1 : (byte)(i + 1)));
             }),
+            withToString("byte[smallOddValue(i)]", (int s) -> {
+                return fill(s * BUFFER_REPS,
+                            i -> (byte)(i % 7 == 0 ? -3 : (i % 3 == 0 ? -1 : 1)));
+            }),
             withToString("byte[cornerCaseValue(i)]", (int s) -> {
                 return fill(s * BUFFER_REPS,
                             i -> cornerCaseValue(i));
diff --git a/test/jdk/jdk/incubator/vector/ByteVector64Tests.java b/test/jdk/jdk/incubator/vector/ByteVector64Tests.java
index e8ff81678cd..b350d0a8ee0 100644
--- a/test/jdk/jdk/incubator/vector/ByteVector64Tests.java
+++ b/test/jdk/jdk/incubator/vector/ByteVector64Tests.java
@@ -1114,6 +1114,10 @@ public class ByteVector64Tests extends AbstractVectorTest {
                 return fill(s * BUFFER_REPS,
                             i -> (((byte)(i + 1) == 0) ? 1 : (byte)(i + 1)));
             }),
+            withToString("byte[smallOddValue(i)]", (int s) -> {
+                return fill(s * BUFFER_REPS,
+                            i -> (byte)(i % 7 == 0 ? -3 : (i % 3 == 0 ? -1 : 1)));
+            }),
             withToString("byte[cornerCaseValue(i)]", (int s) -> {
                 return fill(s * BUFFER_REPS,
                             i -> cornerCaseValue(i));
diff --git a/test/jdk/jdk/incubator/vector/ByteVectorMaxTests.java b/test/jdk/jdk/incubator/vector/ByteVectorMaxTests.java
index c53710c3fdd..ba2307f15b1 100644
--- a/test/jdk/jdk/incubator/vector/ByteVectorMaxTests.java
+++ b/test/jdk/jdk/incubator/vector/ByteVectorMaxTests.java
@@ -1120,6 +1120,10 @@ public class ByteVectorMaxTests extends AbstractVectorTest {
                 return fill(s * BUFFER_REPS,
                             i -> (((byte)(i + 1) == 0) ? 1 : (byte)(i + 1)));
             }),
+            withToString("byte[smallOddValue(i)]", (int s) -> {
+                return fill(s * BUFFER_REPS,
+                            i -> (byte)(i % 7 == 0 ? -3 : (i % 3 == 0 ? -1 : 1)));
+            }),
             withToString("byte[cornerCaseValue(i)]", (int s) -> {
                 return fill(s * BUFFER_REPS,
                             i -> cornerCaseValue(i));
diff --git a/test/jdk/jdk/incubator/vector/DoubleVector128Tests.java b/test/jdk/jdk/incubator/vector/DoubleVector128Tests.java
index 1457e5a51ca..7bec91b698b 100644
--- a/test/jdk/jdk/incubator/vector/DoubleVector128Tests.java
+++ b/test/jdk/jdk/incubator/vector/DoubleVector128Tests.java
@@ -1239,6 +1239,10 @@ relativeError));
                 return fill(s * BUFFER_REPS,
                             i -> (((double)(i + 1) == 0) ? 1 : (double)(i + 1)));
             }),
+            withToString("double[smallOddValue(i)]", (int s) -> {
+                return fill(s * BUFFER_REPS,
+                            i -> (double)(i % 7 == 0 ? -3 : (i % 3 == 0 ? -1 : 1)));
+            }),
             withToString("double[0.01 + (i / (i + 1))]", (int s) -> {
                 return fill(s * BUFFER_REPS,
                             i -> (double)0.01 + ((double)i / (i + 1)));
diff --git a/test/jdk/jdk/incubator/vector/DoubleVector256Tests.java b/test/jdk/jdk/incubator/vector/DoubleVector256Tests.java
index e417abe52e6..3da554e67e5 100644
--- a/test/jdk/jdk/incubator/vector/DoubleVector256Tests.java
+++ b/test/jdk/jdk/incubator/vector/DoubleVector256Tests.java
@@ -1239,6 +1239,10 @@ relativeError));
                 return fill(s * BUFFER_REPS,
                             i -> (((double)(i + 1) == 0) ? 1 : (double)(i + 1)));
             }),
+            withToString("double[smallOddValue(i)]", (int s) -> {
+                return fill(s * BUFFER_REPS,
+                            i -> (double)(i % 7 == 0 ? -3 : (i % 3 == 0 ? -1 : 1)));
+            }),
             withToString("double[0.01 + (i / (i + 1))]", (int s) -> {
                 return fill(s * BUFFER_REPS,
                             i -> (double)0.01 + ((double)i / (i + 1)));
diff --git a/test/jdk/jdk/incubator/vector/DoubleVector512Tests.java b/test/jdk/jdk/incubator/vector/DoubleVector512Tests.java
index d23b2bf1511..6c060714da8 100644
--- a/test/jdk/jdk/incubator/vector/DoubleVector512Tests.java
+++ b/test/jdk/jdk/incubator/vector/DoubleVector512Tests.java
@@ -1239,6 +1239,10 @@ relativeError));
                 return fill(s * BUFFER_REPS,
                             i -> (((double)(i + 1) == 0) ? 1 : (double)(i + 1)));
             }),
+            withToString("double[smallOddValue(i)]", (int s) -> {
+                return fill(s * BUFFER_REPS,
+                            i -> (double)(i % 7 == 0 ? -3 : (i % 3 == 0 ? -1 : 1)));
+            }),
             withToString("double[0.01 + (i / (i + 1))]", (int s) -> {
                 return fill(s * BUFFER_REPS,
                             i -> (double)0.01 + ((double)i / (i + 1)));
diff --git a/test/jdk/jdk/incubator/vector/DoubleVector64Tests.java b/test/jdk/jdk/incubator/vector/DoubleVector64Tests.java
index d2aff0b7ea5..9e34cbc3a31 100644
--- a/test/jdk/jdk/incubator/vector/DoubleVector64Tests.java
+++ b/test/jdk/jdk/incubator/vector/DoubleVector64Tests.java
@@ -1239,6 +1239,10 @@ relativeError));
                 return fill(s * BUFFER_REPS,
                             i -> (((double)(i + 1) == 0) ? 1 : (double)(i + 1)));
             }),
+            withToString("double[smallOddValue(i)]", (int s) -> {
+                return fill(s * BUFFER_REPS,
+                            i -> (double)(i % 7 == 0 ? -3 : (i % 3 == 0 ? -1 : 1)));
+            }),
             withToString("double[0.01 + (i / (i + 1))]", (int s) -> {
                 return fill(s * BUFFER_REPS,
                             i -> (double)0.01 + ((double)i / (i + 1)));
diff --git a/test/jdk/jdk/incubator/vector/DoubleVectorMaxTests.java b/test/jdk/jdk/incubator/vector/DoubleVectorMaxTests.java
index 2684ae2d0c6..74be9b42a8b 100644
--- a/test/jdk/jdk/incubator/vector/DoubleVectorMaxTests.java
+++ b/test/jdk/jdk/incubator/vector/DoubleVectorMaxTests.java
@@ -1245,6 +1245,10 @@ relativeError));
                 return fill(s * BUFFER_REPS,
                             i -> (((double)(i + 1) == 0) ? 1 : (double)(i + 1)));
             }),
+            withToString("double[smallOddValue(i)]", (int s) -> {
+                return fill(s * BUFFER_REPS,
+                            i -> (double)(i % 7 == 0 ? -3 : (i % 3 == 0 ? -1 : 1)));
+            }),
             withToString("double[0.01 + (i / (i + 1))]", (int s) -> {
                 return fill(s * BUFFER_REPS,
                             i -> (double)0.01 + ((double)i / (i + 1)));
diff --git a/test/jdk/jdk/incubator/vector/FloatVector128Tests.java b/test/jdk/jdk/incubator/vector/FloatVector128Tests.java
index 151ea17a886..eb4b686d41f 100644
--- a/test/jdk/jdk/incubator/vector/FloatVector128Tests.java
+++ b/test/jdk/jdk/incubator/vector/FloatVector128Tests.java
@@ -1256,6 +1256,10 @@ relativeError));
                 return fill(s * BUFFER_REPS,
                             i -> (((float)(i + 1) == 0) ? 1 : (float)(i + 1)));
             }),
+            withToString("float[smallOddValue(i)]", (int s) -> {
+                return fill(s * BUFFER_REPS,
+                            i -> (float)(i % 7 == 0 ? -3 : (i % 3 == 0 ? -1 : 1)));
+            }),
             withToString("float[0.01 + (i / (i + 1))]", (int s) -> {
                 return fill(s * BUFFER_REPS,
                             i -> (float)0.01 + ((float)i / (i + 1)));
diff --git a/test/jdk/jdk/incubator/vector/FloatVector256Tests.java b/test/jdk/jdk/incubator/vector/FloatVector256Tests.java
index 5315b69a5b6..f00bf19d383 100644
--- a/test/jdk/jdk/incubator/vector/FloatVector256Tests.java
+++ b/test/jdk/jdk/incubator/vector/FloatVector256Tests.java
@@ -1256,6 +1256,10 @@ relativeError));
                 return fill(s * BUFFER_REPS,
                             i -> (((float)(i + 1) == 0) ? 1 : (float)(i + 1)));
             }),
+            withToString("float[smallOddValue(i)]", (int s) -> {
+                return fill(s * BUFFER_REPS,
+                            i -> (float)(i % 7 == 0 ? -3 : (i % 3 == 0 ? -1 : 1)));
+            }),
             withToString("float[0.01 + (i / (i + 1))]", (int s) -> {
                 return fill(s * BUFFER_REPS,
                             i -> (float)0.01 + ((float)i / (i + 1)));
diff --git a/test/jdk/jdk/incubator/vector/FloatVector512Tests.java b/test/jdk/jdk/incubator/vector/FloatVector512Tests.java
index 6a958511439..573bcc59c63 100644
--- a/test/jdk/jdk/incubator/vector/FloatVector512Tests.java
+++ b/test/jdk/jdk/incubator/vector/FloatVector512Tests.java
@@ -1256,6 +1256,10 @@ relativeError));
                 return fill(s * BUFFER_REPS,
                             i -> (((float)(i + 1) == 0) ? 1 : (float)(i + 1)));
             }),
+            withToString("float[smallOddValue(i)]", (int s) -> {
+                return fill(s * BUFFER_REPS,
+                            i -> (float)(i % 7 == 0 ? -3 : (i % 3 == 0 ? -1 : 1)));
+            }),
             withToString("float[0.01 + (i / (i + 1))]", (int s) -> {
                 return fill(s * BUFFER_REPS,
                             i -> (float)0.01 + ((float)i / (i + 1)));
diff --git a/test/jdk/jdk/incubator/vector/FloatVector64Tests.java b/test/jdk/jdk/incubator/vector/FloatVector64Tests.java
index b06dff18194..8244ffabb51 100644
--- a/test/jdk/jdk/incubator/vector/FloatVector64Tests.java
+++ b/test/jdk/jdk/incubator/vector/FloatVector64Tests.java
@@ -1256,6 +1256,10 @@ relativeError));
                 return fill(s * BUFFER_REPS,
                             i -> (((float)(i + 1) == 0) ? 1 : (float)(i + 1)));
             }),
+            withToString("float[smallOddValue(i)]", (int s) -> {
+                return fill(s * BUFFER_REPS,
+                            i -> (float)(i % 7 == 0 ? -3 : (i % 3 == 0 ? -1 : 1)));
+            }),
             withToString("float[0.01 + (i / (i + 1))]", (int s) -> {
                 return fill(s * BUFFER_REPS,
                             i -> (float)0.01 + ((float)i / (i + 1)));
diff --git a/test/jdk/jdk/incubator/vector/FloatVectorMaxTests.java b/test/jdk/jdk/incubator/vector/FloatVectorMaxTests.java
index 9b84e852c1c..30c470e05f4 100644
--- a/test/jdk/jdk/incubator/vector/FloatVectorMaxTests.java
+++ b/test/jdk/jdk/incubator/vector/FloatVectorMaxTests.java
@@ -1262,6 +1262,10 @@ relativeError));
                 return fill(s * BUFFER_REPS,
                             i -> (((float)(i + 1) == 0) ? 1 : (float)(i + 1)));
             }),
+            withToString("float[smallOddValue(i)]", (int s) -> {
+                return fill(s * BUFFER_REPS,
+                            i -> (float)(i % 7 == 0 ? -3 : (i % 3 == 0 ? -1 : 1)));
+            }),
             withToString("float[0.01 + (i / (i + 1))]", (int s) -> {
                 return fill(s * BUFFER_REPS,
                             i -> (float)0.01 + ((float)i / (i + 1)));
diff --git a/test/jdk/jdk/incubator/vector/IntVector128Tests.java b/test/jdk/jdk/incubator/vector/IntVector128Tests.java
index d62f5d8df00..2b36a2802eb 100644
--- a/test/jdk/jdk/incubator/vector/IntVector128Tests.java
+++ b/test/jdk/jdk/incubator/vector/IntVector128Tests.java
@@ -1104,6 +1104,10 @@ public class IntVector128Tests extends AbstractVectorTest {
                 return fill(s * BUFFER_REPS,
                             i -> (((int)(i + 1) == 0) ? 1 : (int)(i + 1)));
             }),
+            withToString("int[smallOddValue(i)]", (int s) -> {
+                return fill(s * BUFFER_REPS,
+                            i -> (int)(i % 7 == 0 ? -3 : (i % 3 == 0 ? -1 : 1)));
+            }),
             withToString("int[cornerCaseValue(i)]", (int s) -> {
                 return fill(s * BUFFER_REPS,
                             i -> cornerCaseValue(i));
diff --git a/test/jdk/jdk/incubator/vector/IntVector256Tests.java b/test/jdk/jdk/incubator/vector/IntVector256Tests.java
index bb2d1d717f4..9d4632b88dd 100644
--- a/test/jdk/jdk/incubator/vector/IntVector256Tests.java
+++ b/test/jdk/jdk/incubator/vector/IntVector256Tests.java
@@ -1104,6 +1104,10 @@ public class IntVector256Tests extends AbstractVectorTest {
                 return fill(s * BUFFER_REPS,
                             i -> (((int)(i + 1) == 0) ? 1 : (int)(i + 1)));
             }),
+            withToString("int[smallOddValue(i)]", (int s) -> {
+                return fill(s * BUFFER_REPS,
+                            i -> (int)(i % 7 == 0 ? -3 : (i % 3 == 0 ? -1 : 1)));
+            }),
             withToString("int[cornerCaseValue(i)]", (int s) -> {
                 return fill(s * BUFFER_REPS,
                             i -> cornerCaseValue(i));
diff --git a/test/jdk/jdk/incubator/vector/IntVector512Tests.java b/test/jdk/jdk/incubator/vector/IntVector512Tests.java
index 5ceba4e88ec..aa3c3eccf5b 100644
--- a/test/jdk/jdk/incubator/vector/IntVector512Tests.java
+++ b/test/jdk/jdk/incubator/vector/IntVector512Tests.java
@@ -1104,6 +1104,10 @@ public class IntVector512Tests extends AbstractVectorTest {
                 return fill(s * BUFFER_REPS,
                             i -> (((int)(i + 1) == 0) ? 1 : (int)(i + 1)));
             }),
+            withToString("int[smallOddValue(i)]", (int s) -> {
+                return fill(s * BUFFER_REPS,
+                            i -> (int)(i % 7 == 0 ? -3 : (i % 3 == 0 ? -1 : 1)));
+            }),
             withToString("int[cornerCaseValue(i)]", (int s) -> {
                 return fill(s * BUFFER_REPS,
                             i -> cornerCaseValue(i));
diff --git a/test/jdk/jdk/incubator/vector/IntVector64Tests.java b/test/jdk/jdk/incubator/vector/IntVector64Tests.java
index 9d3849a2c04..89247f9f932 100644
--- a/test/jdk/jdk/incubator/vector/IntVector64Tests.java
+++ b/test/jdk/jdk/incubator/vector/IntVector64Tests.java
@@ -1104,6 +1104,10 @@ public class IntVector64Tests extends AbstractVectorTest {
                 return fill(s * BUFFER_REPS,
                             i -> (((int)(i + 1) == 0) ? 1 : (int)(i + 1)));
             }),
+            withToString("int[smallOddValue(i)]", (int s) -> {
+                return fill(s * BUFFER_REPS,
+                            i -> (int)(i % 7 == 0 ? -3 : (i % 3 == 0 ? -1 : 1)));
+            }),
             withToString("int[cornerCaseValue(i)]", (int s) -> {
                 return fill(s * BUFFER_REPS,
                             i -> cornerCaseValue(i));
diff --git a/test/jdk/jdk/incubator/vector/IntVectorMaxTests.java b/test/jdk/jdk/incubator/vector/IntVectorMaxTests.java
index 6c671a81bf1..3272dbbb3de 100644
--- a/test/jdk/jdk/incubator/vector/IntVectorMaxTests.java
+++ b/test/jdk/jdk/incubator/vector/IntVectorMaxTests.java
@@ -1110,6 +1110,10 @@ public class IntVectorMaxTests extends AbstractVectorTest {
                 return fill(s * BUFFER_REPS,
                             i -> (((int)(i + 1) == 0) ? 1 : (int)(i + 1)));
             }),
+            withToString("int[smallOddValue(i)]", (int s) -> {
+                return fill(s * BUFFER_REPS,
+                            i -> (int)(i % 7 == 0 ? -3 : (i % 3 == 0 ? -1 : 1)));
+            }),
             withToString("int[cornerCaseValue(i)]", (int s) -> {
                 return fill(s * BUFFER_REPS,
                             i -> cornerCaseValue(i));
diff --git a/test/jdk/jdk/incubator/vector/LongVector128Tests.java b/test/jdk/jdk/incubator/vector/LongVector128Tests.java
index 49e2e1a0078..30f1ecc2bf4 100644
--- a/test/jdk/jdk/incubator/vector/LongVector128Tests.java
+++ b/test/jdk/jdk/incubator/vector/LongVector128Tests.java
@@ -1088,6 +1088,10 @@ public class LongVector128Tests extends AbstractVectorTest {
                 return fill(s * BUFFER_REPS,
                             i -> (((long)(i + 1) == 0) ? 1 : (long)(i + 1)));
             }),
+            withToString("long[smallOddValue(i)]", (int s) -> {
+                return fill(s * BUFFER_REPS,
+                            i -> (long)(i % 7 == 0 ? -3 : (i % 3 == 0 ? -1 : 1)));
+            }),
             withToString("long[cornerCaseValue(i)]", (int s) -> {
                 return fill(s * BUFFER_REPS,
                             i -> cornerCaseValue(i));
diff --git a/test/jdk/jdk/incubator/vector/LongVector256Tests.java b/test/jdk/jdk/incubator/vector/LongVector256Tests.java
index 84c8da4e800..6dd2f359742 100644
--- a/test/jdk/jdk/incubator/vector/LongVector256Tests.java
+++ b/test/jdk/jdk/incubator/vector/LongVector256Tests.java
@@ -1088,6 +1088,10 @@ public class LongVector256Tests extends AbstractVectorTest {
                 return fill(s * BUFFER_REPS,
                             i -> (((long)(i + 1) == 0) ? 1 : (long)(i + 1)));
             }),
+            withToString("long[smallOddValue(i)]", (int s) -> {
+                return fill(s * BUFFER_REPS,
+                            i -> (long)(i % 7 == 0 ? -3 : (i % 3 == 0 ? -1 : 1)));
+            }),
             withToString("long[cornerCaseValue(i)]", (int s) -> {
                 return fill(s * BUFFER_REPS,
                             i -> cornerCaseValue(i));
diff --git a/test/jdk/jdk/incubator/vector/LongVector512Tests.java b/test/jdk/jdk/incubator/vector/LongVector512Tests.java
index 00d8c4b010a..6347a1b53a2 100644
--- a/test/jdk/jdk/incubator/vector/LongVector512Tests.java
+++ b/test/jdk/jdk/incubator/vector/LongVector512Tests.java
@@ -1088,6 +1088,10 @@ public class LongVector512Tests extends AbstractVectorTest {
                 return fill(s * BUFFER_REPS,
                             i -> (((long)(i + 1) == 0) ? 1 : (long)(i + 1)));
             }),
+            withToString("long[smallOddValue(i)]", (int s) -> {
+                return fill(s * BUFFER_REPS,
+                            i -> (long)(i % 7 == 0 ? -3 : (i % 3 == 0 ? -1 : 1)));
+            }),
             withToString("long[cornerCaseValue(i)]", (int s) -> {
                 return fill(s * BUFFER_REPS,
                             i -> cornerCaseValue(i));
diff --git a/test/jdk/jdk/incubator/vector/LongVector64Tests.java b/test/jdk/jdk/incubator/vector/LongVector64Tests.java
index d4cdfe54ad2..0518c17b75f 100644
--- a/test/jdk/jdk/incubator/vector/LongVector64Tests.java
+++ b/test/jdk/jdk/incubator/vector/LongVector64Tests.java
@@ -1088,6 +1088,10 @@ public class LongVector64Tests extends AbstractVectorTest {
                 return fill(s * BUFFER_REPS,
                             i -> (((long)(i + 1) == 0) ? 1 : (long)(i + 1)));
             }),
+            withToString("long[smallOddValue(i)]", (int s) -> {
+                return fill(s * BUFFER_REPS,
+                            i -> (long)(i % 7 == 0 ? -3 : (i % 3 == 0 ? -1 : 1)));
+            }),
             withToString("long[cornerCaseValue(i)]", (int s) -> {
                 return fill(s * BUFFER_REPS,
                             i -> cornerCaseValue(i));
diff --git a/test/jdk/jdk/incubator/vector/LongVectorMaxTests.java b/test/jdk/jdk/incubator/vector/LongVectorMaxTests.java
index 597169b00f5..f5ab956b5a7 100644
--- a/test/jdk/jdk/incubator/vector/LongVectorMaxTests.java
+++ b/test/jdk/jdk/incubator/vector/LongVectorMaxTests.java
@@ -1094,6 +1094,10 @@ public class LongVectorMaxTests extends AbstractVectorTest {
                 return fill(s * BUFFER_REPS,
                             i -> (((long)(i + 1) == 0) ? 1 : (long)(i + 1)));
             }),
+            withToString("long[smallOddValue(i)]", (int s) -> {
+                return fill(s * BUFFER_REPS,
+                            i -> (long)(i % 7 == 0 ? -3 : (i % 3 == 0 ? -1 : 1)));
+            }),
             withToString("long[cornerCaseValue(i)]", (int s) -> {
                 return fill(s * BUFFER_REPS,
                             i -> cornerCaseValue(i));
diff --git a/test/jdk/jdk/incubator/vector/ShortVector128Tests.java b/test/jdk/jdk/incubator/vector/ShortVector128Tests.java
index 85e7d715182..40de51c90ab 100644
--- a/test/jdk/jdk/incubator/vector/ShortVector128Tests.java
+++ b/test/jdk/jdk/incubator/vector/ShortVector128Tests.java
@@ -1104,6 +1104,10 @@ public class ShortVector128Tests extends AbstractVectorTest {
                 return fill(s * BUFFER_REPS,
                             i -> (((short)(i + 1) == 0) ? 1 : (short)(i + 1)));
             }),
+            withToString("short[smallOddValue(i)]", (int s) -> {
+                return fill(s * BUFFER_REPS,
+                            i -> (short)(i % 7 == 0 ? -3 : (i % 3 == 0 ? -1 : 1)));
+            }),
             withToString("short[cornerCaseValue(i)]", (int s) -> {
                 return fill(s * BUFFER_REPS,
                             i -> cornerCaseValue(i));
diff --git a/test/jdk/jdk/incubator/vector/ShortVector256Tests.java b/test/jdk/jdk/incubator/vector/ShortVector256Tests.java
index df379b64e3a..c28dd34c8ef 100644
--- a/test/jdk/jdk/incubator/vector/ShortVector256Tests.java
+++ b/test/jdk/jdk/incubator/vector/ShortVector256Tests.java
@@ -1104,6 +1104,10 @@ public class ShortVector256Tests extends AbstractVectorTest {
                 return fill(s * BUFFER_REPS,
                             i -> (((short)(i + 1) == 0) ? 1 : (short)(i + 1)));
             }),
+            withToString("short[smallOddValue(i)]", (int s) -> {
+                return fill(s * BUFFER_REPS,
+                            i -> (short)(i % 7 == 0 ? -3 : (i % 3 == 0 ? -1 : 1)));
+            }),
             withToString("short[cornerCaseValue(i)]", (int s) -> {
                 return fill(s * BUFFER_REPS,
                             i -> cornerCaseValue(i));
diff --git a/test/jdk/jdk/incubator/vector/ShortVector512Tests.java b/test/jdk/jdk/incubator/vector/ShortVector512Tests.java
index ae5804c3688..703ef7d358b 100644
--- a/test/jdk/jdk/incubator/vector/ShortVector512Tests.java
+++ b/test/jdk/jdk/incubator/vector/ShortVector512Tests.java
@@ -1104,6 +1104,10 @@ public class ShortVector512Tests extends AbstractVectorTest {
                 return fill(s * BUFFER_REPS,
                             i -> (((short)(i + 1) == 0) ? 1 : (short)(i + 1)));
             }),
+            withToString("short[smallOddValue(i)]", (int s) -> {
+                return fill(s * BUFFER_REPS,
+                            i -> (short)(i % 7 == 0 ? -3 : (i % 3 == 0 ? -1 : 1)));
+            }),
             withToString("short[cornerCaseValue(i)]", (int s) -> {
                 return fill(s * BUFFER_REPS,
                             i -> cornerCaseValue(i));
diff --git a/test/jdk/jdk/incubator/vector/ShortVector64Tests.java b/test/jdk/jdk/incubator/vector/ShortVector64Tests.java
index 5f84682f02f..ea6846498a3 100644
--- a/test/jdk/jdk/incubator/vector/ShortVector64Tests.java
+++ b/test/jdk/jdk/incubator/vector/ShortVector64Tests.java
@@ -1104,6 +1104,10 @@ public class ShortVector64Tests extends AbstractVectorTest {
                 return fill(s * BUFFER_REPS,
                             i -> (((short)(i + 1) == 0) ? 1 : (short)(i + 1)));
             }),
+            withToString("short[smallOddValue(i)]", (int s) -> {
+                return fill(s * BUFFER_REPS,
+                            i -> (short)(i % 7 == 0 ? -3 : (i % 3 == 0 ? -1 : 1)));
+            }),
             withToString("short[cornerCaseValue(i)]", (int s) -> {
                 return fill(s * BUFFER_REPS,
                             i -> cornerCaseValue(i));
diff --git a/test/jdk/jdk/incubator/vector/ShortVectorMaxTests.java b/test/jdk/jdk/incubator/vector/ShortVectorMaxTests.java
index 5451ad6c50e..6a85da12054 100644
--- a/test/jdk/jdk/incubator/vector/ShortVectorMaxTests.java
+++ b/test/jdk/jdk/incubator/vector/ShortVectorMaxTests.java
@@ -1110,6 +1110,10 @@ public class ShortVectorMaxTests extends AbstractVectorTest {
                 return fill(s * BUFFER_REPS,
                             i -> (((short)(i + 1) == 0) ? 1 : (short)(i + 1)));
             }),
+            withToString("short[smallOddValue(i)]", (int s) -> {
+                return fill(s * BUFFER_REPS,
+                            i -> (short)(i % 7 == 0 ? -3 : (i % 3 == 0 ? -1 : 1)));
+            }),
             withToString("short[cornerCaseValue(i)]", (int s) -> {
                 return fill(s * BUFFER_REPS,
                             i -> cornerCaseValue(i));
diff --git a/test/jdk/jdk/incubator/vector/templates/Unit-header.template b/test/jdk/jdk/incubator/vector/templates/Unit-header.template
index e1434dccb2b..b87012a2181 100644
--- a/test/jdk/jdk/incubator/vector/templates/Unit-header.template
+++ b/test/jdk/jdk/incubator/vector/templates/Unit-header.template
@@ -1375,6 +1375,10 @@ relativeError));
                 return fill(s * BUFFER_REPS,
                             i -> ((($type$)(i + 1) == 0) ? 1 : ($type$)(i + 1)));
             }),
+            withToString("$type$[smallOddValue(i)]", (int s) -> {
+                return fill(s * BUFFER_REPS,
+                            i -> ($type$)(i % 7 == 0 ? -3 : (i % 3 == 0 ? -1 : 1)));
+            }),
 #if[FP]
             withToString("$type$[0.01 + (i / (i + 1))]", (int s) -> {
                 return fill(s * BUFFER_REPS,

From 4a335f878c87b75a111252fafa80dbb96c52259a Mon Sep 17 00:00:00 2001
From: Alan Bateman 
Date: Tue, 31 Mar 2026 06:56:56 +0000
Subject: [PATCH 112/359] 8381002: Thread dump should convert longs to json
 numbers if possible

Reviewed-by: kevinw, amenkov, sspitsyn, lmesnik
---
 .../classes/jdk/internal/vm/ThreadDumper.java |  69 ++++--
 .../doc-files/threadDump.schema.json          |  36 ++--
 .../crypto/provider/Cipher/HPKE/KAT9180.java  |  14 +-
 .../DumpThreadsFormat1.java                   |  97 +++++++++
 test/jdk/jdk/jfr/tool/TestPrintJSON.java      |   9 +-
 .../security/provider/acvp/ML_DSA_Test.java   |  28 +--
 .../security/provider/acvp/ML_KEM_Test.java   |  18 +-
 .../sun/security/provider/acvp/SHA_Test.java  |  26 +--
 test/lib/jdk/test/lib/json/JSONValue.java     | 197 ++++++++++++------
 .../jdk/test/lib/threaddump/ThreadDump.java   |  62 +++---
 10 files changed, 373 insertions(+), 183 deletions(-)
 create mode 100644 test/jdk/com/sun/management/HotSpotDiagnosticMXBean/DumpThreadsFormat1.java

diff --git a/src/java.base/share/classes/jdk/internal/vm/ThreadDumper.java b/src/java.base/share/classes/jdk/internal/vm/ThreadDumper.java
index 276c379a564..fa7d4bab076 100644
--- a/src/java.base/share/classes/jdk/internal/vm/ThreadDumper.java
+++ b/src/java.base/share/classes/jdk/internal/vm/ThreadDumper.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved.
  * 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,18 +250,43 @@ public class ThreadDumper {
         }
     }
 
+    /**
+     * JSON is schema-less and the thread dump format will evolve over time.
+     * {@code HotSpotDiagnosticMXBean.dumpThreads} links to a JSON file that documents
+     * the latest/current format. A system property can be used to generate the thread
+     * dump in older formats if necessary.
+     */
+    private static class JsonFormat {
+        private static final String JSON_FORMAT_VERSION_PROP =
+                "com.sun.management.HotSpotDiagnosticMXBean.dumpThreads.format";
+        static final int JSON_FORMAT_V1 = 1;
+        static final int JSON_FORMAT_V2 = 2;
+        private static final int JSON_FORMAT_LATEST = JSON_FORMAT_V2;
+        private static final int JSON_FORMAT;
+        static {
+            int ver = Integer.getInteger(JSON_FORMAT_VERSION_PROP, JSON_FORMAT_LATEST);
+            JSON_FORMAT = Math.clamp(ver, JSON_FORMAT_V1, JSON_FORMAT_LATEST);
+        }
+
+        static int formatVersion() {
+            return JSON_FORMAT;
+        }
+    }
+
     /**
      * Generate a thread dump to the given text stream in JSON format.
      * @throws UncheckedIOException if an I/O error occurs
      */
     private static void dumpThreadsToJson(TextWriter textWriter) {
-        var jsonWriter = new JsonWriter(textWriter);
-
+        int format = JsonFormat.formatVersion();
+        var jsonWriter = new JsonWriter(textWriter, (format == JsonFormat.JSON_FORMAT_V1));
         jsonWriter.startObject();  // top-level object
-
         jsonWriter.startObject("threadDump");
+        if (format > JsonFormat.JSON_FORMAT_V1) {
+            jsonWriter.writeProperty("formatVersion", format);
+        }
 
-        jsonWriter.writeProperty("processId", processId());
+        jsonWriter.writeLongProperty("processId", processId());
         jsonWriter.writeProperty("time", Instant.now());
         jsonWriter.writeProperty("runtimeVersion", Runtime.version());
 
@@ -284,7 +309,11 @@ public class ThreadDumper {
         jsonWriter.writeProperty("parent", container.parent());
 
         Thread owner = container.owner();
-        jsonWriter.writeProperty("owner", (owner != null) ? owner.threadId() : null);
+        if (owner != null) {
+            jsonWriter.writeLongProperty("owner", owner.threadId());
+        } else {
+            jsonWriter.writeProperty("owner", null);  // owner is not optional
+        }
 
         long threadCount = 0;
         jsonWriter.startArray("threads");
@@ -301,7 +330,7 @@ public class ThreadDumper {
         if (!ThreadContainers.trackAllThreads()) {
             threadCount = Long.max(threadCount, container.threadCount());
         }
-        jsonWriter.writeProperty("threadCount", threadCount);
+        jsonWriter.writeLongProperty("threadCount", threadCount);
 
         jsonWriter.endObject();
 
@@ -324,7 +353,7 @@ public class ThreadDumper {
         StackTraceElement[] stackTrace = snapshot.stackTrace();
 
         jsonWriter.startObject();
-        jsonWriter.writeProperty("tid", thread.threadId());
+        jsonWriter.writeLongProperty("tid", thread.threadId());
         jsonWriter.writeProperty("time", now);
         if (thread.isVirtual()) {
             jsonWriter.writeProperty("virtual", Boolean.TRUE);
@@ -339,7 +368,7 @@ public class ThreadDumper {
             jsonWriter.startObject("parkBlocker");
             jsonWriter.writeProperty("object", Objects.toIdentityString(parkBlocker));
             if (snapshot.parkBlockerOwner() instanceof Thread owner) {
-                jsonWriter.writeProperty("owner", owner.threadId());
+                jsonWriter.writeLongProperty("owner", owner.threadId());
             }
             jsonWriter.endObject();
         }
@@ -380,7 +409,7 @@ public class ThreadDumper {
 
         // thread identifier of carrier, when mounted
         if (thread.isVirtual() && snapshot.carrierThread() instanceof Thread carrier) {
-            jsonWriter.writeProperty("carrier", carrier.threadId());
+            jsonWriter.writeLongProperty("carrier", carrier.threadId());
         }
 
         jsonWriter.endObject();
@@ -411,10 +440,12 @@ public class ThreadDumper {
             }
         }
         private final Deque stack = new ArrayDeque<>();
+        private final boolean generateLongsAsString;
         private final TextWriter writer;
 
-        JsonWriter(TextWriter writer) {
+        JsonWriter(TextWriter writer, boolean generateLongsAsString) {
             this.writer = writer;
+            this.generateLongsAsString = generateLongsAsString;
         }
 
         private void indent() {
@@ -461,6 +492,7 @@ public class ThreadDumper {
          */
         void writeProperty(String name, Object obj) {
             Node node = stack.peek();
+            assert node != null;
             if (node.getAndIncrementPropertyCount() > 0) {
                 writer.println(",");
             }
@@ -469,8 +501,6 @@ public class ThreadDumper {
                 writer.print("\"" + name + "\": ");
             }
             switch (obj) {
-                // Long may be larger than safe range of JSON integer value
-                case Long   _  -> writer.print("\"" + obj + "\"");
                 case Number _  -> writer.print(obj);
                 case Boolean _ -> writer.print(obj);
                 case null      -> writer.print("null");
@@ -478,6 +508,19 @@ public class ThreadDumper {
             }
         }
 
+        /**
+         * Write a property with a long value. If the value is outside the "interop"
+         * range of IEEE-754 double-precision floating point (64-bit) then it is
+         * written as a string.
+         */
+        void writeLongProperty(String name, long value) {
+            if (generateLongsAsString || value < -0x1FFFFFFFFFFFFFL || value > 0x1FFFFFFFFFFFFFL) {
+                writeProperty(name, Long.toString(value));
+            } else {
+                writeProperty(name, value);
+            }
+        }
+
         /**
          * Write an unnamed property.
          */
diff --git a/src/jdk.management/share/classes/com/sun/management/doc-files/threadDump.schema.json b/src/jdk.management/share/classes/com/sun/management/doc-files/threadDump.schema.json
index 1da3e3941ef..30161b0bb74 100644
--- a/src/jdk.management/share/classes/com/sun/management/doc-files/threadDump.schema.json
+++ b/src/jdk.management/share/classes/com/sun/management/doc-files/threadDump.schema.json
@@ -4,8 +4,12 @@
     "threadDump": {
       "type": "object",
       "properties": {
+        "formatVersion": {
+          "type": "integer",
+          "description": "Format version (2)."
+        },
         "processId": {
-          "type": "string",
+          "type": "integer",
           "description": "The native process id of the Java virtual machine."
         },
         "time": {
@@ -28,18 +32,12 @@
                   "description": "The container name. The container name is unique."
                 },
                 "parent": {
-                  "type": [
-                    "string",
-                    "null"
-                  ],
+                  "type": [ "string", "null" ],
                   "description": "The parent container name or null for the root container."
                 },
                 "owner": {
-                  "type": [
-                    "string",
-                    "null"
-                  ],
-                  "description": "The thread identifier of the owner thread if owned."
+                  "type": [ "integer", "null" ],
+                  "description": "The thread identifier of the owner thread or null if no owner."
                 },
                 "threads": {
                   "type": "array",
@@ -49,7 +47,7 @@
                       "type": "object",
                       "properties": {
                         "tid": {
-                          "type": "string",
+                          "type": "integer",
                           "description": "The thread identifier."
                         },
                         "time": {
@@ -69,9 +67,7 @@
                           "description": "true for a virtual thread."
                         },
                         "parkBlocker": {
-                          "type": [
-                            "object"
-                          ],
+                          "type": "object",
                           "properties": {
                             "object": {
                               "type": "string",
@@ -79,7 +75,7 @@
                             }
                           },
                           "owner": {
-                            "type": "string",
+                            "type": "integer",
                             "description": "The thread identifier of the owner when the parkBlocker is an AbstractOwnableSynchronizer."
                           },
                           "required": [
@@ -117,10 +113,7 @@
                               "locks": {
                                 "type": "array",
                                 "items": {
-                                  "type": [
-                                    "string",
-                                    "null"
-                                  ],
+                                  "type": [ "string", "null" ],
                                   "description": "The object for which the monitor is owned by the thread, null if eliminated."
                                 }
                               }
@@ -132,7 +125,7 @@
                           }
                         },
                         "carrier":  {
-                          "type": "string",
+                          "type": "integer",
                           "description": "The thread identifier of the carrier thread if mounted."
                         }
                       },
@@ -147,7 +140,7 @@
                   ]
                 },
                 "threadCount": {
-                  "type": "string",
+                  "type": "integer",
                   "description": "The number of threads in the thread container."
                 }
               },
@@ -162,6 +155,7 @@
         }
       },
       "required": [
+        "formatVersion",
         "processId",
         "time",
         "runtimeVersion",
diff --git a/test/jdk/com/sun/crypto/provider/Cipher/HPKE/KAT9180.java b/test/jdk/com/sun/crypto/provider/Cipher/HPKE/KAT9180.java
index 024d5f977a7..9b6fad6a90d 100644
--- a/test/jdk/com/sun/crypto/provider/Cipher/HPKE/KAT9180.java
+++ b/test/jdk/com/sun/crypto/provider/Cipher/HPKE/KAT9180.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -82,12 +82,12 @@ public class KAT9180 {
         var c1 = Cipher.getInstance("HPKE");
         var c2 = Cipher.getInstance("HPKE");
         var ts = JSONValue.parse(new String(Files.readAllBytes(archivePath), StandardCharsets.UTF_8));
-        for (var tg : ts.asArray()) {
-            var mode = Integer.parseInt(tg.get("mode").asString());
+        for (var tg : ts.elements()) {
+            var mode = tg.get("mode").asInt();
             System.err.print('I');
-            var kem_id = Integer.parseInt(tg.get("kem_id").asString());
-            var kdf_id = Integer.parseInt(tg.get("kdf_id").asString());
-            var aead_id = Integer.parseInt(tg.get("aead_id").asString());
+            var kem_id = tg.get("kem_id").asInt();
+            var kdf_id = tg.get("kdf_id").asInt();
+            var aead_id = tg.get("aead_id").asInt();
             var ikmR = h.parseHex(tg.get("ikmR").asString());
             var ikmE = h.parseHex(tg.get("ikmE").asString());
             var info = h.parseHex(tg.get("info").asString());
@@ -117,7 +117,7 @@ public class KAT9180 {
             if (enc != null) {
                 System.err.print('e');
                 var count = 0;
-                for (var p : enc.asArray()) {
+                for (var p : enc.elements()) {
                     var aad = h.parseHex(p.get("aad").asString());
                     var pt = h.parseHex(p.get("pt").asString());
                     var ct = h.parseHex(p.get("ct").asString());
diff --git a/test/jdk/com/sun/management/HotSpotDiagnosticMXBean/DumpThreadsFormat1.java b/test/jdk/com/sun/management/HotSpotDiagnosticMXBean/DumpThreadsFormat1.java
new file mode 100644
index 00000000000..5bc9ae2918f
--- /dev/null
+++ b/test/jdk/com/sun/management/HotSpotDiagnosticMXBean/DumpThreadsFormat1.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please 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 8381169
+ * @summary Basic com.sun.management.HotSpotDiagnosticMXBean.dumpThreads generating a
+ *    format version 1 thread dump
+ * @modules jdk.management
+ * @library /test/lib
+ * @run junit/othervm -Dcom.sun.management.HotSpotDiagnosticMXBean.dumpThreads.format=1 ${test.main.class}
+ */
+
+import java.lang.management.ManagementFactory;
+import java.nio.file.Files;
+import java.nio.file.FileAlreadyExistsException;
+import java.nio.file.Path;
+import java.util.List;
+import com.sun.management.HotSpotDiagnosticMXBean;
+import com.sun.management.HotSpotDiagnosticMXBean.ThreadDumpFormat;
+import jdk.test.lib.json.JSONValue;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.BeforeAll;
+import static org.junit.jupiter.api.Assertions.*;
+
+class DumpThreadsFormat1 {
+    private static JSONValue threadDumpObj;
+
+    @BeforeAll
+    static void generateThreadDump() throws Exception {
+        Path dir = Path.of(".").toAbsolutePath();
+        Path file = Files.createTempFile(dir, "dump", ".json");
+        Files.delete(file);
+        var mbean = ManagementFactory.getPlatformMXBean(HotSpotDiagnosticMXBean.class);
+        mbean.dumpThreads(file.toString(), HotSpotDiagnosticMXBean.ThreadDumpFormat.JSON);
+        System.err.format("Dumped to %s%n", file.getFileName());
+        String json = Files.readString(file);
+        threadDumpObj = JSONValue.parse(json).get("threadDump");
+    }
+
+    /**
+     * Test that "formatVersion" is not present.
+     */
+    @Test
+    void testFormatVersion() {
+        threadDumpObj.getOrAbsent("formatVersion")
+                .ifPresent(_ -> { fail("formatVersion not expected"); });
+    }
+
+    /**
+     * Test "processId" is a string.
+     */
+    @Test
+    void testProcessId() {
+        String processId = "" + ProcessHandle.current().pid();
+        assertEquals(processId, threadDumpObj.get("processId").asString());
+    }
+
+    /**
+     * Test "tid" for current thread in root container is a string.
+     */
+    @Test
+    void testThreadId() throws Exception {
+        JSONValue rootContainerObj = threadDumpObj.get("threadContainers").element(0);
+        String name = rootContainerObj.get("container").asString();
+        assertEquals("", name);
+
+        String tid = "" + Thread.currentThread().threadId();
+        boolean found = rootContainerObj.get("threads")
+                .elements()
+                .stream()
+                .map(t -> t.get("tid").asString())
+                .anyMatch(tid::equals);
+        assertTrue(found, "Current thread not found");
+    }
+}
diff --git a/test/jdk/jdk/jfr/tool/TestPrintJSON.java b/test/jdk/jdk/jfr/tool/TestPrintJSON.java
index 3d79c75300f..2abbff68338 100644
--- a/test/jdk/jdk/jfr/tool/TestPrintJSON.java
+++ b/test/jdk/jdk/jfr/tool/TestPrintJSON.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,6 +28,7 @@ import java.time.OffsetDateTime;
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 
 import jdk.jfr.Timespan;
 import jdk.jfr.Timestamp;
@@ -62,7 +63,7 @@ public class TestPrintJSON {
 
         JSONValue o = JSONValue.parse(json);
         JSONValue recording = o.get("recording");
-        JSONArray jsonEvents = recording.get("events").asArray();
+        List jsonEvents = recording.get("events").elements();
         List events = RecordingFile.readAllEvents(recordingFile);
         Collections.sort(events, new EndTicksComparator());
         // Verify events are equal
@@ -79,7 +80,7 @@ public class TestPrintJSON {
     private static void assertEquals(Object jsonObject, Object jfrObject) throws Exception {
         // Check object
         if (jfrObject instanceof RecordedObject) {
-            JSONValue values = ((JSONValue) jsonObject).get("values");
+            Map values = ((JSONValue) jsonObject).get("values").members();
             RecordedObject recObject = (RecordedObject) jfrObject;
             Asserts.assertEquals(values.size(), recObject.getFields().size());
             for (ValueDescriptor v : recObject.getFields()) {
@@ -102,7 +103,7 @@ public class TestPrintJSON {
         // Check array
         if (jfrObject != null && jfrObject.getClass().isArray()) {
             Object[] jfrArray = (Object[]) jfrObject;
-            JSONArray jsArray = ((JSONArray) jsonObject);
+            List jsArray = ((JSONValue) jsonObject).elements();
             for (int i = 0; i < jfrArray.length; i++) {
                 assertEquals(jsArray.get(i), jfrArray[i]);
             }
diff --git a/test/jdk/sun/security/provider/acvp/ML_DSA_Test.java b/test/jdk/sun/security/provider/acvp/ML_DSA_Test.java
index f76f3d8b9a8..29b760e5d84 100644
--- a/test/jdk/sun/security/provider/acvp/ML_DSA_Test.java
+++ b/test/jdk/sun/security/provider/acvp/ML_DSA_Test.java
@@ -63,12 +63,12 @@ public class ML_DSA_Test {
         var f = p == null
                 ? KeyFactory.getInstance("ML-DSA")
                 : KeyFactory.getInstance("ML-DSA", p);
-        for (var t : kat.get("testGroups").asArray()) {
+        for (var t : kat.get("testGroups").elements()) {
             var pname = t.get("parameterSet").asString();
             var np = genParams(pname);
             System.out.println(">> " + pname);
-            for (var c : t.get("tests").asArray()) {
-                System.out.print(c.get("tcId").asString() + " ");
+            for (var c : t.get("tests").elements()) {
+                System.out.print(c.get("tcId").asInt() + " ");
                 var seed = toByteArray(c.get("seed").asString());
                 g.initialize(np, new FixedSecureRandom(seed));
                 var kp = g.generateKeyPair();
@@ -85,7 +85,7 @@ public class ML_DSA_Test {
         var s = p == null
                 ? Signature.getInstance("ML-DSA")
                 : Signature.getInstance("ML-DSA", p);
-        for (var t : kat.get("testGroups").asArray()) {
+        for (var t : kat.get("testGroups").elements()) {
             var pname = t.get("parameterSet").asString();
             System.out.println(">> " + pname + " sign");
             var det = t.get("deterministic").asBoolean();
@@ -97,14 +97,15 @@ public class ML_DSA_Test {
             if (t.get("externalMu").asBoolean()) {
                 continue; // Not supported
             }
-            for (var c : t.get("tests").asArray()) {
-                var cstr = c.get("context");
-                var ctxt = cstr == null ? new byte[0] : toByteArray(cstr.asString());
+            for (var c : t.get("tests").elements()) {
+                var ctxt =  c.getOrAbsent("context")
+                        .map(v -> toByteArray(v.asString()))
+                        .orElse(new byte[0]);
                 var hashAlg = c.get("hashAlg").asString();
                 if (!hashAlg.equals("none") || ctxt.length != 0) {
                     continue; // Not supported
                 }
-                System.out.print(Integer.parseInt(c.get("tcId").asString()) + " ");
+                System.out.print(c.get("tcId").asInt() + " ");
                 var sk = new PrivateKey() {
                     public String getAlgorithm() { return pname; }
                     public String getFormat() { return "RAW"; }
@@ -129,7 +130,7 @@ public class ML_DSA_Test {
         var s = p == null
                 ? Signature.getInstance("ML-DSA")
                 : Signature.getInstance("ML-DSA", p);
-        for (var t : kat.get("testGroups").asArray()) {
+        for (var t : kat.get("testGroups").elements()) {
             var pname = t.get("parameterSet").asString();
             System.out.println(">> " + pname + " verify");
 
@@ -143,14 +144,15 @@ public class ML_DSA_Test {
                 continue; // Not supported
             }
 
-            for (var c : t.get("tests").asArray()) {
-                var cstr = c.get("context");
-                var ctxt = cstr == null ? new byte[0] : toByteArray(cstr.asString());
+            for (var c : t.get("tests").elements()) {
+                var ctxt =  c.getOrAbsent("context")
+                        .map(v -> toByteArray(v.asString()))
+                        .orElse(new byte[0]);
                 var hashAlg = c.get("hashAlg").asString();
                 if (!hashAlg.equals("none") || ctxt.length != 0) {
                     continue; // Not supported
                 }
-                System.out.print(c.get("tcId").asString() + " ");
+                System.out.print(c.get("tcId").asInt() + " ");
                 var pk = new PublicKey() {
                     public String getAlgorithm() { return pname; }
                     public String getFormat() { return "RAW"; }
diff --git a/test/jdk/sun/security/provider/acvp/ML_KEM_Test.java b/test/jdk/sun/security/provider/acvp/ML_KEM_Test.java
index 35c1ce611da..5d969bc90ed 100644
--- a/test/jdk/sun/security/provider/acvp/ML_KEM_Test.java
+++ b/test/jdk/sun/security/provider/acvp/ML_KEM_Test.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved.
  * 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,12 +61,12 @@ public class ML_KEM_Test {
         var f = p == null
                 ? KeyFactory.getInstance("ML-KEM")
                 : KeyFactory.getInstance("ML-KEM", p);
-        for (var t : kat.get("testGroups").asArray()) {
+        for (var t : kat.get("testGroups").elements()) {
             var pname = t.get("parameterSet").asString();
             var np = genParams(pname);
             System.out.println(">> " + pname);
-            for (var c : t.get("tests").asArray()) {
-                System.out.print(c.get("tcId").asString() + " ");
+            for (var c : t.get("tests").elements()) {
+                System.out.print(c.get("tcId").asInt() + " ");
                 var seed = toByteArray(c.get("d").asString() + c.get("z").asString());
                 g.initialize(np, new FixedSecureRandom(seed));
                 var kp = g.generateKeyPair();
@@ -84,13 +84,13 @@ public class ML_KEM_Test {
         var g = p == null
                 ? KEM.getInstance("ML-KEM")
                 : KEM.getInstance("ML-KEM", p);
-        for (var t : kat.get("testGroups").asArray()) {
+        for (var t : kat.get("testGroups").elements()) {
             var pname = t.get("parameterSet").asString();
             var function = t.get("function").asString();
             System.out.println(">> " + pname + " " + function);
             if (function.equals("encapsulation")) {
-                for (var c : t.get("tests").asArray()) {
-                    System.out.print(c.get("tcId").asString() + " ");
+                for (var c : t.get("tests").elements()) {
+                    System.out.print(c.get("tcId").asInt() + " ");
                     var ek = new PublicKey() {
                         public String getAlgorithm() { return pname; }
                         public String getFormat() { return "RAW"; }
@@ -111,8 +111,8 @@ public class ML_KEM_Test {
                     public String getFormat() { return "RAW"; }
                     public byte[] getEncoded() { return oct(toByteArray(t.get("dk").asString())); }
                 };
-                for (var c : t.get("tests").asArray()) {
-                    System.out.print(c.get("tcId").asString() + " ");
+                for (var c : t.get("tests").elements()) {
+                    System.out.print(c.get("tcId").asInt() + " ");
                     var d = g.newDecapsulator(dk);
                     var k = d.decapsulate(toByteArray(c.get("c").asString()));
                     Asserts.assertEqualsByteArray(toByteArray(c.get("k").asString()), k.getEncoded());
diff --git a/test/jdk/sun/security/provider/acvp/SHA_Test.java b/test/jdk/sun/security/provider/acvp/SHA_Test.java
index 4a64fb00c8c..9f68a583173 100644
--- a/test/jdk/sun/security/provider/acvp/SHA_Test.java
+++ b/test/jdk/sun/security/provider/acvp/SHA_Test.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -37,14 +37,14 @@ public class SHA_Test {
         if (alg.startsWith("SHA2-")) alg = "SHA-" + alg.substring(5);
         var md = provider == null ? MessageDigest.getInstance(alg)
                 : MessageDigest.getInstance(alg, provider);
-        for (var t : kat.get("testGroups").asArray()) {
+        for (var t : kat.get("testGroups").elements()) {
             var testType = t.get("testType").asString();
             switch (testType) {
                 case "AFT" -> {
-                    for (var c : t.get("tests").asArray()) {
-                        System.out.print(c.get("tcId").asString() + " ");
+                    for (var c : t.get("tests").elements()) {
+                        System.out.print(c.get("tcId").asInt() + " ");
                         var msg = toByteArray(c.get("msg").asString());
-                        var len = Integer.parseInt(c.get("len").asString());
+                        var len = c.get("len").asInt();
                         if (msg.length * 8 == len) {
                             Asserts.assertEqualsByteArray(
                                     toByteArray(c.get("md").asString()), md.digest(msg));
@@ -56,12 +56,12 @@ public class SHA_Test {
                 case "MCT" -> {
                     var mctVersion = t.get("mctVersion").asString();
                     var trunc = mctVersion.equals("alternate");
-                    for (var c : t.get("tests").asArray()) {
-                        System.out.print(c.get("tcId").asString() + " ");
+                    for (var c : t.get("tests").elements()) {
+                        System.out.print(c.get("tcId").asInt() + " ");
                         var SEED = toByteArray(c.get("msg").asString());
-                        var INITIAL_SEED_LENGTH = Integer.parseInt(c.get("len").asString());
+                        var INITIAL_SEED_LENGTH = c.get("len").asInt();
                         if (SEED.length * 8 == INITIAL_SEED_LENGTH) {
-                            for (var r : c.get("resultsArray").asArray()) {
+                            for (var r : c.get("resultsArray").elements()) {
                                 if (alg.startsWith("SHA3-")) {
                                     var MD = SEED;
                                     for (var i = 0; i < 1000; i++) {
@@ -99,12 +99,12 @@ public class SHA_Test {
                     }
                 }
                 case "LDT" -> {
-                    for (var c : t.get("tests").asArray()) {
-                        System.out.print(c.get("tcId").asString() + " ");
+                    for (var c : t.get("tests").elements()) {
+                        System.out.print(c.get("tcId").asInt() + " ");
                         var lm = c.get("largeMsg");
                         var ct = toByteArray(lm.get("content").asString());
-                        var flen = Long.parseLong(lm.get("fullLength").asString());
-                        var clen = Long.parseLong(lm.get("contentLength").asString());
+                        var flen = lm.get("fullLength").asLong();
+                        var clen = lm.get("contentLength").asLong();
                         var cc = 0L;
                         while (cc < flen) {
                             md.update(ct);
diff --git a/test/lib/jdk/test/lib/json/JSONValue.java b/test/lib/jdk/test/lib/json/JSONValue.java
index 72ed2fd917c..3ac6441b4c0 100644
--- a/test/lib/jdk/test/lib/json/JSONValue.java
+++ b/test/lib/jdk/test/lib/json/JSONValue.java
@@ -25,47 +25,55 @@ package jdk.test.lib.json;
 import java.math.BigInteger;
 import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Objects;
 import java.util.Optional;
 
-public interface JSONValue {
+public sealed interface JSONValue
+        permits JSONValue.JSONObject, JSONValue.JSONArray, JSONValue.JSONString,
+                JSONValue.JSONNumber, JSONValue.JSONBoolean, JSONValue.JSONNull {
 
     public final class JSONObject implements JSONValue {
-        private final Map value;
+        private final Map members;
 
-        public JSONObject(Map value) {
-            this.value = value;
+        private JSONObject(Map members) {
+            this.members = Map.copyOf(members);
         }
 
         @Override
-        public JSONObject asObject() {
-            return this;
-        }
-
-        public JSONValue get(String k) {
-            return value.get(k);
+        public JSONValue get(String name) {
+            JSONValue v = members.get(name);
+            if (v == null) {
+                throw new NoSuchElementException("member " + name + " does not exist");
+            }
+            return v;
         }
 
         @Override
-        public int size() {
-            return value.size();
+        public Optional getOrAbsent(String name) {
+            return Optional.ofNullable(members.get(name));
+        }
+
+        @Override
+        public Map members() {
+            return members;
         }
 
         @Override
         public String toString() {
             var builder = new StringBuilder();
             builder.append("{");
-            for (var key : value.keySet()) {
+            for (String key : members.keySet()) {
                 builder.append("\"");
                 builder.append(key);
                 builder.append("\":");
-                builder.append(value.get(key).toString());
+                builder.append(members.get(key).toString());
                 builder.append(",");
             }
 
-            var end = builder.length() - 1;
+            int end = builder.length() - 1;
             if (builder.charAt(end) == ',') {
                 builder.deleteCharAt(end);
             }
@@ -73,13 +81,17 @@ public interface JSONValue {
             builder.append("}");
             return builder.toString();
         }
+
+        public static JSONObject of(Map members) {
+            return new JSONObject(members);
+        }
     }
 
     public final class JSONString implements JSONValue {
         private final String value;
 
-        public JSONString(String value) {
-            this.value = value;
+        private JSONString(String value) {
+            this.value = Objects.requireNonNull(value);
         }
 
         @Override
@@ -129,26 +141,17 @@ public interface JSONValue {
             builder.append("\"");
             return builder.toString();
         }
+
+        public static JSONString of(String value) {
+            return new JSONString(value);
+        }
     }
 
-    public final class JSONArray implements JSONValue, Iterable {
-        private final List values;
+    public final class JSONArray implements JSONValue {
+        private final List elements;
 
-        public JSONArray(List array) {
-            this.values = array;
-        }
-
-        @Override
-        public JSONArray asArray() {
-            return this;
-        }
-
-        public JSONValue get(int i) {
-            return values.get(i);
-        }
-
-        public int size() {
-            return values.size();
+        JSONArray(List elements) {
+            this.elements = List.copyOf(elements);
         }
 
         @Override
@@ -156,9 +159,10 @@ public interface JSONValue {
             var builder = new StringBuilder();
 
             builder.append("[");
-            for (var i = 0; i < size(); i++) {
-                builder.append(get(i).toString());
-                if (i != (size() - 1)) {
+            int size = elements.size();
+            for (int i = 0; i < size; i++) {
+                builder.append(elements.get(i).toString());
+                if (i != (size - 1)) {
                     builder.append(",");
                 }
             }
@@ -167,13 +171,61 @@ public interface JSONValue {
         }
 
         @Override
-        public Iterator iterator() {
-            return values.iterator();
+        public List elements() {
+            return elements;
         }
 
         @Override
-        public List elements() {
-            return List.copyOf(values);
+        public JSONValue element(int index) {
+            return elements.get(index);
+        }
+
+        public static JSONArray of(List elements) {
+            return new JSONArray(elements);
+        }
+    }
+
+    public final class JSONNumber implements JSONValue {
+        private final String value;
+
+        private JSONNumber(String value) {
+            this.value = Objects.requireNonNull(value);
+        }
+
+        @Override
+        public int asInt() {
+            return Integer.parseInt(value);
+        }
+
+        @Override
+        public long asLong() {
+            return Long.parseLong(value);
+        }
+
+        @Override
+        public double asDouble() {
+            return Double.parseDouble(value);
+        }
+
+        @Override
+        public String toString() {
+            return value;
+        }
+
+        public static JSONNumber of(String value) {
+            return new JSONNumber(value);
+        }
+
+        public static JSONNumber of(int value) {
+            return of(String.valueOf(value));
+        }
+
+        public static JSONNumber of(long value) {
+            return of(String.valueOf(value));
+        }
+
+        public static JSONNumber of(double value) {
+            return of(String.valueOf(value));
         }
     }
 
@@ -367,11 +419,10 @@ public interface JSONValue {
             var value = builder.toString();
             if (isInteger) {
                 new BigInteger(value);
-                return new JSONString(value);
             } else {
                 Double.parseDouble(value);
-                return new JSONString(value);
             }
+            return JSONNumber.of(value);
         }
 
         private JSONString parseString() {
@@ -422,7 +473,7 @@ public interface JSONValue {
             }
 
             advance(); // step beyond closing "
-            return new JSONString(builder.toString());
+            return JSONString.of(builder.toString());
         }
 
         private JSONArray parseArray() {
@@ -445,7 +496,7 @@ public interface JSONValue {
             }
 
             advance(); // step beyond closing ']'
-            return new JSONArray(list);
+            return JSONArray.of(list);
         }
 
         public JSONNull parseNull() {
@@ -486,7 +537,7 @@ public interface JSONValue {
             }
 
             advance(); // step beyond '}'
-            return new JSONObject(map);
+            return JSONObject.of(map);
         }
 
         private boolean isDigit(char c) {
@@ -574,43 +625,51 @@ public interface JSONValue {
         }
     }
 
-    public static JSONValue parse(String s) {
+    static JSONValue parse(String s) {
         return new JSONParser().parse(s);
     }
 
-    default int size() {
-        throw new UnsupportedOperationException("Size operation unsupported");
+    default JSONValue get(String name) {
+        throw new UnsupportedOperationException("Unsupported conversion to object");
+    }
+
+    default Optional getOrAbsent(String name) {
+        throw new UnsupportedOperationException("Unsupported conversion to object");
+    }
+
+    default Optional valueOrNull() {
+        return Optional.of(this);
+    }
+
+    default Map members() {
+        throw new UnsupportedOperationException("Unsupported conversion to object");
     }
 
     default List elements() {
         throw new UnsupportedOperationException("Unsupported conversion to array");
     }
 
-    default String asString() {
-        throw new UnsupportedOperationException("Unsupported conversion to String");
-    }
-
-    default JSONArray asArray() {
+    default JSONValue element(int index) {
         throw new UnsupportedOperationException("Unsupported conversion to array");
     }
 
-    default JSONObject asObject() {
-        throw new UnsupportedOperationException("Unsupported conversion to object");
+    default String asString() {
+        throw new UnsupportedOperationException("Unsupported conversion to string");
+    }
+
+    default int asInt() {
+        throw new UnsupportedOperationException("Unsupported conversion to number");
+    }
+
+    default long asLong() {
+        throw new UnsupportedOperationException("Unsupported conversion to number");
+    }
+
+    default double asDouble() {
+        throw new UnsupportedOperationException("Unsupported conversion to number");
     }
 
     default boolean asBoolean() {
         throw new UnsupportedOperationException("Unsupported conversion to boolean");
     }
-
-    default JSONValue get(String field) {
-        return asObject().get(field);
-    }
-
-    default Optional getOrAbsent(String field) {
-        return Optional.ofNullable(get(field));
-    }
-
-    default Optional valueOrNull() {
-        return Optional.of(this);
-    }
 }
diff --git a/test/lib/jdk/test/lib/threaddump/ThreadDump.java b/test/lib/jdk/test/lib/threaddump/ThreadDump.java
index 972d46675f4..77dd3dd8c03 100644
--- a/test/lib/jdk/test/lib/threaddump/ThreadDump.java
+++ b/test/lib/jdk/test/lib/threaddump/ThreadDump.java
@@ -50,9 +50,10 @@ import jdk.test.lib.json.JSONValue;
  * 
{@code
  * {
  *   "threadDump": {
- *     "processId": "63406",
- *     "time": "2022-05-20T07:37:16.308017Z",
- *     "runtimeVersion": "19",
+ *     "formatVersion": 2,
+ *     "processId": 63406,
+ *     "time": "2026-03-25T09:20:08.591503Z",
+ *     "runtimeVersion": "27",
  *     "threadContainers": [
  *       {
  *         "container": "",
@@ -60,12 +61,12 @@ import jdk.test.lib.json.JSONValue;
  *         "owner": null,
  *         "threads": [
  *          {
- *            "tid": "1",
+ *            "tid": 1,
  *            "name": "main",
  *            "stack": [...]
  *          },
  *          {
- *            "tid": "8",
+ *            "tid": 8,
  *            "name": "Reference Handler",
  *            "state": "RUNNABLE",
  *            "stack": [
@@ -80,21 +81,21 @@ import jdk.test.lib.json.JSONValue;
  *          {"name": "Monitor Ctrl-Break"...},
  *          {"name": "Notification Thread"...}
  *         ],
- *         "threadCount": "7"
+ *         "threadCount": 7
  *       },
  *       {
  *         "container": "ForkJoinPool.commonPool\/jdk.internal.vm.SharedThreadContainer@56aac163",
  *         "parent": "",
  *         "owner": null,
  *         "threads": [...],
- *         "threadCount": "1"
+ *         "threadCount": 1
  *       },
  *       {
  *         "container": "java.util.concurrent.ThreadPoolExecutor@20322d26\/jdk.internal.vm.SharedThreadContainer@184f6be2",
  *         "parent": "",
  *         "owner": null,
  *         "threads": [...],
- *         "threadCount": "1"
+ *         "threadCount": 1
  *       }
  *     ]
  *   }
@@ -131,20 +132,6 @@ public final class ThreadDump {
         this.threadDumpObj = threadDumpObj;
     }
 
-    /**
-     * Assert that a JSONValue is a JSONString and parse the string as an int.
-     */
-    private static int parseStringAsInt(JSONValue valueObj) {
-        return Integer.parseInt(valueObj.asString());
-    }
-
-    /**
-     * Assert that a JSONValue is a JSONString and parse the string as a long.
-     */
-    private static long parseStringAsLong(JSONValue valueObj) {
-        return Long.parseLong(valueObj.asString());
-    }
-
     /**
      * Represents an element in the threadDump/threadContainers array.
      */
@@ -178,9 +165,9 @@ public final class ThreadDump {
          * Return the thread identifier of the owner or empty OptionalLong if not owned.
          */
         public OptionalLong owner() {
-            return containerObj.get("owner")  // string or null
+            return containerObj.get("owner")  // number or null
                     .valueOrNull()
-                    .map(v -> OptionalLong.of(parseStringAsLong(v)))
+                    .map(v -> OptionalLong.of(v.asLong()))
                     .orElse(OptionalLong.empty());
         }
 
@@ -245,7 +232,7 @@ public final class ThreadDump {
         private final JSONValue threadObj;
 
         ThreadInfo(JSONValue threadObj) {
-            this.tid = parseStringAsLong(threadObj.get("tid"));
+            this.tid = threadObj.get("tid").asLong();
             this.threadObj = threadObj;
         }
 
@@ -293,7 +280,7 @@ public final class ThreadDump {
          */
         public OptionalLong parkBlockerOwner() {
             return threadObj.getOrAbsent("parkBlocker")
-                    .map(v -> OptionalLong.of(parseStringAsLong(v.get("owner"))))
+                    .map(v -> OptionalLong.of(v.get("owner").asLong()))
                     .orElse(OptionalLong.empty());
         }
 
@@ -334,7 +321,7 @@ public final class ThreadDump {
                     .map(JSONValue::elements)
                     .orElse(List.of())
                     .forEach(e -> {
-                        int depth = parseStringAsInt(e.get("depth"));
+                        int depth = e.get("depth").asInt();
                         List locks = e.get("locks")
                                 .elements()
                                 .stream()
@@ -354,7 +341,7 @@ public final class ThreadDump {
          */
         public OptionalLong carrier() {
             return threadObj.getOrAbsent("carrier")
-                    .map(s -> OptionalLong.of(parseStringAsLong(s)))
+                    .map(v -> OptionalLong.of(v.asLong()))
                     .orElse(OptionalLong.empty());
         }
 
@@ -389,8 +376,7 @@ public final class ThreadDump {
      * Returns the value of threadDump/processId.
      */
     public long processId() {
-        return parseStringAsLong(threadDumpObj.get("processId"));
-    }
+        return threadDumpObj.get("processId").asLong(); }
 
     /**
      * Returns the value of threadDump/time.
@@ -436,6 +422,10 @@ public final class ThreadDump {
      */
     public static ThreadDump parse(String json) {
         JSONValue threadDumpObj = JSONValue.parse(json).get("threadDump");
+        int formatVersion = threadDumpObj.get("formatVersion").asInt();
+        if (formatVersion != 2) {
+            fail("Format " + formatVersion + " not supported");
+        }
 
         // threadContainers array, preserve insertion order (parents are added before children)
         Map containerObjs = threadDumpObj.get("threadContainers")
@@ -444,7 +434,7 @@ public final class ThreadDump {
                 .collect(Collectors.toMap(
                         c -> c.get("container").asString(),
                         Function.identity(),
-                        (a, b) -> { throw new RuntimeException("Duplicate container"); },
+                        (a, b) -> { fail("Duplicate container"); return null; },
                         LinkedHashMap::new
                 ));
 
@@ -456,7 +446,7 @@ public final class ThreadDump {
             JSONValue parentObj = containerObj.get("parent");
             if (parentObj instanceof JSONValue.JSONNull) {
                 if (root != null) {
-                    throw new RuntimeException("More than one root container");
+                    fail("More than one root container");
                 }
                 root = new ThreadContainer(name, null, containerObj);
                 map.put(name, root);
@@ -464,7 +454,7 @@ public final class ThreadDump {
                 String parentName = parentObj.asString();
                 ThreadContainer parent = map.get(parentName);
                 if (parent == null) {
-                    throw new RuntimeException("Thread container " + name + " found before " + parentName);
+                    fail("Thread container " + name + " found before " + parentName);
                 }
                 var container = new ThreadContainer(name, parent, containerObj);
                 parent.addChild(container);
@@ -472,9 +462,13 @@ public final class ThreadDump {
             }
         }
         if (root == null) {
-            throw new RuntimeException("No root container");
+            fail("No root container");
         }
 
         return new ThreadDump(root, map, threadDumpObj);
     }
+
+    private static void fail(String message) {
+        throw new RuntimeException(message);
+    }
 }

From e582a3cb002868d27c48bcf029a01cc7733d0edb Mon Sep 17 00:00:00 2001
From: Martin Doerr 
Date: Tue, 31 Mar 2026 09:08:39 +0000
Subject: [PATCH 113/359] 8381315:
 compiler/vectorapi/TestVectorReallocation.java fails with -XX:UseAVX=1 after
 JDK-8380565

Reviewed-by: chagedorn, rrich
---
 test/hotspot/jtreg/ProblemList.txt                            | 1 -
 .../jtreg/compiler/vectorapi/TestVectorReallocation.java      | 4 ++--
 2 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt
index 7580ce4d165..3b871d9f4b6 100644
--- a/test/hotspot/jtreg/ProblemList.txt
+++ b/test/hotspot/jtreg/ProblemList.txt
@@ -56,7 +56,6 @@ compiler/c2/irTests/TestDuplicateBackedge.java 8318904 generic-all
 
 compiler/codecache/jmx/PoolsIndependenceTest.java 8264632 macosx-all
 
-compiler/vectorapi/TestVectorReallocation.java 8381315 generic-x64
 compiler/vectorapi/reshape/TestVectorReinterpret.java 8320897,8348519 aix-ppc64,linux-ppc64le,linux-s390x
 compiler/vectorapi/VectorRebracket128Test.java 8330538 generic-all
 
diff --git a/test/hotspot/jtreg/compiler/vectorapi/TestVectorReallocation.java b/test/hotspot/jtreg/compiler/vectorapi/TestVectorReallocation.java
index 1bdc6ea726d..6b21b693d1e 100644
--- a/test/hotspot/jtreg/compiler/vectorapi/TestVectorReallocation.java
+++ b/test/hotspot/jtreg/compiler/vectorapi/TestVectorReallocation.java
@@ -301,7 +301,7 @@ public class TestVectorReallocation {
     }
 
     @Test
-    @IR(counts = {IRNode.ADD_VF, " >0 "})
+    @IR(counts = {IRNode.ADD_VF, IRNode.VECTOR_SIZE_ANY, " >0 "})
     void floatIdentityWithReallocation() {
         FloatVector v0 = FloatVector.fromArray(F_SPECIES, f_a, 0);
         float zeroSum = 0;
@@ -339,7 +339,7 @@ public class TestVectorReallocation {
     }
 
     @Test
-    @IR(counts = {IRNode.ADD_VD, " >0 "})
+    @IR(counts = {IRNode.ADD_VD, IRNode.VECTOR_SIZE_ANY, " >0 "})
     void doubleIdentityWithReallocation() {
         DoubleVector v0 = DoubleVector.fromArray(D_SPECIES, d_a, 0);
         double zeroSum = 0;

From 6652d69fd551591518a3870691bc44ea597ea936 Mon Sep 17 00:00:00 2001
From: Kerem Kat 
Date: Tue, 31 Mar 2026 09:45:44 +0000
Subject: [PATCH 114/359] 8374497: C2: assert(verify(phase)) failed: missing
 Value() optimization with -XX:+StressReflectiveCode

Reviewed-by: dfenacci, snatarajan, qamai
---
 src/hotspot/share/opto/subtypenode.cpp        |  3 +-
 .../TestSubTypeCheckStressReflectiveCode.java | 42 +++++++++++++++++++
 2 files changed, 44 insertions(+), 1 deletion(-)
 create mode 100644 test/hotspot/jtreg/compiler/types/TestSubTypeCheckStressReflectiveCode.java

diff --git a/src/hotspot/share/opto/subtypenode.cpp b/src/hotspot/share/opto/subtypenode.cpp
index 69b7058d053..317b839fbd4 100644
--- a/src/hotspot/share/opto/subtypenode.cpp
+++ b/src/hotspot/share/opto/subtypenode.cpp
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2020, 2026, 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.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -177,7 +178,7 @@ bool SubTypeCheckNode::verify(PhaseGVN* phase) {
       return true;
     }
     const Type* cached_t = Value(phase); // cache the type to validate consistency
-    switch (C->static_subtype_check(superk, subk)) {
+    switch (C->static_subtype_check(superk, subk, false)) {
       case Compile::SSC_easy_test: {
         return verify_helper(phase, load_klass(phase), cached_t);
       }
diff --git a/test/hotspot/jtreg/compiler/types/TestSubTypeCheckStressReflectiveCode.java b/test/hotspot/jtreg/compiler/types/TestSubTypeCheckStressReflectiveCode.java
new file mode 100644
index 00000000000..5814a4a4b39
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/types/TestSubTypeCheckStressReflectiveCode.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 8374497
+ * @summary SubTypeCheckNode::verify fails when StressReflectiveCode skips
+ *          static_subtype_check in verify() but not in sub()
+ * @run main/othervm -Xcomp -XX:CompileCommand=compileonly,*TimeZone::*
+ *                   -XX:+IgnoreUnrecognizedVMOptions -XX:+StressReflectiveCode
+ *                   ${test.main.class}
+ */
+
+package compiler.types;
+
+import java.util.TimeZone;
+
+public class TestSubTypeCheckStressReflectiveCode {
+    public static void main(String[] args) {
+        TimeZone.getDefault();
+    }
+}

From 46306d38ed4620480c66b6eded82985bdecb2218 Mon Sep 17 00:00:00 2001
From: Renjith Kannath Pariyangad 
Date: Tue, 31 Mar 2026 09:59:15 +0000
Subject: [PATCH 115/359] 8361493: RepaintManager.invalidComponents uses
 different equality when searching element

Co-authored-by: Alexey Ivanov 
Reviewed-by: aivanov, prr, serb, dmarkov
---
 .../classes/javax/swing/RepaintManager.java   |  8 +-
 .../RemoveInvalidComponentTest.java           | 96 +++++++++++++++++++
 2 files changed, 103 insertions(+), 1 deletion(-)
 create mode 100644 test/jdk/javax/swing/RepaintManager/RemoveInvalidComponentTest.java

diff --git a/src/java.desktop/share/classes/javax/swing/RepaintManager.java b/src/java.desktop/share/classes/javax/swing/RepaintManager.java
index b587cf2da84..ab21e555919 100644
--- a/src/java.desktop/share/classes/javax/swing/RepaintManager.java
+++ b/src/java.desktop/share/classes/javax/swing/RepaintManager.java
@@ -379,7 +379,13 @@ public class RepaintManager
             return;
         }
         if (invalidComponents != null) {
-            invalidComponents.remove(component);
+            int n = invalidComponents.size();
+            for (int i = 0; i < n; i++) {
+                if (component == invalidComponents.get(i)) {
+                    invalidComponents.remove(i);
+                    break;
+                }
+            }
         }
     }
 
diff --git a/test/jdk/javax/swing/RepaintManager/RemoveInvalidComponentTest.java b/test/jdk/javax/swing/RepaintManager/RemoveInvalidComponentTest.java
new file mode 100644
index 00000000000..bd40bab4c43
--- /dev/null
+++ b/test/jdk/javax/swing/RepaintManager/RemoveInvalidComponentTest.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.RepaintManager;
+import javax.swing.SwingUtilities;
+
+/*
+ * @test
+ * @bug 8361493
+ * @key headful
+ * @summary Verifies that RepaintManager's removeInvalidComponent
+ *          remove wrong component
+ * @run main/othervm RemoveInvalidComponentTest
+ */
+public final class RemoveInvalidComponentTest {
+    private static volatile boolean isValidateCalled;
+
+    private static final class EqualLabel extends JLabel {
+
+        public EqualLabel(String text) {
+            super(text);
+        }
+
+        @Override
+        public void validate() {
+            System.out.println("validate called");
+            isValidateCalled = true;
+            super.validate();
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            return obj instanceof EqualLabel el
+                   && el.getText().equals(getText());
+        }
+
+        @Override
+        public boolean isValidateRoot() {
+            return true;
+        }
+    }
+
+    private static void runTest() {
+        final RepaintManager repaintManager = new RepaintManager();
+
+        JLabel label1 = new EqualLabel("label");
+        JLabel label2 = new EqualLabel("label");
+
+        if (!label1.equals(label2)) {
+            throw new RuntimeException("label1.equals(label2) returned false");
+        }
+
+        JFrame frame = new JFrame("RemoveInvalidComponentTest");
+
+        frame.add(label1);
+        frame.add(label2);
+
+        frame.setVisible(true);
+
+        repaintManager.addInvalidComponent(label1);
+        repaintManager.removeInvalidComponent(label2);
+        repaintManager.validateInvalidComponents();
+
+        frame.dispose();
+    }
+
+    public static void main(String[] args) throws Exception {
+        SwingUtilities.invokeAndWait(RemoveInvalidComponentTest::runTest);
+
+        if (!isValidateCalled) {
+            throw new RuntimeException("Label1 was removed from repaint manager");
+        }
+    }
+}

From f45b48ba9867984cb0247e378dff5d0c84b9e08a Mon Sep 17 00:00:00 2001
From: David Beaumont 
Date: Tue, 31 Mar 2026 10:00:03 +0000
Subject: [PATCH 116/359] 8380307: Refactor miscellaneous JAXP tests in
 javax/xml/jaxp/unittest to JUnit

Reviewed-by: liach, joehw
---
 .../parsers/ptests/FactoryConfErrorTest.java  |   3 -
 .../xml/transform/ptests/TransformTest.java   |   3 -
 .../validation/ptests/SchemaFactoryTest.java  |   4 -
 .../xml/jaxp/unittest/bcel/UtilityTest.java   |   9 +-
 .../catalog/CatalogFileInputTest.java         | 190 ++++++------
 .../unittest/catalog/CatalogResolverTest.java |  51 ++--
 .../unittest/catalog/CatalogReuseTest.java    |  56 ++--
 .../jaxp/unittest/catalog/CatalogSupport.java |  67 +++--
 .../unittest/catalog/CatalogSupport1.java     |  69 ++---
 .../unittest/catalog/CatalogSupport2.java     | 153 +++++-----
 .../unittest/catalog/CatalogSupport3.java     | 151 +++++-----
 .../unittest/catalog/CatalogSupport4.java     |  74 +++--
 .../unittest/catalog/CatalogSupport5.java     | 120 ++++----
 .../unittest/catalog/CatalogSupportBase.java  | 103 +++----
 .../jaxp/unittest/catalog/CatalogTest.java    | 273 +++++++++---------
 .../xml/jaxp/unittest/catalog/GroupTest.java  |  29 +-
 .../jaxp/unittest/datatype/Bug6320118.java    |  30 +-
 .../unittest/datatype/Bug6937951Test.java     |  18 +-
 .../unittest/datatype/Bug6937964Test.java     | 187 +++++-------
 .../unittest/datatype/Bug7042647Test.java     |  18 +-
 .../datatype/DatatypeFactoryTest.java         |  68 ++---
 .../jaxp/unittest/datatype/DurationTest.java  | 262 +++++++----------
 .../unittest/datatype/FactoryFindTest.java    |  38 +--
 .../jaxp/unittest/datatype/HashCodeTest.java  |  53 ++--
 .../unittest/datatype/JDK8068839Test.java     |  13 +-
 .../datatype/XMLGregorianCalendarTest.java    | 111 +++----
 .../unittest/sax/Attributes2ImplTest.java     |  98 +++----
 .../xml/jaxp/unittest/sax/Bug6889654Test.java |  60 +---
 .../xml/jaxp/unittest/sax/Bug6925410Test.java |  35 +--
 .../xml/jaxp/unittest/sax/Bug6949607Test.java |  59 ++--
 .../xml/jaxp/unittest/sax/Bug6992561Test.java |  52 ++--
 .../xml/jaxp/unittest/sax/Bug7057778.xml      |   3 -
 .../xml/jaxp/unittest/sax/Bug7057778Test.java | 178 ++----------
 .../jaxp/unittest/sax/DeclarationTest.java    |  67 ++---
 .../unittest/sax/DefaultHandler2Test.java     | 266 ++++++-----------
 .../jaxp/unittest/sax/IssueTracker56Test.java |  99 ++-----
 .../xml/jaxp/unittest/sax/NSSupportTest.java  |  93 +++---
 .../unittest/sax/SAXExceptionInitCause.java   |  74 ++---
 .../xml/jaxp/unittest/sax/SAXParserTest.java  |  58 ++--
 .../unittest/sax/SymbolTableResetTest.java    |  23 +-
 .../xml/jaxp/unittest/sax/XMLReaderTest.java  |  40 ++-
 .../unittest/sbd/test/ExternalRefTest.java    |  21 +-
 42 files changed, 1457 insertions(+), 1922 deletions(-)
 delete mode 100644 test/jaxp/javax/xml/jaxp/unittest/sax/Bug7057778.xml

diff --git a/test/jaxp/javax/xml/jaxp/functional/javax/xml/parsers/ptests/FactoryConfErrorTest.java b/test/jaxp/javax/xml/jaxp/functional/javax/xml/parsers/ptests/FactoryConfErrorTest.java
index fe4288fc2b1..3ee91ff6555 100644
--- a/test/jaxp/javax/xml/jaxp/functional/javax/xml/parsers/ptests/FactoryConfErrorTest.java
+++ b/test/jaxp/javax/xml/jaxp/functional/javax/xml/parsers/ptests/FactoryConfErrorTest.java
@@ -26,8 +26,6 @@ package javax.xml.parsers.ptests;
 import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.parallel.Execution;
-import org.junit.jupiter.api.parallel.ExecutionMode;
 
 import javax.xml.parsers.DocumentBuilderFactory;
 import javax.xml.parsers.FactoryConfigurationError;
@@ -44,7 +42,6 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
  * @library /javax/xml/jaxp/libs
  * @run junit/othervm javax.xml.parsers.ptests.FactoryConfErrorTest
  */
-@Execution(ExecutionMode.SAME_THREAD)
 public class FactoryConfErrorTest {
 
     /**
diff --git a/test/jaxp/javax/xml/jaxp/functional/javax/xml/transform/ptests/TransformTest.java b/test/jaxp/javax/xml/jaxp/functional/javax/xml/transform/ptests/TransformTest.java
index 1d9600b330b..7ca7fc6c6d8 100644
--- a/test/jaxp/javax/xml/jaxp/functional/javax/xml/transform/ptests/TransformTest.java
+++ b/test/jaxp/javax/xml/jaxp/functional/javax/xml/transform/ptests/TransformTest.java
@@ -26,8 +26,6 @@ package javax.xml.transform.ptests;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.TestInstance;
 import org.junit.jupiter.api.TestInstance.Lifecycle;
-import org.junit.jupiter.api.parallel.Execution;
-import org.junit.jupiter.api.parallel.ExecutionMode;
 import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.MethodSource;
 import org.w3c.dom.Document;
@@ -77,7 +75,6 @@ import static javax.xml.transform.ptests.TransformerTestConst.XML_DIR;
  * @summary Tests for variable combination of Transformer.transform(Source, Result)
  */
 @TestInstance(Lifecycle.PER_CLASS)
-@Execution(ExecutionMode.SAME_THREAD)
 public class TransformTest {
 
     /*
diff --git a/test/jaxp/javax/xml/jaxp/functional/javax/xml/validation/ptests/SchemaFactoryTest.java b/test/jaxp/javax/xml/jaxp/functional/javax/xml/validation/ptests/SchemaFactoryTest.java
index dc5acdfe1a3..e7ebdb973f3 100644
--- a/test/jaxp/javax/xml/jaxp/functional/javax/xml/validation/ptests/SchemaFactoryTest.java
+++ b/test/jaxp/javax/xml/jaxp/functional/javax/xml/validation/ptests/SchemaFactoryTest.java
@@ -22,13 +22,10 @@
  */
 package javax.xml.validation.ptests;
 
-import jaxp.library.JAXPDataProvider;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.TestInstance;
 import org.junit.jupiter.api.TestInstance.Lifecycle;
-import org.junit.jupiter.api.parallel.Execution;
-import org.junit.jupiter.api.parallel.ExecutionMode;
 import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.MethodSource;
 import org.w3c.dom.Document;
@@ -78,7 +75,6 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
  * @run junit/othervm javax.xml.validation.ptests.SchemaFactoryTest
  * @summary Class containing the test cases for SchemaFactory
  */
-@Execution(ExecutionMode.SAME_THREAD)
 @TestInstance(Lifecycle.PER_CLASS)
 public class SchemaFactoryTest {
 
diff --git a/test/jaxp/javax/xml/jaxp/unittest/bcel/UtilityTest.java b/test/jaxp/javax/xml/jaxp/unittest/bcel/UtilityTest.java
index 56545698778..020010628cf 100644
--- a/test/jaxp/javax/xml/jaxp/unittest/bcel/UtilityTest.java
+++ b/test/jaxp/javax/xml/jaxp/unittest/bcel/UtilityTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved.
  * 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,14 +24,15 @@
 package bcel;
 
 import com.sun.org.apache.bcel.internal.classfile.Utility;
+import org.junit.jupiter.api.Test;
+
 import java.util.Base64;
-import org.testng.annotations.Test;
 
 /*
  * @test
  * @bug 8256919
  * @modules java.xml/com.sun.org.apache.bcel.internal.classfile
- * @run testng bcel.UtilityTest
+ * @run junit bcel.UtilityTest
  * @summary Tests the Utility.
  */
 public class UtilityTest {
@@ -42,7 +43,7 @@ public class UtilityTest {
      */
     @Test
     public void test() throws Exception {
-        /**
+        /*
          * public class Hello {
          *     public void hello(){
          *         System.out.println("Hello,world");
diff --git a/test/jaxp/javax/xml/jaxp/unittest/catalog/CatalogFileInputTest.java b/test/jaxp/javax/xml/jaxp/unittest/catalog/CatalogFileInputTest.java
index 9a19c0237d7..ece63b7e3f1 100644
--- a/test/jaxp/javax/xml/jaxp/unittest/catalog/CatalogFileInputTest.java
+++ b/test/jaxp/javax/xml/jaxp/unittest/catalog/CatalogFileInputTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved.
  * 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,24 @@
 
 package catalog;
 
+import com.sun.net.httpserver.HttpServer;
+import com.sun.net.httpserver.SimpleFileServer;
+import jdk.test.lib.net.URIBuilder;
+import jdk.test.lib.util.JarUtils;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInstance;
+import org.junit.jupiter.api.TestInstance.Lifecycle;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.MethodSource;
+import org.xml.sax.InputSource;
+
+import javax.xml.catalog.Catalog;
+import javax.xml.catalog.CatalogException;
+import javax.xml.catalog.CatalogFeatures;
+import javax.xml.catalog.CatalogManager;
+import javax.xml.catalog.CatalogResolver;
 import java.io.BufferedOutputStream;
 import java.io.BufferedReader;
 import java.io.BufferedWriter;
@@ -41,32 +59,18 @@ import java.nio.file.Paths;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 
-import javax.xml.catalog.Catalog;
-import javax.xml.catalog.CatalogException;
-import javax.xml.catalog.CatalogFeatures;
-import javax.xml.catalog.CatalogManager;
-import javax.xml.catalog.CatalogResolver;
-
 import static java.nio.file.StandardOpenOption.APPEND;
 import static java.nio.file.StandardOpenOption.CREATE;
-import static jaxp.library.JAXPTestUtilities.getSystemProperty;
-
-import com.sun.net.httpserver.HttpServer;
-import com.sun.net.httpserver.SimpleFileServer;
-import jdk.test.lib.net.URIBuilder;
-import jdk.test.lib.util.JarUtils;
-import org.testng.Assert;
-import org.testng.annotations.AfterClass;
-import org.testng.annotations.BeforeClass;
-import org.testng.annotations.DataProvider;
-import org.testng.annotations.Test;
-import org.xml.sax.InputSource;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
 
 /*
  * @test
  * @bug 8151154 8171243
  * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest /test/lib
- * @run testng/othervm catalog.CatalogFileInputTest
+ * @run junit/othervm catalog.CatalogFileInputTest
  * @summary Verifies that the Catalog API accepts valid URIs only;
  *          Verifies that the CatalogFeatures' builder throws
  *          IllegalArgumentException on invalid file inputs.
@@ -74,11 +78,12 @@ import org.xml.sax.InputSource;
  *          JDK-8168968, it has to only run without SecurityManager
  *          because an ACE will be thrown for invalid path.
  */
+@TestInstance(Lifecycle.PER_CLASS)
 public class CatalogFileInputTest extends CatalogSupportBase {
 
     static final CatalogFeatures FEATURES = CatalogFeatures.builder().
             with(CatalogFeatures.Feature.PREFER, "system").build();
-    static String CLS_DIR = getSystemProperty("test.classes");
+    static String CLS_DIR = System.getProperty("test.classes");
     static String SRC_DIR = System.getProperty("test.src");
     static String JAR_CONTENT = "META-INF";
     final static String SCHEME_JARFILE = "jar:";
@@ -91,7 +96,7 @@ public class CatalogFileInputTest extends CatalogSupportBase {
     /*
      * Initializing fields
      */
-    @BeforeClass
+    @BeforeAll
     public void setUpClass() throws Exception {
         super.setUp();
         // set up HttpServer
@@ -107,7 +112,7 @@ public class CatalogFileInputTest extends CatalogSupportBase {
                 .build().toString() + REMOTE_FILE_LOCATION;
     }
 
-    @AfterClass
+    @AfterAll
     protected void tearDown() {
         if (httpserver != null) {
             httpserver.stop(0);
@@ -119,87 +124,86 @@ public class CatalogFileInputTest extends CatalogSupportBase {
      * Verifies that the Catalog can be created with file system paths including JAR
      * and http URL, and used to resolve a systemId as expected.
      */
-    @Test(dataProvider = "acceptedURI")
-    public void testMatch(final String uri, final String sysId, final String pubId,
-            final String expectedId, final String msg) {
+    @ParameterizedTest
+    @MethodSource("acceptedURI")
+    public void testMatch(String uri, String sysId, String pubId, String expectedId, String msg) {
         CatalogResolver cr = CatalogManager.catalogResolver(FEATURES, URI.create(uri));
         InputSource is = cr.resolveEntity(pubId, sysId);
-        Assert.assertNotNull(is, msg);
-        Assert.assertEquals(expectedId, is.getSystemId(), msg);
+        assertNotNull(is, msg);
+        assertEquals(expectedId, is.getSystemId(), msg);
     }
 
-    @Test(dataProvider = "invalidCatalog")
-    public void testEmptyCatalog(final String uri, final String publicId, final String msg) {
+    @ParameterizedTest
+    @MethodSource("invalidCatalog")
+    public void testEmptyCatalog(String uri, String publicId, String msg) {
         Catalog c = CatalogManager.catalog(FEATURES, uri != null ? URI.create(uri) : null);
-        Assert.assertNull(c.matchSystem(publicId), msg);
+        assertNull(c.matchSystem(publicId), msg);
     }
 
-    @Test(dataProvider = "invalidCatalog", expectedExceptions = CatalogException.class)
-    public void testCatalogResolverWEmptyCatalog(final String uri, final String publicId, final String msg) {
+    @ParameterizedTest
+    @MethodSource("invalidCatalog")
+    public void testCatalogResolverWEmptyCatalog(String uri, String publicId, String msg) {
         CatalogResolver cr = CatalogManager.catalogResolver(
                 CatalogFeatures.builder().with(CatalogFeatures.Feature.RESOLVE, "strict").build(),
                 uri != null ? URI.create(uri) : null);
-        InputSource is = cr.resolveEntity(publicId, "");
+        assertThrows(CatalogException.class, () -> cr.resolveEntity(publicId, ""));
     }
 
-    @Test(dataProvider = "invalidCatalog")
-    public void testCatalogResolverWEmptyCatalog1(final String uri, final String publicId, final String msg) {
+    @ParameterizedTest
+    @MethodSource("invalidCatalog")
+    public void testCatalogResolverWEmptyCatalog1(String uri, String publicId, String msg) {
         CatalogResolver cr = CatalogManager.catalogResolver(
                 CatalogFeatures.builder().with(CatalogFeatures.Feature.RESOLVE, "continue").build(),
                 uri != null ? URI.create(uri) : null);
-        Assert.assertNull(cr.resolveEntity(publicId, ""), msg);
+        assertNull(cr.resolveEntity(publicId, ""), msg);
     }
 
-    @Test(dataProvider = "invalidInput", expectedExceptions = IllegalArgumentException.class)
-    public void testFileInput(final String file) {
-        CatalogFeatures features = CatalogFeatures.builder()
-            .with(CatalogFeatures.Feature.FILES, file)
-            .build();
+    @ParameterizedTest
+    @MethodSource("invalidInput")
+    public void testFileInput(String file) {
+        assertThrows(
+                IllegalArgumentException.class,
+                () -> CatalogFeatures.builder().with(CatalogFeatures.Feature.FILES, file));
     }
 
-    @Test(dataProvider = "invalidInput", expectedExceptions = IllegalArgumentException.class)
-    public void testInvalidUri(final String file) {
-        CatalogResolver cr = CatalogManager.catalogResolver(FEATURES, file != null ? URI.create(file) : null);
+    @ParameterizedTest
+    @MethodSource("invalidInput")
+    public void testInvalidUri(String file) {
+        URI uri = file != null ? URI.create(file) : null;
+        assertThrows(IllegalArgumentException.class, () -> CatalogManager.catalogResolver(FEATURES, uri));
     }
 
-    @Test(dataProvider = "invalidInput", expectedExceptions = IllegalArgumentException.class)
-    public void testInvalidUri1(final String file) {
-        Catalog c = CatalogManager.catalog(FEATURES, file != null ? URI.create(file) : null);
-        System.err.println("Catalog =" + c);
+    @ParameterizedTest
+    @MethodSource("invalidInput")
+    public void testInvalidUri1(String file) {
+        URI uri = file != null ? URI.create(file) : null;
+        assertThrows(IllegalArgumentException.class, () -> CatalogManager.catalog(FEATURES, uri));
     }
 
-
-    @Test(expectedExceptions = NullPointerException.class)
-    public void testNullFileInput() {
-        CatalogFeatures features = CatalogFeatures.builder()
-            .with(CatalogFeatures.Feature.FILES, null)
-            .build();
+    @Test
+    public void testNull() {
+        assertThrows(
+                NullPointerException.class,
+                () -> CatalogFeatures.builder().with(CatalogFeatures.Feature.FILES, null));
     }
 
-    @Test(expectedExceptions = NullPointerException.class)
+    @Test
     public void testNullUri() {
-        URI uri = null;
-        CatalogResolver cr = CatalogManager.catalogResolver(FEATURES, uri);
+        assertThrows(NullPointerException.class, () -> CatalogManager.catalogResolver(FEATURES, (URI) null));
+        assertThrows(NullPointerException.class, () -> CatalogManager.catalog(FEATURES, (URI) null));
     }
 
-    @Test(expectedExceptions = NullPointerException.class)
-    public void testNullUri1() {
-        URI uri = null;
-        Catalog c = CatalogManager.catalog(FEATURES, uri);
-    }
-
-    private String systemId = "http://www.sys00test.com/rewrite.dtd";
-    private String publicId = "PUB-404";
-    private String expected = "http://www.groupxmlbase.com/dtds/rewrite.dtd";
-    private String errMsg = "Relative rewriteSystem with xml:base at group level failed";
+    private static final String systemId = "http://www.sys00test.com/rewrite.dtd";
+    private static final String publicId = "PUB-404";
+    private static final String expected = "http://www.groupxmlbase.com/dtds/rewrite.dtd";
+    private static final String errMsg = "Relative rewriteSystem with xml:base at group level failed";
 
     /*
         DataProvider: used to verify CatalogResolver's resolveEntity function.
         Data columns:
         catalog, systemId, publicId, expectedUri, msg
      */
-    @DataProvider(name = "acceptedURI")
-    Object[][] getData() throws Exception {
+    Object[][] acceptedURI() throws IOException {
         String filename = "rewriteSystem_id.xml";
         String urlFile = getClass().getResource(filename).toExternalForm();
         String urlHttp = remoteFilePath + "/jax-ws-catalog.xml";
@@ -209,12 +213,7 @@ public class CatalogFileInputTest extends CatalogSupportBase {
         String xsd = jarPath.substring(0, jarPath.lastIndexOf("/")) + "/catalog/ws-addr.xsd";
 
         // create JAR file
-        try {
-            JarUtils.createJarFile(Paths.get(CLS_DIR + "/JDK8171243.jar"),
-                    Paths.get(SRC_DIR + "/jar"), JAR_CONTENT);
-        } catch (IOException ex) {
-            Assert.fail("Failed to create JAR: " + ex.getMessage());
-        }
+        JarUtils.createJarFile(Paths.get(CLS_DIR + "/JDK8171243.jar"), Paths.get(SRC_DIR + "/jar"), JAR_CONTENT);
 
         return new Object[][]{
             // URL
@@ -230,8 +229,7 @@ public class CatalogFileInputTest extends CatalogSupportBase {
      *  Note: the difference from invalidInput is that invalidInput is syntactically
      *  rejected with an IAE.
      */
-    @DataProvider(name = "invalidCatalog")
-    public Object[][] getInvalidCatalog() {
+    public Object[][] invalidCatalog() {
         String catalogUri = getClass().getResource("catalog_invalid.xml").toExternalForm();
         return new Object[][]{
             {catalogUri, "-//W3C//DTD XHTML 1.0 Strict//EN",
@@ -245,38 +243,24 @@ public class CatalogFileInputTest extends CatalogSupportBase {
      *  DataProvider: a list of invalid inputs, expects IAE
      *  Note: exclude null since NPE would have been expected
      */
-    @DataProvider(name = "invalidInput")
-    public Object[][] getFiles() throws Exception {
+    public Object[][] invalidInput() throws Exception {
         String filename = "rewriteSystem_id.xml";
         copyFile(Paths.get(SRC_DIR + "/" + filename), Paths.get(filename));
         String absolutePath = getClass().getResource(filename).getFile();
 
-        return new Object[][]{
-            {""},
-            {"file:a/b\\c"},
-            {"c:/te:t"},
-            {"c:/te?t"},
-            {"c/te*t"},
-            {"in|valid.txt"},
-            {"shema:invalid.txt"},
-            // relative file path
-            {filename},
-            // absolute file path
-            {absolutePath}
+        return new Object[][] {
+                { "c:/te:t" },
+                { "c:/te?t" },
+                { "c/te*t" },
+                { "shema:invalid.txt" },
+                // relative file path
+                { filename },
+                // absolute file path
+                { absolutePath }
         };
     }
 
-    /*
-       DataProvider: a list of invalid inputs
-     */
-    @DataProvider(name = "nullTest")
-    public Object[][] getNull() {
-        return new Object[][]{
-            {null},
-        };
-    }
-
-    void copyFile(final Path src, final Path target) throws Exception {
+    private static void copyFile(final Path src, final Path target) throws Exception {
         try (InputStream in = Files.newInputStream(src);
                 BufferedReader reader
                 = new BufferedReader(new InputStreamReader(in));
diff --git a/test/jaxp/javax/xml/jaxp/unittest/catalog/CatalogResolverTest.java b/test/jaxp/javax/xml/jaxp/unittest/catalog/CatalogResolverTest.java
index 6ad23785b64..b4a2d20efcc 100644
--- a/test/jaxp/javax/xml/jaxp/unittest/catalog/CatalogResolverTest.java
+++ b/test/jaxp/javax/xml/jaxp/unittest/catalog/CatalogResolverTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved.
  * 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,36 +22,41 @@
  */
 package catalog;
 
-import java.net.URI;
-import java.nio.file.Paths;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.TestInstance;
+import org.junit.jupiter.api.TestInstance.Lifecycle;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.MethodSource;
+import org.xml.sax.InputSource;
+
 import javax.xml.catalog.Catalog;
 import javax.xml.catalog.CatalogException;
 import javax.xml.catalog.CatalogFeatures;
 import javax.xml.catalog.CatalogManager;
 import javax.xml.catalog.CatalogResolver;
 import javax.xml.catalog.CatalogResolver.NotFoundAction;
-import org.testng.Assert;
-import org.testng.annotations.BeforeClass;
-import org.testng.annotations.DataProvider;
-import org.testng.annotations.Test;
-import org.xml.sax.InputSource;
+import java.net.URI;
+import java.nio.file.Paths;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
 
 /*
  * @test
  * @bug 8316996
  * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest
- * @run testng/othervm catalog.CatalogResolverTest
+ * @run junit/othervm catalog.CatalogResolverTest
  * @summary Tests CatalogResolver functions. See CatalogTest for existing basic
  * functional tests.
  */
+@TestInstance(Lifecycle.PER_CLASS)
 public class CatalogResolverTest extends CatalogSupportBase {
-    static final String KEY_FILES = "javax.xml.catalog.files";
     static final String SYSTEM_ID = "http://openjdk_java_net/xml/catalog/dtd/system.dtd";
 
     /*
      * Initializing fields
      */
-    @BeforeClass
+    @BeforeAll
     public void setUpClass() throws Exception {
         super.setUp();
     }
@@ -63,7 +68,6 @@ public class CatalogResolverTest extends CatalogSupportBase {
         resolve property for the Catalog, resolve property for the CatalogResolver,
         system ID to be resolved, expected result, expected exception
      */
-    @DataProvider(name = "factoryMethodInput")
     public Object[][] getInputs() throws Exception {
 
         return new Object[][]{
@@ -80,7 +84,6 @@ public class CatalogResolverTest extends CatalogSupportBase {
          };
     }
 
-    @DataProvider(name = "NPETest")
     public Object[][] getNPETest() throws Exception {
         return new Object[][]{
             {null, null},
@@ -104,22 +107,22 @@ public class CatalogResolverTest extends CatalogSupportBase {
      * @param expectedThrow the expected exception
      * @throws Exception if the test fails
      */
-    @Test(dataProvider = "factoryMethodInput")
+    @ParameterizedTest
+    @MethodSource("getInputs")
     public void testResolveProperty(String cResolve, NotFoundAction action,
             String systemId, String expectedResult, Class expectedThrow)
             throws Exception {
         Catalog c = getCatalog(cResolve);
 
         if (expectedThrow != null) {
-            Assert.assertThrows(expectedThrow,
-                () -> resolveRef(c, action, systemId));
+            assertThrows(expectedThrow, () -> resolveRef(c, action, systemId));
         } else {
-
             String sysId = resolveRef(c, action, systemId);
             System.out.println(sysId);
-            Assert.assertEquals(sysId,
-                    (expectedResult == null) ? null : Paths.get(filepath + expectedResult).toUri().toString().replace("///", "/"),
-                    "System ID match not right");
+            String expected = (expectedResult == null)
+                    ? null
+                    : Paths.get(filepath + expectedResult).toUri().toString().replace("///", "/");
+            assertEquals(expected, sysId, "System ID match not right");
         }
     }
 
@@ -127,9 +130,10 @@ public class CatalogResolverTest extends CatalogSupportBase {
      * Verifies that the catalogResolver method throws NullPointerException if
      * any of the parameters is null.
      */
-    @Test(dataProvider = "NPETest", expectedExceptions = NullPointerException.class)
+    @ParameterizedTest
+    @MethodSource("getNPETest")
     public void testCatalogProperty(Catalog c, NotFoundAction action) {
-        CatalogManager.catalogResolver(c, action);
+        assertThrows(NullPointerException.class, () -> CatalogManager.catalogResolver(c, action));
     }
 
     private String resolveRef(Catalog c, NotFoundAction action, String systemId) throws Exception {
@@ -140,9 +144,8 @@ public class CatalogResolverTest extends CatalogSupportBase {
 
     private Catalog getCatalog(String cResolve) throws Exception {
         URI catalogFile = getClass().getResource("catalog.xml").toURI();
-        Catalog c = CatalogManager.catalog(
+        return CatalogManager.catalog(
                 CatalogFeatures.builder().with(CatalogFeatures.Feature.RESOLVE, cResolve).build(),
                 catalogFile);
-        return c;
     }
 }
diff --git a/test/jaxp/javax/xml/jaxp/unittest/catalog/CatalogReuseTest.java b/test/jaxp/javax/xml/jaxp/unittest/catalog/CatalogReuseTest.java
index 6bc563f3df3..fc4329fa198 100644
--- a/test/jaxp/javax/xml/jaxp/unittest/catalog/CatalogReuseTest.java
+++ b/test/jaxp/javax/xml/jaxp/unittest/catalog/CatalogReuseTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved.
  * 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,22 +22,27 @@
  */
 package catalog;
 
-import java.net.URI;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.TestInstance;
+import org.junit.jupiter.api.TestInstance.Lifecycle;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.MethodSource;
+
 import javax.xml.catalog.Catalog;
 import javax.xml.catalog.CatalogFeatures;
 import javax.xml.catalog.CatalogManager;
-import org.testng.Assert;
-import org.testng.annotations.BeforeClass;
-import org.testng.annotations.DataProvider;
-import org.testng.annotations.Test;
+import java.net.URI;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 /*
  * @test
  * @bug 8253569
  * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest
- * @run testng catalog.CatalogReuseTest
+ * @run junit catalog.CatalogReuseTest
  * @summary Verifies that a catalog can be reused.
  */
+@TestInstance(Lifecycle.PER_CLASS)
 public class CatalogReuseTest extends CatalogSupportBase {
     static final CatalogFeatures FEATURES_STRICT = CatalogFeatures.builder().
             with(CatalogFeatures.Feature.RESOLVE, "strict").build();
@@ -46,7 +51,6 @@ public class CatalogReuseTest extends CatalogSupportBase {
         DataProvider: reuses a catalog. The length of the URIs is in descending order.
         Data columns: catalog, uri, expected
      */
-    @DataProvider(name = "dataWithCatalogD")
     public Object[][] dataWithCatalogD() {
         Catalog c = getCatalog();
         return new Object[][]{
@@ -59,7 +63,6 @@ public class CatalogReuseTest extends CatalogSupportBase {
         DataProvider: reuses a catalog. The length of the URIs is in ascending order.
         Data columns: catalog, uri, expected
      */
-    @DataProvider(name = "dataWithCatalogA")
     public Object[][] dataWithCatalogA() {
         Catalog c = getCatalog();
         return new Object[][]{
@@ -72,18 +75,17 @@ public class CatalogReuseTest extends CatalogSupportBase {
         DataProvider: provides no catalog. A new catalog will be created for each test.
         Data columns: uri, expected
      */
-    @DataProvider(name = "dataWithoutCatalog")
     public Object[][] dataWithoutCatalog() {
-        return new Object[][]{
-            {"http://entailments/example.org/A/B/derived.ttl", "derived/A/B/derived.ttl"},
-            {"http://example.org/A/B.owl", "sources/A/B.owl"},
-         };
+        return new Object[][] {
+                { "http://entailments/example.org/A/B/derived.ttl", "derived/A/B/derived.ttl" },
+                { "http://example.org/A/B.owl", "sources/A/B.owl" },
+        };
     }
 
     /*
      * Initializing fields
      */
-    @BeforeClass
+    @BeforeAll
     public void setUpClass() throws Exception {
         super.setUp();
     }
@@ -91,36 +93,38 @@ public class CatalogReuseTest extends CatalogSupportBase {
     /*
      * Verifies that a Catalog object can be reused, that no state data are
      * in the way of a subsequent matching attempt.
-    */
-    @Test(dataProvider = "dataWithCatalogD")
+     */
+    @ParameterizedTest
+    @MethodSource("dataWithCatalogD")
     public void testD(Catalog c, String uri, String expected) throws Exception {
         String m = c.matchURI(uri);
-        Assert.assertTrue(m.endsWith(expected), "Expected: " + expected);
+        assertTrue(m.endsWith(expected), "Expected: " + expected);
     }
 
     /*
      * Verifies that a Catalog object can be reused.
-    */
-    @Test(dataProvider = "dataWithCatalogA")
+     */
+    @ParameterizedTest
+    @MethodSource("dataWithCatalogA")
     public void testA(Catalog c, String uri, String expected) throws Exception {
         String m = c.matchURI(uri);
-        Assert.assertTrue(m.endsWith(expected), "Expected: " + expected);
+        assertTrue(m.endsWith(expected), "Expected: " + expected);
     }
 
     /*
      * Verifies that a match is found in a newly created Catalog.
-    */
-    @Test(dataProvider = "dataWithoutCatalog")
+     */
+    @ParameterizedTest
+    @MethodSource("dataWithoutCatalog")
     public void testNew(String uri, String expected) throws Exception {
         Catalog c = getCatalog();
         String m = c.matchURI(uri);
-        Assert.assertTrue(m.endsWith(expected), "Expected: " + expected);
+        assertTrue(m.endsWith(expected), "Expected: " + expected);
 
     }
 
     private Catalog getCatalog() {
         String uri = "file://" + slash + filepath + "/catalogReuse.xml";
-        Catalog c = CatalogManager.catalog(FEATURES_STRICT, uri != null? URI.create(uri) : null);
-        return c;
+        return CatalogManager.catalog(FEATURES_STRICT, URI.create(uri));
     }
 }
diff --git a/test/jaxp/javax/xml/jaxp/unittest/catalog/CatalogSupport.java b/test/jaxp/javax/xml/jaxp/unittest/catalog/CatalogSupport.java
index 4344bc1c623..1bd44d3c26b 100644
--- a/test/jaxp/javax/xml/jaxp/unittest/catalog/CatalogSupport.java
+++ b/test/jaxp/javax/xml/jaxp/unittest/catalog/CatalogSupport.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved.
  * 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,14 @@
 
 package catalog;
 
-import java.io.File;
-import java.io.StringReader;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.TestInstance;
+import org.junit.jupiter.api.TestInstance.Lifecycle;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.MethodSource;
+import org.w3c.dom.ls.LSResourceResolver;
+import org.xml.sax.InputSource;
+
 import javax.xml.stream.XMLResolver;
 import javax.xml.transform.Source;
 import javax.xml.transform.URIResolver;
@@ -32,17 +38,14 @@ import javax.xml.transform.dom.DOMSource;
 import javax.xml.transform.sax.SAXSource;
 import javax.xml.transform.stax.StAXSource;
 import javax.xml.transform.stream.StreamSource;
-import org.testng.annotations.BeforeClass;
-import org.testng.annotations.DataProvider;
-import org.testng.annotations.Test;
-import org.w3c.dom.ls.LSResourceResolver;
-import org.xml.sax.InputSource;
+import java.io.File;
+import java.io.StringReader;
 
-/**
+/*
  * @test
  * @bug 8158084 8162438 8162442 8166220 8166398 8290740
  * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest
- * @run testng/othervm catalog.CatalogSupport
+ * @run junit/othervm catalog.CatalogSupport
  * @summary verifies the use of Catalog in SAX/DOM/StAX/Validation/Transform.
  * The two main scenarios for all processors are:
  * A custom resolver is used whether or not there's a Catalog;
@@ -51,12 +54,12 @@ import org.xml.sax.InputSource;
 */
 
 /**
- * Support Catalog:
+ * 

Support Catalog:

* With this patch, the Catalog features are supported by all of the JAXP processors. * The support is enabled by default. Using Catalog is as simple as setting a * path to a catalog, through the API, or System property, or jaxp.properties. * - * Test notes: + *

Test notes:

* For all DataProviders, the 1st and 2nd columns determine whether to set USE_CATALOG * through the API and to use Catalog. When a custom resolver is specified, these * settings should not affect the operation, thus the tests are repeated for both @@ -64,11 +67,12 @@ import org.xml.sax.InputSource; * * @author huizhe.wang@oracle.com */ +@TestInstance(Lifecycle.PER_CLASS) public class CatalogSupport extends CatalogSupportBase { /* * Initializing fields */ - @BeforeClass + @BeforeAll public void setUpClass() throws Exception { setUp(); } @@ -76,7 +80,8 @@ public class CatalogSupport extends CatalogSupportBase { /* Verifies the Catalog support on SAXParser. */ - @Test(dataProvider = "data_SAXA") + @ParameterizedTest + @MethodSource("getDataSAX") public void testSAXA(boolean setUseCatalog, boolean useCatalog, String catalog, String xml, MyHandler handler, String expected) throws Exception { testSAX(setUseCatalog, useCatalog, catalog, xml, handler, expected); @@ -85,7 +90,8 @@ public class CatalogSupport extends CatalogSupportBase { /* Verifies the Catalog support on XMLReader. */ - @Test(dataProvider = "data_SAXA") + @ParameterizedTest + @MethodSource("getDataSAX") public void testXMLReaderA(boolean setUseCatalog, boolean useCatalog, String catalog, String xml, MyHandler handler, String expected) throws Exception { testXMLReader(setUseCatalog, useCatalog, catalog, xml, handler, expected); @@ -94,7 +100,8 @@ public class CatalogSupport extends CatalogSupportBase { /* Verifies the Catalog support on XInclude. */ - @Test(dataProvider = "data_XIA") + @ParameterizedTest + @MethodSource("getDataXI") public void testXIncludeA(boolean setUseCatalog, boolean useCatalog, String catalog, String xml, MyHandler handler, String expected) throws Exception { testXInclude(setUseCatalog, useCatalog, catalog, xml, handler, expected); @@ -104,7 +111,8 @@ public class CatalogSupport extends CatalogSupportBase { Verifies that the Catalog is used when the handler is null. The test shall run through without an Exception (that was thrown before the fix). */ - @Test(dataProvider = "data_XIA") + @ParameterizedTest + @MethodSource("getDataXI") public void testXIncludeA_NullHandler(boolean setUseCatalog, boolean useCatalog, String catalog, String xml, MyHandler handler, String expected) throws Exception { handler = null; @@ -114,7 +122,8 @@ public class CatalogSupport extends CatalogSupportBase { /* Verifies the Catalog support on DOM parser. */ - @Test(dataProvider = "data_DOMA") + @ParameterizedTest + @MethodSource("getDataDOM") public void testDOMA(boolean setUseCatalog, boolean useCatalog, String catalog, String xml, MyHandler handler, String expected) throws Exception { testDOM(setUseCatalog, useCatalog, catalog, xml, handler, expected); @@ -123,7 +132,8 @@ public class CatalogSupport extends CatalogSupportBase { /* Verifies the Catalog support on XMLStreamReader. */ - @Test(dataProvider = "data_StAXA") + @ParameterizedTest + @MethodSource("getDataStAX") public void testStAXA(boolean setUseCatalog, boolean useCatalog, String catalog, String xml, XMLResolver resolver, String expected) throws Exception { testStAX(setUseCatalog, useCatalog, catalog, xml, resolver, expected); @@ -133,7 +143,8 @@ public class CatalogSupport extends CatalogSupportBase { Verifies the Catalog support on resolving DTD, xsd import and include in Schema files. */ - @Test(dataProvider = "data_SchemaA") + @ParameterizedTest + @MethodSource("getDataSchema") public void testValidationA(boolean setUseCatalog, boolean useCatalog, String catalog, String xsd, LSResourceResolver resolver) throws Exception { @@ -145,7 +156,8 @@ public class CatalogSupport extends CatalogSupportBase { @bug 8158084 8162438 these tests also verifies the fix for 8162438 Verifies the Catalog support on the Schema Validator. */ - @Test(dataProvider = "data_ValidatorA") + @ParameterizedTest + @MethodSource("getDataValidator") public void testValidatorA(boolean setUseCatalog1, boolean setUseCatalog2, boolean useCatalog, Source source, LSResourceResolver resolver1, LSResourceResolver resolver2, String catalog1, String catalog2) @@ -158,7 +170,8 @@ public class CatalogSupport extends CatalogSupportBase { Verifies the Catalog support on resolving DTD, xsl import and include in XSL files. */ - @Test(dataProvider = "data_XSLA") + @ParameterizedTest + @MethodSource("getDataXSL") public void testXSLImportA(boolean setUseCatalog, boolean useCatalog, String catalog, SAXSource xsl, StreamSource xml, URIResolver resolver, String expected) throws Exception { @@ -171,7 +184,8 @@ public class CatalogSupport extends CatalogSupportBase { Verifies the Catalog support on resolving DTD, xsl import and include in XSL files. */ - @Test(dataProvider = "data_XSLA") + @ParameterizedTest + @MethodSource("getDataXSL") public void testXSLImportWTemplatesA(boolean setUseCatalog, boolean useCatalog, String catalog, SAXSource xsl, StreamSource xml, URIResolver resolver, String expected) throws Exception { @@ -182,7 +196,6 @@ public class CatalogSupport extends CatalogSupportBase { DataProvider: for testing the SAX parser Data: set use_catalog, use_catalog, catalog file, xml file, handler, expected result string */ - @DataProvider(name = "data_SAXA") public Object[][] getDataSAX() { String[] systemIds = {"system.dtd"}; return new Object[][]{ @@ -198,7 +211,6 @@ public class CatalogSupport extends CatalogSupportBase { DataProvider: for testing XInclude Data: set use_catalog, use_catalog, catalog file, xml file, handler, expected result string */ - @DataProvider(name = "data_XIA") public Object[][] getDataXI() { String[] systemIds = {"XI_simple.xml"}; InputSource[] returnValues = {new InputSource(xml_xIncludeSimple)}; @@ -214,7 +226,6 @@ public class CatalogSupport extends CatalogSupportBase { DataProvider: for testing DOM parser Data: set use_catalog, use_catalog, catalog file, xml file, handler, expected result string */ - @DataProvider(name = "data_DOMA") public Object[][] getDataDOM() { String[] systemIds = {"system.dtd"}; InputSource[] returnValues = {new InputSource(new StringReader(dtd_systemResolved))}; @@ -232,7 +243,6 @@ public class CatalogSupport extends CatalogSupportBase { DataProvider: for testing the StAX parser Data: set use_catalog, use_catalog, catalog file, xml file, handler, expected result string */ - @DataProvider(name = "data_StAXA") public Object[][] getDataStAX() { return new Object[][]{ @@ -250,7 +260,6 @@ public class CatalogSupport extends CatalogSupportBase { DataProvider: for testing Schema validation Data: set use_catalog, use_catalog, catalog file, xsd file, a LSResourceResolver */ - @DataProvider(name = "data_SchemaA") public Object[][] getDataSchema() { String[] systemIds = {"pathto/XMLSchema.dtd", "datatypes.dtd"}; XmlInput[] returnValues = {new XmlInput(null, dtd_xmlSchema, null), new XmlInput(null, dtd_datatypes, null)}; @@ -285,7 +294,6 @@ public class CatalogSupport extends CatalogSupportBase { DataProvider: for testing Schema Validator Data: source, resolver1, resolver2, catalog1, a catalog2 */ - @DataProvider(name = "data_ValidatorA") public Object[][] getDataValidator() { DOMSource ds = getDOMSource(xml_val_test, xml_val_test_id, false, true, xml_catalog); @@ -325,7 +333,6 @@ public class CatalogSupport extends CatalogSupportBase { DataProvider: for testing XSL import and include Data: set use_catalog, use_catalog, catalog file, xsl file, xml file, a URIResolver, expected result */ - @DataProvider(name = "data_XSLA") public Object[][] getDataXSL() { // XSLInclude.xsl has one import XSLImport_html.xsl and two includes, // XSLInclude_header.xsl and XSLInclude_footer.xsl; diff --git a/test/jaxp/javax/xml/jaxp/unittest/catalog/CatalogSupport1.java b/test/jaxp/javax/xml/jaxp/unittest/catalog/CatalogSupport1.java index 2025e2d14d3..d8e7f8bb77e 100644 --- a/test/jaxp/javax/xml/jaxp/unittest/catalog/CatalogSupport1.java +++ b/test/jaxp/javax/xml/jaxp/unittest/catalog/CatalogSupport1.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * 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,14 @@ package catalog; -import static jaxp.library.JAXPTestUtilities.clearSystemProperty; -import static jaxp.library.JAXPTestUtilities.setSystemProperty; - -import java.io.File; -import java.io.StringReader; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.TestInstance.Lifecycle; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import org.w3c.dom.ls.LSResourceResolver; +import org.xml.sax.InputSource; import javax.xml.catalog.CatalogFeatures.Feature; import javax.xml.stream.XMLResolver; @@ -37,19 +40,14 @@ import javax.xml.transform.dom.DOMSource; import javax.xml.transform.sax.SAXSource; import javax.xml.transform.stax.StAXSource; import javax.xml.transform.stream.StreamSource; - -import org.testng.annotations.AfterClass; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; -import org.w3c.dom.ls.LSResourceResolver; -import org.xml.sax.InputSource; +import java.io.File; +import java.io.StringReader; /* * @test * @bug 8158084 8162438 8162442 8166220 * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest - * @run testng/othervm catalog.CatalogSupport1 + * @run junit/othervm catalog.CatalogSupport1 * @summary extends CatalogSupport, verifies that the catalog file can be set * using the System property. */ @@ -60,25 +58,27 @@ import org.xml.sax.InputSource; * * @author huizhe.wang@oracle.com */ +@TestInstance(Lifecycle.PER_CLASS) public class CatalogSupport1 extends CatalogSupportBase { /* * Initializing fields */ - @BeforeClass + @BeforeAll public void setUpClass() throws Exception { setUp(); - setSystemProperty(Feature.FILES.getPropertyName(), xml_catalog); + System.setProperty(Feature.FILES.getPropertyName(), xml_catalog); } - @AfterClass + @AfterAll public void tearDownClass() throws Exception { - clearSystemProperty(Feature.FILES.getPropertyName()); + System.clearProperty(Feature.FILES.getPropertyName()); } /* Verifies the Catalog support on SAXParser. */ - @Test(dataProvider = "data_SAXC") + @ParameterizedTest + @MethodSource("getDataSAXC") public void testSAXC(boolean setUseCatalog, boolean useCatalog, String catalog, String xml, MyHandler handler, String expected) throws Exception { testSAX(setUseCatalog, useCatalog, catalog, xml, handler, expected); } @@ -86,7 +86,8 @@ public class CatalogSupport1 extends CatalogSupportBase { /* Verifies the Catalog support on XMLReader. */ - @Test(dataProvider = "data_SAXC") + @ParameterizedTest + @MethodSource("getDataSAXC") public void testXMLReaderC(boolean setUseCatalog, boolean useCatalog, String catalog, String xml, MyHandler handler, String expected) throws Exception { testXMLReader(setUseCatalog, useCatalog, catalog, xml, handler, expected); } @@ -94,7 +95,8 @@ public class CatalogSupport1 extends CatalogSupportBase { /* Verifies the Catalog support on XInclude. */ - @Test(dataProvider = "data_XIC") + @ParameterizedTest + @MethodSource("getDataXIC") public void testXIncludeC(boolean setUseCatalog, boolean useCatalog, String catalog, String xml, MyHandler handler, String expected) throws Exception { testXInclude(setUseCatalog, useCatalog, catalog, xml, handler, expected); } @@ -102,7 +104,8 @@ public class CatalogSupport1 extends CatalogSupportBase { /* Verifies the Catalog support on DOM parser. */ - @Test(dataProvider = "data_DOMC") + @ParameterizedTest + @MethodSource("getDataDOMC") public void testDOMC(boolean setUseCatalog, boolean useCatalog, String catalog, String xml, MyHandler handler, String expected) throws Exception { testDOM(setUseCatalog, useCatalog, catalog, xml, handler, expected); } @@ -110,7 +113,8 @@ public class CatalogSupport1 extends CatalogSupportBase { /* Verifies the Catalog support on XMLStreamReader. */ - @Test(dataProvider = "data_StAXC") + @ParameterizedTest + @MethodSource("getDataStAX") public void testStAXC(boolean setUseCatalog, boolean useCatalog, String catalog, String xml, XMLResolver resolver, String expected) throws Exception { testStAX(setUseCatalog, useCatalog, catalog, xml, resolver, expected); @@ -120,7 +124,8 @@ public class CatalogSupport1 extends CatalogSupportBase { Verifies the Catalog support on resolving DTD, xsd import and include in Schema files. */ - @Test(dataProvider = "data_SchemaC") + @ParameterizedTest + @MethodSource("getDataSchemaC") public void testValidationC(boolean setUseCatalog, boolean useCatalog, String catalog, String xsd, LSResourceResolver resolver) throws Exception { @@ -131,7 +136,8 @@ public class CatalogSupport1 extends CatalogSupportBase { @bug 8158084 8162438 these tests also verifies the fix for 8162438 Verifies the Catalog support on the Schema Validator. */ - @Test(dataProvider = "data_ValidatorC") + @ParameterizedTest + @MethodSource("getDataValidator") public void testValidatorA(boolean setUseCatalog1, boolean setUseCatalog2, boolean useCatalog, Source source, LSResourceResolver resolver1, LSResourceResolver resolver2, String catalog1, String catalog2) @@ -144,7 +150,8 @@ public class CatalogSupport1 extends CatalogSupportBase { Verifies the Catalog support on resolving DTD, xsl import and include in XSL files. */ - @Test(dataProvider = "data_XSLC") + @ParameterizedTest + @MethodSource("getDataXSLC") public void testXSLImportC(boolean setUseCatalog, boolean useCatalog, String catalog, SAXSource xsl, StreamSource xml, URIResolver resolver, String expected) throws Exception { @@ -156,7 +163,8 @@ public class CatalogSupport1 extends CatalogSupportBase { Verifies the Catalog support on resolving DTD, xsl import and include in XSL files. */ - @Test(dataProvider = "data_XSLC") + @ParameterizedTest + @MethodSource("getDataXSLC") public void testXSLImportWTemplatesC(boolean setUseCatalog, boolean useCatalog, String catalog, SAXSource xsl, StreamSource xml, URIResolver resolver, String expected) throws Exception { testXSLImportWTemplates(setUseCatalog, useCatalog, catalog, xsl, xml, resolver, expected); @@ -166,7 +174,6 @@ public class CatalogSupport1 extends CatalogSupportBase { DataProvider: for testing the SAX parser Data: set use_catalog, use_catalog, catalog file, xml file, handler, expected result string */ - @DataProvider(name = "data_SAXC") public Object[][] getDataSAXC() { return new Object[][]{ {false, true, null, xml_system, new MyHandler(elementInSystem), expectedWCatalog} @@ -178,7 +185,6 @@ public class CatalogSupport1 extends CatalogSupportBase { DataProvider: for testing XInclude Data: set use_catalog, use_catalog, catalog file, xml file, handler, expected result string */ - @DataProvider(name = "data_XIC") public Object[][] getDataXIC() { return new Object[][]{ {false, true, null, xml_xInclude, new MyHandler(elementInXISimple), contentInUIutf8Catalog}, @@ -189,7 +195,6 @@ public class CatalogSupport1 extends CatalogSupportBase { DataProvider: for testing DOM parser Data: set use_catalog, use_catalog, catalog file, xml file, handler, expected result string */ - @DataProvider(name = "data_DOMC") public Object[][] getDataDOMC() { return new Object[][]{ {false, true, null, xml_system, new MyHandler(elementInSystem), expectedWCatalog} @@ -200,7 +205,6 @@ public class CatalogSupport1 extends CatalogSupportBase { DataProvider: for testing the StAX parser Data: set use_catalog, use_catalog, catalog file, xml file, handler, expected result string */ - @DataProvider(name = "data_StAXC") public Object[][] getDataStAX() { return new Object[][]{ @@ -212,7 +216,6 @@ public class CatalogSupport1 extends CatalogSupportBase { DataProvider: for testing Schema validation Data: set use_catalog, use_catalog, catalog file, xsd file, a LSResourceResolver */ - @DataProvider(name = "data_SchemaC") public Object[][] getDataSchemaC() { return new Object[][]{ @@ -230,7 +233,6 @@ public class CatalogSupport1 extends CatalogSupportBase { DataProvider: for testing Schema Validator Data: source, resolver1, resolver2, catalog1, a catalog2 */ - @DataProvider(name = "data_ValidatorC") public Object[][] getDataValidator() { DOMSource ds = getDOMSource(xml_val_test, xml_val_test_id, false, true, null); @@ -270,7 +272,6 @@ public class CatalogSupport1 extends CatalogSupportBase { DataProvider: for testing XSL import and include Data: set use_catalog, use_catalog, catalog file, xsl file, xml file, a URIResolver, expected */ - @DataProvider(name = "data_XSLC") public Object[][] getDataXSLC() { SAXSource xslSourceDTD = new SAXSource(new InputSource(new StringReader(xsl_includeDTD))); StreamSource xmlSourceDTD = new StreamSource(new StringReader(xml_xslDTD)); diff --git a/test/jaxp/javax/xml/jaxp/unittest/catalog/CatalogSupport2.java b/test/jaxp/javax/xml/jaxp/unittest/catalog/CatalogSupport2.java index ecb88de1932..2346a8577b0 100644 --- a/test/jaxp/javax/xml/jaxp/unittest/catalog/CatalogSupport2.java +++ b/test/jaxp/javax/xml/jaxp/unittest/catalog/CatalogSupport2.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,13 +23,17 @@ package catalog; -import static jaxp.library.JAXPTestUtilities.clearSystemProperty; -import static jaxp.library.JAXPTestUtilities.getSystemProperty; -import static jaxp.library.JAXPTestUtilities.setSystemProperty; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.TestInstance.Lifecycle; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import org.w3c.dom.ls.LSResourceResolver; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; -import java.io.File; -import java.io.IOException; -import java.io.StringReader; import javax.xml.stream.XMLResolver; import javax.xml.stream.XMLStreamException; import javax.xml.transform.Source; @@ -39,21 +43,16 @@ import javax.xml.transform.dom.DOMSource; import javax.xml.transform.sax.SAXSource; import javax.xml.transform.stax.StAXSource; import javax.xml.transform.stream.StreamSource; +import java.io.File; +import java.io.StringReader; -import org.testng.annotations.AfterClass; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; -import org.w3c.dom.ls.LSResourceResolver; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; -import org.xml.sax.SAXParseException; +import static org.junit.jupiter.api.Assertions.assertThrows; /* * @test * @bug 8158084 8162438 8162442 8163535 8166220 8344800 * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest - * @run testng/othervm catalog.CatalogSupport2 + * @run junit/othervm catalog.CatalogSupport2 * @summary extends CatalogSupport tests, verifies that the use of the Catalog may * be disabled through the System property. */ @@ -65,108 +64,130 @@ import org.xml.sax.SAXParseException; * * @author huizhe.wang@oracle.com */ +@TestInstance(Lifecycle.PER_CLASS) public class CatalogSupport2 extends CatalogSupportBase { static final String TTIMEOUTREAD = "sun.net.client.defaultReadTimeout"; static final String TIMEOUTCONNECT = "sun.net.client.defaultConnectTimeout"; - static String timeoutRead = getSystemProperty(TTIMEOUTREAD); - static String timeoutConnect = getSystemProperty(TIMEOUTCONNECT); + static String timeoutRead = System.getProperty(TTIMEOUTREAD); + static String timeoutConnect = System.getProperty(TIMEOUTCONNECT); /* * Initializing fields */ - @BeforeClass + @BeforeAll public void setUpClass() throws Exception { setUp(); - setSystemProperty(SP_USE_CATALOG, "false"); - setSystemProperty(SP_ACCESS_EXTERNAL_DTD, "file"); - timeoutRead = getSystemProperty(TTIMEOUTREAD); - timeoutConnect = getSystemProperty(TIMEOUTCONNECT); - setSystemProperty(TTIMEOUTREAD, "1000"); - setSystemProperty(TIMEOUTCONNECT, "1000"); + System.setProperty(SP_USE_CATALOG, "false"); + System.setProperty(SP_ACCESS_EXTERNAL_DTD, "file"); + timeoutRead = System.getProperty(TTIMEOUTREAD); + timeoutConnect = System.getProperty(TIMEOUTCONNECT); + System.setProperty(TTIMEOUTREAD, "1000"); + System.setProperty(TIMEOUTCONNECT, "1000"); } - @AfterClass - public void tearDownClass() throws Exception { - clearSystemProperty(SP_USE_CATALOG); - clearSystemProperty(SP_ACCESS_EXTERNAL_DTD); - setSystemProperty(TIMEOUTCONNECT, "-1"); - setSystemProperty(TTIMEOUTREAD, "-1"); + @AfterAll + public void tearDownClass() { + System.clearProperty(SP_USE_CATALOG); + System.clearProperty(SP_ACCESS_EXTERNAL_DTD); + System.setProperty(TIMEOUTCONNECT, "-1"); + System.setProperty(TTIMEOUTREAD, "-1"); } /* Verifies the Catalog support on SAXParser. */ - @Test(dataProvider = "data_SAXC", expectedExceptions = SAXParseException.class) + @ParameterizedTest + @MethodSource("getDataSAXC") public void testSAXC(boolean setUseCatalog, boolean useCatalog, String catalog, String xml, MyHandler handler, String expected) throws Exception { - testSAX(setUseCatalog, useCatalog, catalog, xml, handler, expected); + assertThrows( + SAXParseException.class, + () -> testSAX(setUseCatalog, useCatalog, catalog, xml, handler, expected)); } /* Verifies the Catalog support on XMLReader. */ - @Test(dataProvider = "data_SAXC", expectedExceptions = SAXParseException.class) + @ParameterizedTest + @MethodSource("getDataSAXC") public void testXMLReaderC(boolean setUseCatalog, boolean useCatalog, String catalog, - String xml, MyHandler handler, String expected) throws Exception { - testXMLReader(setUseCatalog, useCatalog, catalog, xml, handler, expected); + String xml, MyHandler handler, String expected) throws Exception { + assertThrows( + SAXParseException.class, + () -> testXMLReader(setUseCatalog, useCatalog, catalog, xml, handler, expected)); } /* Verifies the Catalog support on XInclude. */ - @Test(dataProvider = "data_XIC", expectedExceptions = SAXParseException.class) + @ParameterizedTest + @MethodSource("getDataXIC") public void testXIncludeC(boolean setUseCatalog, boolean useCatalog, String catalog, - String xml, MyHandler handler, String expected) throws Exception { - testXInclude(setUseCatalog, useCatalog, catalog, xml, handler, expected); + String xml, MyHandler handler, String expected) throws Exception { + assertThrows( + SAXParseException.class, + () -> testXInclude(setUseCatalog, useCatalog, catalog, xml, handler, expected)); } /* Verifies the Catalog support on DOM parser. */ - @Test(dataProvider = "data_DOMC", expectedExceptions = SAXParseException.class) + @ParameterizedTest + @MethodSource("getDataDOMC") public void testDOMC(boolean setUseCatalog, boolean useCatalog, String catalog, - String xml, MyHandler handler, String expected) throws Exception { - testDOM(setUseCatalog, useCatalog, catalog, xml, handler, expected); + String xml, MyHandler handler, String expected) throws Exception { + assertThrows( + SAXParseException.class, + () -> testDOM(setUseCatalog, useCatalog, catalog, xml, handler, expected)); } /* Verifies the Catalog support on XMLStreamReader. */ - @Test(dataProvider = "data_StAXC", expectedExceptions = XMLStreamException.class) + @ParameterizedTest + @MethodSource("getDataStAX") public void testStAXC(boolean setUseCatalog, boolean useCatalog, String catalog, - String xml, XMLResolver resolver, String expected) throws Exception { - testStAXNegative(setUseCatalog, useCatalog, catalog, xml, resolver, expected); + String xml, XMLResolver resolver, String expected) throws Exception { + assertThrows( + XMLStreamException.class, + () -> testStAXNegative(setUseCatalog, useCatalog, catalog, xml, resolver, expected)); } /* Verifies the Catalog support on resolving DTD, xsd import and include in Schema files. */ - @Test(dataProvider = "data_SchemaC", expectedExceptions = SAXParseException.class) + @ParameterizedTest + @MethodSource("getDataSchemaC") public void testValidationC(boolean setUseCatalog, boolean useCatalog, String catalog, - String xsd, LSResourceResolver resolver) - throws Exception { - testValidation(setUseCatalog, useCatalog, catalog, xsd, resolver) ; + String xsd, LSResourceResolver resolver) { + assertThrows( + SAXParseException.class, + () -> testValidation(setUseCatalog, useCatalog, catalog, xsd, resolver)); } - @Test(dataProvider = "data_ValidatorC", expectedExceptions = {SAXException.class, IOException.class}) + @ParameterizedTest + @MethodSource("getDataValidator") public void testValidatorC(boolean setUseCatalog1, boolean setUseCatalog2, boolean useCatalog, - Source source, LSResourceResolver resolver1, LSResourceResolver resolver2, - String catalog1, String catalog2) - throws Exception { - testValidator(setUseCatalog1, setUseCatalog2, useCatalog, source, - resolver1, resolver2, catalog1, catalog2); + Source source, LSResourceResolver resolver1, LSResourceResolver resolver2, + String catalog1, String catalog2) { + assertThrows( + SAXException.class, + () -> testValidator(setUseCatalog1, setUseCatalog2, useCatalog, source, resolver1, resolver2, catalog1, catalog2)); } /* Verifies the Catalog support on resolving DTD, xsl import and include in XSL files. */ - @Test(dataProvider = "data_XSLC", expectedExceptions = TransformerException.class) + @ParameterizedTest + @MethodSource("getDataXSLC") public void testXSLImportC(boolean setUseCatalog, boolean useCatalog, String catalog, - SAXSource xsl, StreamSource xml, URIResolver resolver, String expected) throws Exception { + SAXSource xsl, StreamSource xml, URIResolver resolver, String expected) { - testXSLImport(setUseCatalog, useCatalog, catalog, xsl, xml, resolver, expected); + assertThrows( + TransformerException.class, + () -> testXSLImport(setUseCatalog, useCatalog, catalog, xsl, xml, resolver, expected)); } /* @@ -174,17 +195,19 @@ public class CatalogSupport2 extends CatalogSupportBase { Verifies the Catalog support on resolving DTD, xsl import and include in XSL files. */ - @Test(dataProvider = "data_XSLC", expectedExceptions = TransformerException.class) + @ParameterizedTest + @MethodSource("getDataXSLC") public void testXSLImportWTemplatesC(boolean setUseCatalog, boolean useCatalog, String catalog, - SAXSource xsl, StreamSource xml, URIResolver resolver, String expected) throws Exception { - testXSLImportWTemplates(setUseCatalog, useCatalog, catalog, xsl, xml, resolver, expected); + SAXSource xsl, StreamSource xml, URIResolver resolver, String expected) { + assertThrows( + TransformerException.class, + () -> testXSLImportWTemplates(setUseCatalog, useCatalog, catalog, xsl, xml, resolver, expected)); } /* DataProvider: for testing the SAX parser Data: set use_catalog, use_catalog, catalog file, xml file, handler, expected result string */ - @DataProvider(name = "data_SAXC") public Object[][] getDataSAXC() { return new Object[][]{ {false, true, xml_catalog, xml_system, new MyHandler(elementInSystem), expectedWCatalog} @@ -196,7 +219,6 @@ public class CatalogSupport2 extends CatalogSupportBase { DataProvider: for testing XInclude Data: set use_catalog, use_catalog, catalog file, xml file, handler, expected result string */ - @DataProvider(name = "data_XIC") public Object[][] getDataXIC() { return new Object[][]{ {false, true, xml_catalog, xml_xInclude, new MyHandler(elementInXISimple), contentInUIutf8Catalog}, @@ -207,7 +229,6 @@ public class CatalogSupport2 extends CatalogSupportBase { DataProvider: for testing DOM parser Data: set use_catalog, use_catalog, catalog file, xml file, handler, expected result string */ - @DataProvider(name = "data_DOMC") public Object[][] getDataDOMC() { return new Object[][]{ {false, true, xml_catalog, xml_system, new MyHandler(elementInSystem), expectedWCatalog} @@ -218,7 +239,6 @@ public class CatalogSupport2 extends CatalogSupportBase { DataProvider: for testing the StAX parser Data: set use_catalog, use_catalog, catalog file, xml file, handler, expected result string */ - @DataProvider(name = "data_StAXC") public Object[][] getDataStAX() { return new Object[][]{ {false, true, xml_catalog, xml_system, null, "null"}, @@ -229,7 +249,6 @@ public class CatalogSupport2 extends CatalogSupportBase { DataProvider: for testing Schema validation Data: set use_catalog, use_catalog, catalog file, xsd file, a LSResourceResolver */ - @DataProvider(name = "data_SchemaC") public Object[][] getDataSchemaC() { return new Object[][]{ @@ -247,7 +266,6 @@ public class CatalogSupport2 extends CatalogSupportBase { DataProvider: for testing Schema Validator Data: source, resolver1, resolver2, catalog1, a catalog2 */ - @DataProvider(name = "data_ValidatorC") public Object[][] getDataValidator() { DOMSource ds = getDOMSource(xml_val_test, xml_val_test_id, true, true, xml_catalog); @@ -276,7 +294,6 @@ public class CatalogSupport2 extends CatalogSupportBase { DataProvider: for testing XSL import and include Data: set use_catalog, use_catalog, catalog file, xsl file, xml file, a URIResolver, expected */ - @DataProvider(name = "data_XSLC") public Object[][] getDataXSLC() { SAXSource xslSourceDTD = new SAXSource(new InputSource(new StringReader(xsl_includeDTD))); StreamSource xmlSourceDTD = new StreamSource(new StringReader(xml_xslDTD)); diff --git a/test/jaxp/javax/xml/jaxp/unittest/catalog/CatalogSupport3.java b/test/jaxp/javax/xml/jaxp/unittest/catalog/CatalogSupport3.java index 4d44ce80fe6..cd06c2b6cba 100644 --- a/test/jaxp/javax/xml/jaxp/unittest/catalog/CatalogSupport3.java +++ b/test/jaxp/javax/xml/jaxp/unittest/catalog/CatalogSupport3.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,13 +23,17 @@ package catalog; -import static jaxp.library.JAXPTestUtilities.clearSystemProperty; -import static jaxp.library.JAXPTestUtilities.getSystemProperty; -import static jaxp.library.JAXPTestUtilities.setSystemProperty; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.TestInstance.Lifecycle; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import org.w3c.dom.ls.LSResourceResolver; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; -import java.io.File; -import java.io.IOException; -import java.io.StringReader; import javax.xml.stream.XMLResolver; import javax.xml.stream.XMLStreamException; import javax.xml.transform.Source; @@ -39,21 +43,16 @@ import javax.xml.transform.dom.DOMSource; import javax.xml.transform.sax.SAXSource; import javax.xml.transform.stax.StAXSource; import javax.xml.transform.stream.StreamSource; +import java.io.File; +import java.io.StringReader; -import org.testng.annotations.AfterClass; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; -import org.w3c.dom.ls.LSResourceResolver; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; -import org.xml.sax.SAXParseException; +import static org.junit.jupiter.api.Assertions.assertThrows; /* * @test * @bug 8158084 8162438 8162442 8163535 8166220 8344800 * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest - * @run testng/othervm catalog.CatalogSupport3 + * @run junit/othervm catalog.CatalogSupport3 * @summary extends CatalogSupport tests, verifies that the use of the Catalog may * be disabled through the API property. */ @@ -65,109 +64,131 @@ import org.xml.sax.SAXParseException; * * @author huizhe.wang@oracle.com */ +@TestInstance(Lifecycle.PER_CLASS) public class CatalogSupport3 extends CatalogSupportBase { static final String TTIMEOUTREAD = "sun.net.client.defaultReadTimeout"; static final String TIMEOUTCONNECT = "sun.net.client.defaultConnectTimeout"; - static String timeoutRead = getSystemProperty(TTIMEOUTREAD); - static String timeoutConnect = getSystemProperty(TIMEOUTCONNECT); + static String timeoutRead = System.getProperty(TTIMEOUTREAD); + static String timeoutConnect = System.getProperty(TIMEOUTCONNECT); /* * Initializing fields */ - @BeforeClass + @BeforeAll public void setUpClass() throws Exception { setUp(); - timeoutRead = getSystemProperty(TTIMEOUTREAD); - timeoutConnect = getSystemProperty(TIMEOUTCONNECT); - setSystemProperty(TTIMEOUTREAD, "1000"); - setSystemProperty(TIMEOUTCONNECT, "1000"); - setSystemProperty(SP_ACCESS_EXTERNAL_DTD, "file"); + timeoutRead = System.getProperty(TTIMEOUTREAD); + timeoutConnect = System.getProperty(TIMEOUTCONNECT); + System.setProperty(TTIMEOUTREAD, "1000"); + System.setProperty(TIMEOUTCONNECT, "1000"); + System.setProperty(SP_ACCESS_EXTERNAL_DTD, "file"); } - @AfterClass - public void tearDownClass() throws Exception { - setSystemProperty(TIMEOUTCONNECT, "-1"); - setSystemProperty(TTIMEOUTREAD, "-1"); - clearSystemProperty(SP_ACCESS_EXTERNAL_DTD); + @AfterAll + public void tearDownClass() { + System.setProperty(TIMEOUTCONNECT, "-1"); + System.setProperty(TTIMEOUTREAD, "-1"); + System.clearProperty(SP_ACCESS_EXTERNAL_DTD); } /* Verifies the Catalog support on SAXParser. */ - @Test(dataProvider = "data_SAXC", expectedExceptions = SAXParseException.class) + @ParameterizedTest + @MethodSource("getDataSAXC") public void testSAXC(boolean setUseCatalog, boolean useCatalog, String catalog, - String xml, MyHandler handler, String expected) throws Exception { - testSAX(setUseCatalog, useCatalog, catalog, xml, handler, expected); + String xml, MyHandler handler, String expected) { + assertThrows( + SAXParseException.class, + () -> testSAX(setUseCatalog, useCatalog, catalog, xml, handler, expected)); } /* Verifies the Catalog support on XMLReader. */ - @Test(dataProvider = "data_SAXC", expectedExceptions = SAXParseException.class) + @ParameterizedTest + @MethodSource("getDataSAXC") public void testXMLReaderC(boolean setUseCatalog, boolean useCatalog, String catalog, - String xml, MyHandler handler, String expected) throws Exception { - testXMLReader(setUseCatalog, useCatalog, catalog, xml, handler, expected); + String xml, MyHandler handler, String expected) { + assertThrows( + SAXParseException.class, + () -> testXMLReader(setUseCatalog, useCatalog, catalog, xml, handler, expected)); } /* Verifies the Catalog support on XInclude. */ - @Test(dataProvider = "data_XIC", expectedExceptions = SAXParseException.class) + @ParameterizedTest + @MethodSource("getDataXIC") public void testXIncludeC(boolean setUseCatalog, boolean useCatalog, String catalog, - String xml, MyHandler handler, String expected) throws Exception { - testXInclude(setUseCatalog, useCatalog, catalog, xml, handler, expected); + String xml, MyHandler handler, String expected) { + assertThrows( + SAXParseException.class, + () -> testXInclude(setUseCatalog, useCatalog, catalog, xml, handler, expected)); } /* Verifies the Catalog support on DOM parser. */ - @Test(dataProvider = "data_DOMC", expectedExceptions = SAXParseException.class) + @ParameterizedTest + @MethodSource("getDataDOMC") public void testDOMC(boolean setUseCatalog, boolean useCatalog, String catalog, - String xml, MyHandler handler, String expected) throws Exception { - testDOM(setUseCatalog, useCatalog, catalog, xml, handler, expected); + String xml, MyHandler handler, String expected) { + assertThrows( + SAXParseException.class, + () -> testDOM(setUseCatalog, useCatalog, catalog, xml, handler, expected)); } /* Verifies the Catalog support on XMLStreamReader. */ - @Test(dataProvider = "data_StAXC", expectedExceptions = XMLStreamException.class) + @ParameterizedTest + @MethodSource("getDataStAX") public void testStAXC(boolean setUseCatalog, boolean useCatalog, String catalog, - String xml, XMLResolver resolver, String expected) throws Exception { - testStAXNegative(setUseCatalog, useCatalog, catalog, xml, resolver, expected); + String xml, XMLResolver resolver, String expected) { + assertThrows( + XMLStreamException.class, + () -> testStAXNegative(setUseCatalog, useCatalog, catalog, xml, resolver, expected)); } /* Verifies the Catalog support on resolving DTD, xsd import and include in Schema files. */ - @Test(dataProvider = "data_SchemaC", expectedExceptions = SAXParseException.class) + @ParameterizedTest + @MethodSource("getDataSchemaC") public void testValidationC(boolean setUseCatalog, boolean useCatalog, String catalog, - String xsd, LSResourceResolver resolver) - throws Exception { - testValidation(setUseCatalog, useCatalog, catalog, xsd, resolver) ; + String xsd, LSResourceResolver resolver) { + assertThrows( + SAXParseException.class, + () -> testValidation(setUseCatalog, useCatalog, catalog, xsd, resolver)); } /* @bug 8158084 8162438 these tests also verifies the fix for 8162438 Verifies the Catalog support on the Schema Validator. */ - @Test(dataProvider = "data_ValidatorC", expectedExceptions = {SAXException.class, IOException.class}) + @ParameterizedTest + @MethodSource("getDataValidator") public void testValidatorC(boolean setUseCatalog1, boolean setUseCatalog2, boolean useCatalog, - Source source, LSResourceResolver resolver1, LSResourceResolver resolver2, - String catalog1, String catalog2) - throws Exception { - testValidator(setUseCatalog1, setUseCatalog2, useCatalog, source, - resolver1, resolver2, catalog1, catalog2); + Source source, LSResourceResolver resolver1, LSResourceResolver resolver2, + String catalog1, String catalog2) { + assertThrows( + SAXException.class, + () -> testValidator(setUseCatalog1, setUseCatalog2, useCatalog, source, resolver1, resolver2, catalog1, catalog2)); } /* Verifies the Catalog support on resolving DTD, xsl import and include in XSL files. */ - @Test(dataProvider = "data_XSLC", expectedExceptions = TransformerException.class) + @ParameterizedTest + @MethodSource("getDataXSLC") public void testXSLImportC(boolean setUseCatalog, boolean useCatalog, String catalog, SAXSource xsl, StreamSource xml, URIResolver resolver, String expected) throws Exception { - testXSLImport(setUseCatalog, useCatalog, catalog, xsl, xml, resolver, expected); + assertThrows( + TransformerException.class, + () -> testXSLImport(setUseCatalog, useCatalog, catalog, xsl, xml, resolver, expected)); } /* @@ -175,18 +196,20 @@ public class CatalogSupport3 extends CatalogSupportBase { Verifies the Catalog support on resolving DTD, xsl import and include in XSL files. */ - @Test(dataProvider = "data_XSLC", expectedExceptions = TransformerException.class) + @ParameterizedTest + @MethodSource("getDataXSLC") public void testXSLImportWTemplatesC(boolean setUseCatalog, boolean useCatalog, String catalog, - SAXSource xsl, StreamSource xml, - URIResolver resolver, String expected) throws Exception { - testXSLImportWTemplates(setUseCatalog, useCatalog, catalog, xsl, xml, resolver, expected); + SAXSource xsl, StreamSource xml, + URIResolver resolver, String expected) throws Exception { + assertThrows( + TransformerException.class, + () -> testXSLImportWTemplates(setUseCatalog, useCatalog, catalog, xsl, xml, resolver, expected)); } /* DataProvider: for testing the SAX parser Data: set use_catalog, use_catalog, catalog file, xml file, handler, expected result string */ - @DataProvider(name = "data_SAXC") public Object[][] getDataSAXC() { return new Object[][]{ {true, false, xml_catalog, xml_system, new MyHandler(elementInSystem), expectedWCatalog} @@ -198,7 +221,6 @@ public class CatalogSupport3 extends CatalogSupportBase { DataProvider: for testing XInclude Data: set use_catalog, use_catalog, catalog file, xml file, handler, expected result string */ - @DataProvider(name = "data_XIC") public Object[][] getDataXIC() { return new Object[][]{ {true, false, xml_catalog, xml_xInclude, new MyHandler(elementInXISimple), contentInUIutf8Catalog}, @@ -209,7 +231,6 @@ public class CatalogSupport3 extends CatalogSupportBase { DataProvider: for testing DOM parser Data: set use_catalog, use_catalog, catalog file, xml file, handler, expected result string */ - @DataProvider(name = "data_DOMC") public Object[][] getDataDOMC() { return new Object[][]{ {true, false, xml_catalog, xml_system, new MyHandler(elementInSystem), expectedWCatalog} @@ -220,7 +241,6 @@ public class CatalogSupport3 extends CatalogSupportBase { DataProvider: for testing the StAX parser Data: set use_catalog, use_catalog, catalog file, xml file, handler, expected result string */ - @DataProvider(name = "data_StAXC") public Object[][] getDataStAX() { return new Object[][]{ {true, false, xml_catalog, xml_system, null, "null"}, @@ -231,7 +251,6 @@ public class CatalogSupport3 extends CatalogSupportBase { DataProvider: for testing Schema validation Data: set use_catalog, use_catalog, catalog file, xsd file, a LSResourceResolver */ - @DataProvider(name = "data_SchemaC") public Object[][] getDataSchemaC() { return new Object[][]{ @@ -249,7 +268,6 @@ public class CatalogSupport3 extends CatalogSupportBase { DataProvider: for testing Schema Validator Data: source, resolver1, resolver2, catalog1, a catalog2 */ - @DataProvider(name = "data_ValidatorC") public Object[][] getDataValidator() { DOMSource ds = getDOMSource(xml_val_test, xml_val_test_id, false, true, xml_catalog); @@ -287,7 +305,6 @@ public class CatalogSupport3 extends CatalogSupportBase { DataProvider: for testing XSL import and include Data: set use_catalog, use_catalog, catalog file, xsl file, xml file, a URIResolver, expected */ - @DataProvider(name = "data_XSLC") public Object[][] getDataXSLC() { SAXSource xslSourceDTD = new SAXSource(new InputSource(new StringReader(xsl_includeDTD))); StreamSource xmlSourceDTD = new StreamSource(new StringReader(xml_xslDTD)); diff --git a/test/jaxp/javax/xml/jaxp/unittest/catalog/CatalogSupport4.java b/test/jaxp/javax/xml/jaxp/unittest/catalog/CatalogSupport4.java index 8d06cc61355..f666e198228 100644 --- a/test/jaxp/javax/xml/jaxp/unittest/catalog/CatalogSupport4.java +++ b/test/jaxp/javax/xml/jaxp/unittest/catalog/CatalogSupport4.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * 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,15 @@ package catalog; -import static jaxp.library.JAXPTestUtilities.clearSystemProperty; -import static jaxp.library.JAXPTestUtilities.setSystemProperty; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.TestInstance.Lifecycle; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import org.w3c.dom.ls.LSResourceResolver; +import org.xml.sax.InputSource; -import java.io.File; -import java.io.StringReader; import javax.xml.stream.XMLResolver; import javax.xml.transform.Source; import javax.xml.transform.URIResolver; @@ -35,19 +39,14 @@ import javax.xml.transform.dom.DOMSource; import javax.xml.transform.sax.SAXSource; import javax.xml.transform.stax.StAXSource; import javax.xml.transform.stream.StreamSource; +import java.io.File; +import java.io.StringReader; -import org.testng.annotations.AfterClass; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; -import org.w3c.dom.ls.LSResourceResolver; -import org.xml.sax.InputSource; - -/** +/* * @test * @bug 8158084 8162438 8162442 8166220 * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest - * @run testng/othervm catalog.CatalogSupport4 + * @run junit/othervm catalog.CatalogSupport4 * @summary verifies the overriding over of the USE_CATALOG feature. Extending * CatalogSupport tests, the USE_CATALOG is turned off system-wide, however, * a JAXP processor may decide to use Catalog by enabling it through the factory @@ -62,26 +61,28 @@ import org.xml.sax.InputSource; * * @author huizhe.wang@oracle.com */ +@TestInstance(Lifecycle.PER_CLASS) public class CatalogSupport4 extends CatalogSupportBase { /* * Initializing fields */ - @BeforeClass + @BeforeAll public void setUpClass() throws Exception { setUp(); //turn off USE_CATALOG system-wide - setSystemProperty(SP_USE_CATALOG, "false"); + System.setProperty(SP_USE_CATALOG, "false"); } - @AfterClass + @AfterAll public void tearDownClass() throws Exception { - clearSystemProperty(SP_USE_CATALOG); + System.clearProperty(SP_USE_CATALOG); } /* Verifies the Catalog support on SAXParser. */ - @Test(dataProvider = "data_SAXA") + @ParameterizedTest + @MethodSource("getDataSAX") public void testSAXA(boolean setUseCatalog, boolean useCatalog, String catalog, String xml, MyHandler handler, String expected) throws Exception { testSAX(setUseCatalog, useCatalog, catalog, xml, handler, expected); @@ -90,7 +91,8 @@ public class CatalogSupport4 extends CatalogSupportBase { /* Verifies the Catalog support on XMLReader. */ - @Test(dataProvider = "data_SAXA") + @ParameterizedTest + @MethodSource("getDataSAX") public void testXMLReaderA(boolean setUseCatalog, boolean useCatalog, String catalog, String xml, MyHandler handler, String expected) throws Exception { testXMLReader(setUseCatalog, useCatalog, catalog, xml, handler, expected); @@ -99,7 +101,8 @@ public class CatalogSupport4 extends CatalogSupportBase { /* Verifies the Catalog support on XInclude. */ - @Test(dataProvider = "data_XIA") + @ParameterizedTest + @MethodSource("getDataXI") public void testXIncludeA(boolean setUseCatalog, boolean useCatalog, String catalog, String xml, MyHandler handler, String expected) throws Exception { testXInclude(setUseCatalog, useCatalog, catalog, xml, handler, expected); @@ -108,7 +111,8 @@ public class CatalogSupport4 extends CatalogSupportBase { /* Verifies the Catalog support on DOM parser. */ - @Test(dataProvider = "data_DOMA") + @ParameterizedTest + @MethodSource("getDataDOM") public void testDOMA(boolean setUseCatalog, boolean useCatalog, String catalog, String xml, MyHandler handler, String expected) throws Exception { testDOM(setUseCatalog, useCatalog, catalog, xml, handler, expected); @@ -117,7 +121,8 @@ public class CatalogSupport4 extends CatalogSupportBase { /* Verifies the Catalog support on XMLStreamReader. */ - @Test(dataProvider = "data_StAXA") + @ParameterizedTest + @MethodSource("getDataStAX") public void testStAXA(boolean setUseCatalog, boolean useCatalog, String catalog, String xml, XMLResolver resolver, String expected) throws Exception { testStAX(setUseCatalog, useCatalog, catalog, xml, resolver, expected); @@ -127,7 +132,8 @@ public class CatalogSupport4 extends CatalogSupportBase { Verifies the Catalog support on resolving DTD, xsd import and include in Schema files. */ - @Test(dataProvider = "data_SchemaA") + @ParameterizedTest + @MethodSource("getDataSchema") public void testValidationA(boolean setUseCatalog, boolean useCatalog, String catalog, String xsd, LSResourceResolver resolver) throws Exception { @@ -139,7 +145,8 @@ public class CatalogSupport4 extends CatalogSupportBase { @bug 8158084 8162438 these tests also verifies the fix for 8162438 Verifies the Catalog support on the Schema Validator. */ - @Test(dataProvider = "data_ValidatorA") + @ParameterizedTest + @MethodSource("getDataValidator") public void testValidatorA(boolean setUseCatalog1, boolean setUseCatalog2, boolean useCatalog, Source source, LSResourceResolver resolver1, LSResourceResolver resolver2, String catalog1, String catalog2) @@ -152,7 +159,8 @@ public class CatalogSupport4 extends CatalogSupportBase { Verifies the Catalog support on resolving DTD, xsl import and include in XSL files. */ - @Test(dataProvider = "data_XSLA") + @ParameterizedTest + @MethodSource("getDataXSL") public void testXSLImportA(boolean setUseCatalog, boolean useCatalog, String catalog, SAXSource xsl, StreamSource xml, URIResolver resolver, String expected) throws Exception { @@ -165,7 +173,8 @@ public class CatalogSupport4 extends CatalogSupportBase { Verifies the Catalog support on resolving DTD, xsl import and include in XSL files. */ - @Test(dataProvider = "data_XSLA") + @ParameterizedTest + @MethodSource("getDataXSL") public void testXSLImportWTemplatesA(boolean setUseCatalog, boolean useCatalog, String catalog, SAXSource xsl, StreamSource xml, URIResolver resolver, String expected) throws Exception { @@ -176,7 +185,6 @@ public class CatalogSupport4 extends CatalogSupportBase { DataProvider: for testing the SAX parser Data: set use_catalog, use_catalog, catalog file, xml file, handler, expected result string */ - @DataProvider(name = "data_SAXA") public Object[][] getDataSAX() { return new Object[][]{ {true, true, xml_catalog, xml_system, new MyHandler(elementInSystem), expectedWCatalog}, @@ -187,7 +195,6 @@ public class CatalogSupport4 extends CatalogSupportBase { DataProvider: for testing XInclude Data: set use_catalog, use_catalog, catalog file, xml file, handler, expected result string */ - @DataProvider(name = "data_XIA") public Object[][] getDataXI() { return new Object[][]{ {true, true, xml_catalog, xml_xInclude, new MyHandler(elementInXISimple), contentInUIutf8Catalog}, @@ -198,7 +205,6 @@ public class CatalogSupport4 extends CatalogSupportBase { DataProvider: for testing DOM parser Data: set use_catalog, use_catalog, catalog file, xml file, handler, expected result string */ - @DataProvider(name = "data_DOMA") public Object[][] getDataDOM() { return new Object[][]{ {true, true, xml_catalog, xml_system, new MyHandler(elementInSystem), expectedWCatalog}, @@ -209,7 +215,6 @@ public class CatalogSupport4 extends CatalogSupportBase { DataProvider: for testing the StAX parser Data: set use_catalog, use_catalog, catalog file, xml file, handler, expected result string */ - @DataProvider(name = "data_StAXA") public Object[][] getDataStAX() { return new Object[][]{ @@ -217,15 +222,10 @@ public class CatalogSupport4 extends CatalogSupportBase { }; } - MyEntityHandler getMyEntityHandler(String elementName, String[] systemIds, InputSource... returnValues) { - return new MyEntityHandler(systemIds, returnValues, elementName); - } - /* DataProvider: for testing Schema validation Data: set use_catalog, use_catalog, catalog file, xsd file, a LSResourceResolver */ - @DataProvider(name = "data_SchemaA") public Object[][] getDataSchema() { return new Object[][]{ // for resolving DTD in xsd @@ -241,7 +241,6 @@ public class CatalogSupport4 extends CatalogSupportBase { DataProvider: for testing Schema Validator Data: source, resolver1, resolver2, catalog1, a catalog2 */ - @DataProvider(name = "data_ValidatorA") public Object[][] getDataValidator() { DOMSource ds = getDOMSource(xml_val_test, xml_val_test_id, true, true, xml_catalog); @@ -270,7 +269,6 @@ public class CatalogSupport4 extends CatalogSupportBase { DataProvider: for testing XSL import and include Data: set use_catalog, use_catalog, catalog file, xsl file, xml file, a URIResolver, expected result */ - @DataProvider(name = "data_XSLA") public Object[][] getDataXSL() { // XSLInclude.xsl has one import XSLImport_html.xsl and two includes, // XSLInclude_header.xsl and XSLInclude_footer.xsl; diff --git a/test/jaxp/javax/xml/jaxp/unittest/catalog/CatalogSupport5.java b/test/jaxp/javax/xml/jaxp/unittest/catalog/CatalogSupport5.java index 564848e2e1a..9a09fb9a45e 100644 --- a/test/jaxp/javax/xml/jaxp/unittest/catalog/CatalogSupport5.java +++ b/test/jaxp/javax/xml/jaxp/unittest/catalog/CatalogSupport5.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * 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,15 @@ package catalog; -import java.io.File; -import java.io.StringReader; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.TestInstance.Lifecycle; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import org.w3c.dom.ls.LSResourceResolver; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + import javax.xml.stream.XMLResolver; import javax.xml.stream.XMLStreamException; import javax.xml.transform.Source; @@ -34,19 +41,16 @@ import javax.xml.transform.dom.DOMSource; import javax.xml.transform.sax.SAXSource; import javax.xml.transform.stax.StAXSource; import javax.xml.transform.stream.StreamSource; -import org.testng.annotations.AfterClass; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; -import org.w3c.dom.ls.LSResourceResolver; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; +import java.io.File; +import java.io.StringReader; + +import static org.junit.jupiter.api.Assertions.assertThrows; /* * @test * @bug 8158084 8163232 8166220 * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest - * @run testng/othervm catalog.CatalogSupport5 + * @run junit/othervm catalog.CatalogSupport5 * @summary extends CatalogSupport tests, verifies that when errors occur, * relevant checked Exceptions are returned. */ @@ -58,12 +62,13 @@ import org.xml.sax.SAXException; * * @author huizhe.wang@oracle.com */ +@TestInstance(Lifecycle.PER_CLASS) public class CatalogSupport5 extends CatalogSupportBase { /* * Initializing fields */ - @BeforeClass + @BeforeAll public void setUpClass() throws Exception { setUp(); } @@ -72,77 +77,98 @@ public class CatalogSupport5 extends CatalogSupportBase { /* Verifies the Catalog support on SAXParser. */ - @Test(dataProvider = "data_SAXC", expectedExceptions = SAXException.class) + @ParameterizedTest + @MethodSource("getDataSAXC") public void testSAXC(boolean setUseCatalog, boolean useCatalog, String catalog, String - xml, MyHandler handler, String expected) throws Exception { - testSAX(setUseCatalog, useCatalog, catalog, xml, handler, expected); + xml, MyHandler handler, String expected) { + assertThrows( + SAXException.class, + () -> testSAX(setUseCatalog, useCatalog, catalog, xml, handler, expected)); } /* Verifies the Catalog support on XMLReader. */ - @Test(dataProvider = "data_SAXC", expectedExceptions = SAXException.class) + @ParameterizedTest + @MethodSource("getDataSAXC") public void testXMLReaderC(boolean setUseCatalog, boolean useCatalog, String catalog, - String xml, MyHandler handler, String expected) throws Exception { - testXMLReader(setUseCatalog, useCatalog, catalog, xml, handler, expected); + String xml, MyHandler handler, String expected) { + assertThrows( + SAXException.class, + () -> testXMLReader(setUseCatalog, useCatalog, catalog, xml, handler, expected)); } /* Verifies the Catalog support on XInclude. */ - @Test(dataProvider = "data_XIC", expectedExceptions = SAXException.class) + @ParameterizedTest + @MethodSource("getDataXIC") public void testXIncludeC(boolean setUseCatalog, boolean useCatalog, String catalog, - String xml, MyHandler handler, String expected) throws Exception { - testXInclude(setUseCatalog, useCatalog, catalog, xml, handler, expected); + String xml, MyHandler handler, String expected) { + assertThrows( + SAXException.class, + () -> testXInclude(setUseCatalog, useCatalog, catalog, xml, handler, expected)); } /* Verifies the Catalog support on DOM parser. */ - @Test(dataProvider = "data_DOMC", expectedExceptions = SAXException.class) + @ParameterizedTest + @MethodSource("getDataDOMC") public void testDOMC(boolean setUseCatalog, boolean useCatalog, String catalog, - String xml, MyHandler handler, String expected) throws Exception { - testDOM(setUseCatalog, useCatalog, catalog, xml, handler, expected); + String xml, MyHandler handler, String expected) { + assertThrows( + SAXException.class, + () -> testDOM(setUseCatalog, useCatalog, catalog, xml, handler, expected)); } /* Verifies the Catalog support on XMLStreamReader. */ - @Test(dataProvider = "data_StAXC", expectedExceptions = XMLStreamException.class) + @ParameterizedTest + @MethodSource("getDataStAX") public void testStAXC(boolean setUseCatalog, boolean useCatalog, String catalog, - String xml, XMLResolver resolver, String expected) throws Exception { - testStAX(setUseCatalog, useCatalog, catalog, xml, resolver, expected); + String xml, XMLResolver resolver, String expected) { + assertThrows( + XMLStreamException.class, + () -> testStAX(setUseCatalog, useCatalog, catalog, xml, resolver, expected)); } /* Verifies the Catalog support on resolving DTD, xsd import and include in Schema files. */ - @Test(dataProvider = "data_SchemaC", expectedExceptions = SAXException.class) + @ParameterizedTest + @MethodSource("getDataSchemaC") public void testValidationC(boolean setUseCatalog, boolean useCatalog, String catalog, - String xsd, LSResourceResolver resolver) - throws Exception { - testValidation(setUseCatalog, useCatalog, catalog, xsd, resolver) ; + String xsd, LSResourceResolver resolver) { + assertThrows( + SAXException.class, + () -> testValidation(setUseCatalog, useCatalog, catalog, xsd, resolver)); } - @Test(dataProvider = "data_ValidatorC", expectedExceptions = SAXException.class) + @ParameterizedTest + @MethodSource("getDataValidator") public void testValidatorC(boolean setUseCatalog1, boolean setUseCatalog2, boolean useCatalog, - Source source, LSResourceResolver resolver1, LSResourceResolver resolver2, - String catalog1, String catalog2) - throws Exception { - testValidator(setUseCatalog1, setUseCatalog2, useCatalog, source, - resolver1, resolver2, catalog1, catalog2); + Source source, LSResourceResolver resolver1, LSResourceResolver resolver2, + String catalog1, String catalog2) { + assertThrows( + SAXException.class, + () -> testValidator(setUseCatalog1, setUseCatalog2, useCatalog, source, resolver1, resolver2, catalog1, catalog2)); } /* Verifies the Catalog support on resolving DTD, xsl import and include in XSL files. */ - @Test(dataProvider = "data_XSLC", expectedExceptions = TransformerException.class) + @ParameterizedTest + @MethodSource("getDataXSLC") public void testXSLImportC(boolean setUseCatalog, boolean useCatalog, String catalog, SAXSource xsl, StreamSource xml, URIResolver resolver, String expected) throws Exception { - testXSLImport(setUseCatalog, useCatalog, catalog, xsl, xml, resolver, expected); + assertThrows( + TransformerException.class, + () -> testXSLImport(setUseCatalog, useCatalog, catalog, xsl, xml, resolver, expected)); } /* @@ -150,17 +176,19 @@ public class CatalogSupport5 extends CatalogSupportBase { Verifies the Catalog support on resolving DTD, xsl import and include in XSL files. */ - @Test(dataProvider = "data_XSLC", expectedExceptions = TransformerException.class) + @ParameterizedTest + @MethodSource("getDataXSLC") public void testXSLImportWTemplatesC(boolean setUseCatalog, boolean useCatalog, String catalog, - SAXSource xsl, StreamSource xml, URIResolver resolver, String expected) throws Exception { - testXSLImportWTemplates(setUseCatalog, useCatalog, catalog, xsl, xml, resolver, expected); + SAXSource xsl, StreamSource xml, URIResolver resolver, String expected) throws Exception { + assertThrows( + TransformerException.class, + () -> testXSLImportWTemplates(setUseCatalog, useCatalog, catalog, xsl, xml, resolver, expected)); } /* DataProvider: for testing the SAX parser Data: set use_catalog, use_catalog, catalog file, xml file, handler, expected result string */ - @DataProvider(name = "data_SAXC") public Object[][] getDataSAXC() { return new Object[][]{ {false, true, xml_bogus_catalog, xml_system, new MyHandler(elementInSystem), expectedWCatalog} @@ -172,7 +200,6 @@ public class CatalogSupport5 extends CatalogSupportBase { DataProvider: for testing XInclude Data: set use_catalog, use_catalog, catalog file, xml file, handler, expected result string */ - @DataProvider(name = "data_XIC") public Object[][] getDataXIC() { return new Object[][]{ {false, true, xml_bogus_catalog, xml_xInclude, new MyHandler(elementInXISimple), contentInUIutf8Catalog}, @@ -183,7 +210,6 @@ public class CatalogSupport5 extends CatalogSupportBase { DataProvider: for testing DOM parser Data: set use_catalog, use_catalog, catalog file, xml file, handler, expected result string */ - @DataProvider(name = "data_DOMC") public Object[][] getDataDOMC() { return new Object[][]{ {false, true, xml_bogus_catalog, xml_system, new MyHandler(elementInSystem), expectedWCatalog} @@ -194,7 +220,6 @@ public class CatalogSupport5 extends CatalogSupportBase { DataProvider: for testing the StAX parser Data: set use_catalog, use_catalog, catalog file, xml file, handler, expected result string */ - @DataProvider(name = "data_StAXC") public Object[][] getDataStAX() { return new Object[][]{ @@ -206,7 +231,6 @@ public class CatalogSupport5 extends CatalogSupportBase { DataProvider: for testing Schema validation Data: set use_catalog, use_catalog, catalog file, xsd file, a LSResourceResolver */ - @DataProvider(name = "data_SchemaC") public Object[][] getDataSchemaC() { return new Object[][]{ @@ -224,7 +248,6 @@ public class CatalogSupport5 extends CatalogSupportBase { Data: setUseCatalog1, setUseCatalog2, useCatalog, source, resolver1, resolver2, catalog1, catalog2 */ - @DataProvider(name = "data_ValidatorC") public Object[][] getDataValidator() { DOMSource ds = getDOMSource(xml_val_test, xml_val_test_id, true, true, xml_catalog); @@ -253,7 +276,6 @@ public class CatalogSupport5 extends CatalogSupportBase { DataProvider: for testing XSL import and include Data: set use_catalog, use_catalog, catalog file, xsl file, xml file, a URIResolver, expected */ - @DataProvider(name = "data_XSLC") public Object[][] getDataXSLC() { SAXSource xslSourceDTD = new SAXSource(new InputSource(new StringReader(xsl_includeDTD))); StreamSource xmlSourceDTD = new StreamSource(new StringReader(xml_xslDTD)); diff --git a/test/jaxp/javax/xml/jaxp/unittest/catalog/CatalogSupportBase.java b/test/jaxp/javax/xml/jaxp/unittest/catalog/CatalogSupportBase.java index faa260b275e..52d0ccc8ce4 100644 --- a/test/jaxp/javax/xml/jaxp/unittest/catalog/CatalogSupportBase.java +++ b/test/jaxp/javax/xml/jaxp/unittest/catalog/CatalogSupportBase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * 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,25 +23,17 @@ package catalog; -import static jaxp.library.JAXPTestUtilities.getSystemProperty; +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.w3c.dom.ls.LSInput; +import org.w3c.dom.ls.LSResourceResolver; +import org.xml.sax.Attributes; +import org.xml.sax.ErrorHandler; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.XMLReader; +import org.xml.sax.ext.DefaultHandler2; -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.io.Reader; -import java.io.StringReader; -import java.io.StringWriter; -import java.io.UnsupportedEncodingException; -import java.nio.file.Paths; -import java.security.CodeSource; -import java.security.Permission; -import java.security.PermissionCollection; -import java.security.Permissions; -import java.security.Policy; -import java.security.ProtectionDomain; import javax.xml.XMLConstants; import javax.xml.catalog.CatalogFeatures; import javax.xml.catalog.CatalogResolver; @@ -68,17 +60,26 @@ import javax.xml.transform.stream.StreamSource; import javax.xml.validation.Schema; import javax.xml.validation.SchemaFactory; import javax.xml.validation.Validator; -import org.testng.Assert; -import org.w3c.dom.Document; -import org.w3c.dom.Node; -import org.w3c.dom.ls.LSInput; -import org.w3c.dom.ls.LSResourceResolver; -import org.xml.sax.Attributes; -import org.xml.sax.ErrorHandler; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; -import org.xml.sax.XMLReader; -import org.xml.sax.ext.DefaultHandler2; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; +import java.io.StringReader; +import java.io.StringWriter; +import java.io.UnsupportedEncodingException; +import java.nio.file.Paths; +import java.security.CodeSource; +import java.security.Permission; +import java.security.PermissionCollection; +import java.security.Permissions; +import java.security.Policy; +import java.security.ProtectionDomain; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; /** * Base class: @@ -99,7 +100,7 @@ public class CatalogSupportBase { protected void setUp() { String file1 = getClass().getResource("CatalogSupport.xml").getFile(); - if (getSystemProperty("os.name").contains("Windows")) { + if (System.getProperty("os.name").contains("Windows")) { filepath = file1.substring(1, file1.lastIndexOf("/") + 1); slash = "/"; } else { @@ -285,7 +286,7 @@ public class CatalogSupportBase { SAXParser parser = getSAXParser(setUseCatalog, useCatalog, catalog); parser.parse(xml, handler); - Assert.assertEquals(handler.getResult().trim(), expected); + assertEquals(expected, handler.getResult().trim()); } /* @@ -298,7 +299,7 @@ public class CatalogSupportBase { reader.setContentHandler(handler); reader.setEntityResolver(handler); reader.parse(xml); - Assert.assertEquals(handler.getResult().trim(), expected); + assertEquals(expected, handler.getResult().trim()); } /* @@ -312,7 +313,7 @@ public class CatalogSupportBase { // is thrown if handler == null. if (handler != null) { debugPrint("handler.result:" + handler.getResult()); - Assert.assertEquals(handler.getResult().trim(), expected); + assertEquals(expected, handler.getResult().trim()); } } @@ -327,7 +328,7 @@ public class CatalogSupportBase { Node node = doc.getElementsByTagName(elementInSystem).item(0); String result = node.getFirstChild().getTextContent(); - Assert.assertEquals(result.trim(), expected); + assertEquals(expected, result.trim()); } /* @@ -336,10 +337,10 @@ public class CatalogSupportBase { public void testStAX(boolean setUseCatalog, boolean useCatalog, String catalog, String xml, XMLResolver resolver, String expected) throws Exception { - XMLStreamReader streamReader = getStreamReader( - setUseCatalog, useCatalog, catalog, xml, resolver); - String text = getText(streamReader, XMLStreamConstants.CHARACTERS); - Assert.assertEquals(text.trim(), expected); + XMLStreamReader streamReader = getStreamReader( + setUseCatalog, useCatalog, catalog, xml, resolver); + String text = getText(streamReader, XMLStreamConstants.CHARACTERS); + assertEquals(expected, text.trim()); } /* @@ -349,10 +350,10 @@ public class CatalogSupportBase { public void testStAXNegative(boolean setUseCatalog, boolean useCatalog, String catalog, String xml, XMLResolver resolver, String expected) throws Exception { - XMLStreamReader streamReader = getStreamReader( - setUseCatalog, useCatalog, catalog, xml, resolver); - String text = getText(streamReader, XMLStreamConstants.ENTITY_REFERENCE); - Assert.assertEquals(text.trim(), expected); + XMLStreamReader streamReader = getStreamReader( + setUseCatalog, useCatalog, catalog, xml, resolver); + String text = getText(streamReader, XMLStreamConstants.ENTITY_REFERENCE); + assertEquals(expected, text.trim()); } /* @@ -381,7 +382,6 @@ public class CatalogSupportBase { } else { Schema schema = factory.newSchema(new StreamSource(new StringReader(xsd))); } - success("XMLSchema.dtd and datatypes.dtd are resolved."); } /** @@ -439,8 +439,7 @@ public class CatalogSupportBase { StringWriter out = new StringWriter(); transformer.transform(xml, new StreamResult(out)); - debugPrint("out:\n" + out.toString()); - Assert.assertTrue(out.toString().contains(expected), "testXSLImport"); + assertTrue(out.toString().contains(expected), "Output did not contain '" + expected + "':\n" + out); } /* @@ -455,7 +454,7 @@ public class CatalogSupportBase { Transformer transformer = factory.newTemplates(xsl).newTransformer(); StringWriter out = new StringWriter(); transformer.transform(xml, new StreamResult(out)); - Assert.assertTrue(out.toString().contains(expected), "testXSLImportWTemplates"); + assertTrue(out.toString().contains(expected), "Output did not contain '" + expected + "':\n" + out); } /** @@ -688,16 +687,6 @@ public class CatalogSupportBase { return factory; } - void fail(String msg) { - System.out.println("Test failed:"); - System.out.println(msg); - } - - void success(String msg) { - System.out.println("Test succeded:"); - System.out.println(msg); - } - void debugPrint(String msg) { if (debug) { System.out.println(msg); diff --git a/test/jaxp/javax/xml/jaxp/unittest/catalog/CatalogTest.java b/test/jaxp/javax/xml/jaxp/unittest/catalog/CatalogTest.java index 0c0e77bb952..1b2086f67b3 100644 --- a/test/jaxp/javax/xml/jaxp/unittest/catalog/CatalogTest.java +++ b/test/jaxp/javax/xml/jaxp/unittest/catalog/CatalogTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * 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,14 +22,19 @@ */ package catalog; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.StringReader; -import java.io.StringWriter; -import java.net.URI; -import java.nio.file.Paths; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.TestInstance.Lifecycle; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import org.xml.sax.Attributes; +import org.xml.sax.ErrorHandler; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.XMLReader; +import org.xml.sax.ext.DefaultHandler2; + import javax.xml.XMLConstants; import javax.xml.catalog.Catalog; import javax.xml.catalog.CatalogException; @@ -52,26 +57,29 @@ import javax.xml.transform.stream.StreamSource; import javax.xml.validation.Schema; import javax.xml.validation.SchemaFactory; import javax.xml.validation.Validator; -import static jaxp.library.JAXPTestUtilities.clearSystemProperty; -import static jaxp.library.JAXPTestUtilities.setSystemProperty; -import org.testng.Assert; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; -import org.xml.sax.Attributes; -import org.xml.sax.ErrorHandler; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; -import org.xml.sax.XMLReader; -import org.xml.sax.ext.DefaultHandler2; +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.io.StringReader; +import java.io.StringWriter; +import java.net.URI; +import java.nio.file.Paths; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; /* * @test * @bug 8081248 8144966 8146606 8146237 8150969 8151162 8152527 8154220 8163232 * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest - * @run testng/othervm catalog.CatalogTest + * @run junit/othervm catalog.CatalogTest * @summary Tests basic Catalog functions. */ +@TestInstance(Lifecycle.PER_CLASS) public class CatalogTest extends CatalogSupportBase { static final String KEY_FILES = "javax.xml.catalog.files"; @@ -79,7 +87,7 @@ public class CatalogTest extends CatalogSupportBase { /* * Initializing fields */ - @BeforeClass + @BeforeAll public void setUpClass() throws Exception { super.setUp(); } @@ -98,8 +106,9 @@ public class CatalogTest extends CatalogSupportBase { /* * Verifies the support for org.xml.sax.EntityResolver. * Expected: the parser returns the expected string. - */ - @Test(dataProvider = "supportXMLResolver") + */ + @ParameterizedTest + @MethodSource("supportXMLResolver") public void supportEntityResolver(URI catalogFile, String xml, String expected) throws Exception { String xmlSource = getClass().getResource(xml).getFile(); @@ -108,14 +117,15 @@ public class CatalogTest extends CatalogSupportBase { SAXParser parser = getSAXParser(false, true, null); parser.parse(xmlSource, handler); - Assert.assertEquals(handler.getResult().trim(), expected); + assertEquals(expected, handler.getResult().trim()); } /* * Verifies the support for javax.xml.stream.XMLResolver. * Expected: the parser returns the expected string. - */ - @Test(dataProvider = "supportXMLResolver") + */ + @ParameterizedTest + @MethodSource("supportXMLResolver") public void supportXMLResolver(URI catalogFile, String xml, String expected) throws Exception { String xmlSource = getClass().getResource(xml).getFile(); @@ -140,15 +150,16 @@ public class CatalogTest extends CatalogSupportBase { } System.out.println(": expected [" + expected + "] <> actual [" + result.trim() + "]"); - Assert.assertEquals(result.trim(), expected); + assertEquals(expected, result.trim()); } /* * Verifies the support for org.w3c.dom.ls.LSResourceResolver by ShemaFactory. * Success: parsing goes through with no error * Fail: throws Exception if references are not resolved (by the CatalogResolver) - */ - @Test(dataProvider = "supportLSResourceResolver") + */ + @ParameterizedTest + @MethodSource("supportLSResourceResolver") public void supportLSResourceResolver(URI catalogFile, Source schemaSource) throws SAXException { CatalogResolver cr = CatalogManager.catalogResolver(CatalogFeatures.defaults(), catalogFile); @@ -163,8 +174,9 @@ public class CatalogTest extends CatalogSupportBase { * Verifies the support for org.w3c.dom.ls.LSResourceResolver by Validator. * Success: parsing goes through with no error * Fail: throws Exception if references are not resolved (by the CatalogResolver) - */ - @Test(dataProvider = "supportLSResourceResolver1") + */ + @ParameterizedTest + @MethodSource("supportLSResourceResolver1") public void supportLSResourceResolver1(URI catalogFile, Source source) throws Exception { CatalogResolver cr = CatalogManager.catalogResolver(CatalogFeatures.defaults(), catalogFile); @@ -179,20 +191,21 @@ public class CatalogTest extends CatalogSupportBase { * Verifies the support for javax.xml.transform.URIResolver. * Success: parsing goes through with no error * Fail: throws Exception if references are not resolved (by the CatalogResolver) - */ - @Test(dataProvider = "supportURIResolver") + */ + @ParameterizedTest + @MethodSource("supportURIResolver") public void supportURIResolver(URI catalogFile, Source xsl, Source xml, String expected) throws Exception { CatalogResolver cr = CatalogManager.catalogResolver(CatalogFeatures.defaults(), catalogFile); - TransformerFactory factory = TransformerFactory.newInstance(); - factory.setURIResolver(cr); - Transformer transformer = factory.newTransformer(xsl); - StringWriter out = new StringWriter(); - transformer.transform(xml, new StreamResult(out)); - if (expected != null) { - Assert.assertTrue(out.toString().contains(expected), "supportURIResolver"); - } + TransformerFactory factory = TransformerFactory.newInstance(); + factory.setURIResolver(cr); + Transformer transformer = factory.newTransformer(xsl); + StringWriter out = new StringWriter(); + transformer.transform(xml, new StreamResult(out)); + if (expected != null) { + assertTrue(out.toString().contains(expected), "supportURIResolver"); + } } /* @@ -200,7 +213,6 @@ public class CatalogTest extends CatalogSupportBase { Data columns: catalog filepath, xml source file, expected result */ - @DataProvider(name = "supportXMLResolver") public Object[][] supportXMLResolver() throws Exception { URI catalogFile = getClass().getResource("catalog.xml").toURI(); URI catalogFileUri = getClass().getResource("catalog_uri.xml").toURI(); @@ -228,7 +240,6 @@ public class CatalogTest extends CatalogSupportBase { Data columns: catalog filepath, schema source file */ - @DataProvider(name = "supportLSResourceResolver") public Object[][] supportLSResourceResolver() throws Exception { URI catalogFile = getClass().getResource("CatalogSupport.xml").toURI(); URI catalogFileUri = getClass().getResource("CatalogSupport_uri.xml").toURI(); @@ -252,7 +263,6 @@ public class CatalogTest extends CatalogSupportBase { Data columns: catalog filepath, source file */ - @DataProvider(name = "supportLSResourceResolver1") public Object[][] supportLSResourceResolver1() throws Exception { URI catalogFile = getClass().getResource("CatalogSupport.xml").toURI(); URI catalogFileUri = getClass().getResource("CatalogSupport_uri.xml").toURI(); @@ -275,7 +285,6 @@ public class CatalogTest extends CatalogSupportBase { Data columns: catalog filepath, xsl source, xml source file */ - @DataProvider(name = "supportURIResolver") public Object[][] supportURIResolver() throws Exception { URI catalogFile = getClass().getResource("CatalogSupport.xml").toURI(); URI catalogFileUri = getClass().getResource("CatalogSupport_uri.xml").toURI(); @@ -303,10 +312,12 @@ public class CatalogTest extends CatalogSupportBase { * requires a system identifier on all external entities, so this value is * always specified. */ - @Test(expectedExceptions = NullPointerException.class) + @Test public void sysIdCantBeNull() { CatalogResolver catalogResolver = CatalogManager.catalogResolver(CatalogFeatures.defaults()); - InputSource is = catalogResolver.resolveEntity("-//FOO//DTD XML Dummy V0.0//EN", null); + assertThrows( + NullPointerException.class, + () -> catalogResolver.resolveEntity("-//FOO//DTD XML Dummy V0.0//EN", null)); } /* @@ -318,14 +329,15 @@ public class CatalogTest extends CatalogSupportBase { * copying the JCK test and its dataProvider. This test may be reused for * other cases in that test. */ - @Test(dataProvider = "resolveUri") + @ParameterizedTest + @MethodSource("getDataForUriResolver") public void testMatch1(String cFile, String href, String expectedFile, String expectedUri, String msg) throws Exception { URI catalogFile = getClass().getResource(cFile).toURI(); CatalogResolver cur = CatalogManager.catalogResolver(CatalogFeatures.defaults(), catalogFile); Source source = cur.resolve(href, null); - Assert.assertNotNull(source, "Source returned is null"); - Assert.assertEquals(expectedUri, source.getSystemId(), msg); + assertNotNull(source, "Source returned is null"); + assertEquals(expectedUri, source.getSystemId(), msg); } /* @@ -333,20 +345,21 @@ public class CatalogTest extends CatalogSupportBase { * Verifies that the file input is validated properly. Valid input includes * multiple file paths separated by semicolon. */ - @Test(dataProvider = "hierarchyOfCatFilesData") + @ParameterizedTest + @MethodSource("getHierarchyOfCatFilesData") public void hierarchyOfCatFiles2(String systemId, String expectedUri) { String file1 = getClass().getResource("first_cat.xml").toExternalForm(); String file2 = getClass().getResource("second_cat.xml").toExternalForm(); String files = file1 + ";" + file2; try { - setSystemProperty(KEY_FILES, files); + System.setProperty(KEY_FILES, files); CatalogResolver catalogResolver = CatalogManager.catalogResolver(CatalogFeatures.defaults()); - String sysId = catalogResolver.resolveEntity(null, systemId).getSystemId(); - Assert.assertEquals(sysId, Paths.get(filepath + expectedUri).toUri().toString().replace("///", "/"), - "System ID match not right"); + String actualSysId = catalogResolver.resolveEntity(null, systemId).getSystemId(); + String expectedSysId = Paths.get(filepath + expectedUri).toUri().toString().replace("///", "/"); + assertEquals(expectedSysId, actualSysId, "System ID match not right"); } finally { - clearSystemProperty(KEY_FILES); + System.clearProperty(KEY_FILES); } } @@ -357,16 +370,17 @@ public class CatalogTest extends CatalogSupportBase { * Verifies that the CatalogResolver resolves a publicId and/or systemId as * expected. */ - @Test(dataProvider = "resolveEntity") + @ParameterizedTest + @MethodSource("getDataForMatchingBothIds") public void testMatch1(String cfile, String prefer, String sysId, String pubId, String expectedUri, String expectedFile, String msg) throws Exception { URI catalogFile = getClass().getResource(cfile).toURI(); CatalogFeatures features = CatalogFeatures.builder().with(CatalogFeatures.Feature.PREFER, prefer).build(); CatalogResolver catalogResolver = CatalogManager.catalogResolver(features, catalogFile); InputSource is = catalogResolver.resolveEntity(pubId, sysId); - Assert.assertNotNull(is, msg); + assertNotNull(is, msg); String expected = (expectedUri == null) ? expectedFile : expectedUri; - Assert.assertEquals(expected, is.getSystemId(), msg); + assertEquals(expected, is.getSystemId(), msg); } /* @@ -374,7 +388,8 @@ public class CatalogTest extends CatalogSupportBase { * Verifies that the Catalog matches specified publicId or systemId and returns * results as expected. */ - @Test(dataProvider = "matchWithPrefer") + @ParameterizedTest + @MethodSource("getDataForMatch") public void matchWithPrefer(String prefer, String cfile, String publicId, String systemId, String expected) throws Exception { URI catalogFile = getClass().getResource(cfile).toURI(); @@ -387,7 +402,7 @@ public class CatalogTest extends CatalogSupportBase { } else { result = c.matchSystem(systemId); } - Assert.assertEquals(expected, result); + assertEquals(expected, result); } /* @@ -401,7 +416,8 @@ public class CatalogTest extends CatalogSupportBase { * attempts to resolve with a public entry if no matching * system entry is found. */ - @Test(dataProvider = "resolveWithPrefer") + @ParameterizedTest + @MethodSource("getDataForResolve") public void resolveWithPrefer(String prefer, String cfile, String publicId, String systemId, String expected) throws Exception { URI catalogFile = getClass().getResource(cfile).toURI(); @@ -411,7 +427,7 @@ public class CatalogTest extends CatalogSupportBase { .build(); CatalogResolver catalogResolver = CatalogManager.catalogResolver(f, catalogFile); String result = catalogResolver.resolveEntity(publicId, systemId).getSystemId(); - Assert.assertEquals(expected, result); + assertEquals(expected, result); } /** @@ -420,7 +436,8 @@ public class CatalogTest extends CatalogSupportBase { * over other settings, in which case, whether next and delegate Catalogs will * be loaded is determined by the defer attribute. */ - @Test(dataProvider = "invalidAltCatalogs", expectedExceptions = CatalogException.class) + @ParameterizedTest + @MethodSource("getInvalidAltCatalogs") public void testDeferAltCatalogs(String file) throws Exception { URI catalogFile = getClass().getResource(file).toURI(); CatalogFeatures features = CatalogFeatures.builder(). @@ -431,7 +448,7 @@ public class CatalogTest extends CatalogSupportBase { the parent catalog will try to load the alt catalog, which will fail since it points to an invalid catalog. */ - Catalog catalog = CatalogManager.catalog(features, catalogFile); + assertThrows(CatalogException.class, () -> CatalogManager.catalog(features, catalogFile)); } @@ -443,22 +460,17 @@ public class CatalogTest extends CatalogSupportBase { public void testJDK8146237() throws Exception { URI catalogFile = getClass().getResource("JDK8146237_catalog.xml").toURI(); - try { - CatalogFeatures features = CatalogFeatures.builder() - .with(CatalogFeatures.Feature.PREFER, "system") - .build(); - Catalog catalog = CatalogManager.catalog(features, catalogFile); - CatalogResolver catalogResolver = CatalogManager.catalogResolver(catalog); - String actualSystemId = catalogResolver.resolveEntity( - "-//FOO//DTD XML Dummy V0.0//EN", - "http://www.oracle.com/alt1sys.dtd") - .getSystemId(); - Assert.assertTrue(actualSystemId.contains("dummy.dtd"), - "Resulting id should contain dummy.dtd, indicating a match by publicId"); - - } catch (Exception e) { - Assert.fail(e.getMessage()); - } + CatalogFeatures features = CatalogFeatures.builder() + .with(CatalogFeatures.Feature.PREFER, "system") + .build(); + Catalog catalog = CatalogManager.catalog(features, catalogFile); + CatalogResolver catalogResolver = CatalogManager.catalogResolver(catalog); + String actualSystemId = catalogResolver.resolveEntity( + "-//FOO//DTD XML Dummy V0.0//EN", + "http://www.oracle.com/alt1sys.dtd") + .getSystemId(); + assertTrue(actualSystemId.contains("dummy.dtd"), + "Resulting id should contain dummy.dtd, indicating a match by publicId"); } /* @@ -469,14 +481,9 @@ public class CatalogTest extends CatalogSupportBase { public void testRewriteSystem() throws Exception { URI catalog = getClass().getResource("rewriteCatalog.xml").toURI(); - try { - CatalogResolver resolver = CatalogManager.catalogResolver(CatalogFeatures.defaults(), catalog); - String actualSystemId = resolver.resolveEntity(null, "http://remote.com/dtd/book.dtd").getSystemId(); - Assert.assertTrue(!actualSystemId.contains("//"), "result contains duplicate slashes"); - } catch (Exception e) { - Assert.fail(e.getMessage()); - } - + CatalogResolver resolver = CatalogManager.catalogResolver(CatalogFeatures.defaults(), catalog); + String actualSystemId = resolver.resolveEntity(null, "http://remote.com/dtd/book.dtd").getSystemId(); + assertFalse(actualSystemId.contains("//"), "result contains duplicate slashes"); } /* @@ -487,23 +494,18 @@ public class CatalogTest extends CatalogSupportBase { public void testRewriteUri() throws Exception { URI catalog = getClass().getResource("rewriteCatalog.xml").toURI(); - try { - - CatalogResolver resolver = CatalogManager.catalogResolver(CatalogFeatures.defaults(), catalog); - String actualSystemId = resolver.resolve("http://remote.com/import/import.xsl", null).getSystemId(); - Assert.assertTrue(!actualSystemId.contains("//"), "result contains duplicate slashes"); - } catch (Exception e) { - Assert.fail(e.getMessage()); - } + CatalogResolver resolver = CatalogManager.catalogResolver(CatalogFeatures.defaults(), catalog); + String actualSystemId = resolver.resolve("http://remote.com/import/import.xsl", null).getSystemId(); + assertFalse(actualSystemId.contains("//"), "result contains duplicate slashes"); } /* @bug 8144966 Verifies that passing null as CatalogFeatures will result in a NPE. */ - @Test(expectedExceptions = NullPointerException.class) + @Test public void testFeatureNull() { - CatalogResolver resolver = CatalogManager.catalogResolver((CatalogFeatures)null, (URI)null); + assertThrows(NullPointerException.class, () -> CatalogManager.catalogResolver((CatalogFeatures) null, (URI) null)); } @@ -511,10 +513,11 @@ public class CatalogTest extends CatalogSupportBase { @bug 8144966 Verifies that passing null as the URI will result in a NPE. */ - @Test(expectedExceptions = NullPointerException.class) + @Test public void testPathNull() { - URI uri = null; - CatalogResolver resolver = CatalogManager.catalogResolver(CatalogFeatures.defaults(), uri); + assertThrows( + NullPointerException.class, + () -> CatalogManager.catalogResolver(CatalogFeatures.defaults(), (URI) null)); } /* @@ -523,7 +526,8 @@ public class CatalogTest extends CatalogSupportBase { is successful, the Handler shall return the value of the entity reference that matches the expected value. */ - @Test(dataProvider = "catalog") + @ParameterizedTest + @MethodSource("getCatalog") public void testCatalogResolver(String test, String expected, String catalogFile, String xml, SAXParser saxParser) throws Exception { URI catalog = null; @@ -531,18 +535,14 @@ public class CatalogTest extends CatalogSupportBase { catalog = getClass().getResource(catalogFile).toURI(); } String url = getClass().getResource(xml).getFile(); - try { - CatalogResolver cr = CatalogManager.catalogResolver(CatalogFeatures.defaults(), catalog); - XMLReader reader = saxParser.getXMLReader(); - reader.setEntityResolver(cr); - MyHandler handler = new MyHandler(saxParser); - reader.setContentHandler(handler); - reader.parse(url); - System.out.println(test + ": expected [" + expected + "] <> actual [" + handler.getResult() + "]"); - Assert.assertEquals(handler.getResult(), expected); - } catch (SAXException | IOException e) { - Assert.fail(e.getMessage()); - } + CatalogResolver cr = CatalogManager.catalogResolver(CatalogFeatures.defaults(), catalog); + XMLReader reader = saxParser.getXMLReader(); + reader.setEntityResolver(cr); + MyHandler handler = new MyHandler(saxParser); + reader.setContentHandler(handler); + reader.parse(url); + System.out.println(test + ": expected [" + expected + "] <> actual [" + handler.getResult() + "]"); + assertEquals(expected, handler.getResult()); } /* @@ -564,7 +564,7 @@ public class CatalogTest extends CatalogSupportBase { } catch (Exception e) { String msg = e.getMessage(); if (msg != null) { - Assert.assertTrue(msg.contains(expectedMsgId), + assertTrue(msg.contains(expectedMsgId), "Message shall contain the corrent message ID " + expectedMsgId); } } @@ -585,19 +585,15 @@ public class CatalogTest extends CatalogSupportBase { .build(); String test = "testInvalidCatalog"; - try { - CatalogResolver resolver = CatalogManager.catalogResolver(f); - String actualSystemId = resolver.resolveEntity( - null, - "http://remote/xml/dtd/sys/alice/docAlice.dtd") - .getSystemId(); - System.out.println("testIgnoreInvalidCatalog: expected [null]"); - System.out.println("testIgnoreInvalidCatalog: expected [null]"); - System.out.println("actual [" + actualSystemId + "]"); - Assert.assertEquals(actualSystemId, null); - } catch (Exception e) { - Assert.fail(e.getMessage()); - } + CatalogResolver resolver = CatalogManager.catalogResolver(f); + String actualSystemId = resolver.resolveEntity( + null, + "http://remote/xml/dtd/sys/alice/docAlice.dtd") + .getSystemId(); + System.out.println("testIgnoreInvalidCatalog: expected [null]"); + System.out.println("testIgnoreInvalidCatalog: expected [null]"); + System.out.println("actual [" + actualSystemId + "]"); + assertNull(actualSystemId); } @@ -608,7 +604,6 @@ public class CatalogTest extends CatalogSupportBase { This DataProvider is copied from JCK ResolveTests' dataMatch1 */ - @DataProvider(name = "resolveUri") public Object[][] getDataForUriResolver() { return new Object[][]{ {"uri.xml", @@ -623,7 +618,6 @@ public class CatalogTest extends CatalogSupportBase { DataProvider: used to verify hierarchical catalogs. Refer to JCK test hierarchyOfCatFiles2. */ - @DataProvider(name = "hierarchyOfCatFilesData") public Object[][] getHierarchyOfCatFilesData() { return new Object[][]{ {"http://www.oracle.com/sequence.dtd", "first.dtd"}, @@ -637,7 +631,6 @@ public class CatalogTest extends CatalogSupportBase { Data columns: catalog, prefer, systemId, publicId, expectedUri, expectedFile, msg */ - @DataProvider(name = "resolveEntity") public Object[][] getDataForMatchingBothIds() { String expected = "http://www.groupxmlbase.com/dtds/rewrite.dtd"; return new Object[][]{ @@ -658,7 +651,6 @@ public class CatalogTest extends CatalogSupportBase { Data columns: prefer, catalog, publicId, systemId, expected result */ - @DataProvider(name = "matchWithPrefer") public Object[][] getDataForMatch() { return new Object[][]{ {"public", "pubOnly.xml", id, "", "http://local/base/dtd/public.dtd"}, @@ -682,7 +674,6 @@ public class CatalogTest extends CatalogSupportBase { Data columns: prefer, catalog, publicId, systemId, expected result */ - @DataProvider(name = "resolveWithPrefer") public Object[][] getDataForResolve() { return new Object[][]{ {"system", "pubOnly.xml", id, "", "http://local/base/dtd/public.dtd"}, @@ -709,11 +700,10 @@ public class CatalogTest extends CatalogSupportBase { DataProvider: catalogs that contain invalid next or delegate catalogs. The defer attribute is set to false. */ - @DataProvider(name = "invalidAltCatalogs") - public Object[][] getCatalogs() { - return new Object[][]{ - {"defer_false_2.xml"}, - {"defer_del_false.xml"} + public Object[][] getInvalidAltCatalogs() { + return new Object[][] { + { "defer_false_2.xml" }, + { "defer_del_false.xml" } }; } @@ -722,7 +712,6 @@ public class CatalogTest extends CatalogSupportBase { DataProvider: provides test name, expected string, the catalog, and XML document. */ - @DataProvider(name = "catalog") public Object[][] getCatalog() { return new Object[][]{ {"testSystem", "Test system entry", "catalog.xml", "system.xml", getParser()}, diff --git a/test/jaxp/javax/xml/jaxp/unittest/catalog/GroupTest.java b/test/jaxp/javax/xml/jaxp/unittest/catalog/GroupTest.java index 46aa46ee29f..6a5593db11b 100644 --- a/test/jaxp/javax/xml/jaxp/unittest/catalog/GroupTest.java +++ b/test/jaxp/javax/xml/jaxp/unittest/catalog/GroupTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * 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,31 +22,36 @@ */ package catalog; -import java.net.URI; -import java.nio.file.Paths; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.TestInstance.Lifecycle; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + import javax.xml.catalog.CatalogFeatures; import javax.xml.catalog.CatalogManager; import javax.xml.catalog.CatalogResolver; import javax.xml.transform.Source; -import org.testng.Assert; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import java.net.URI; +import java.nio.file.Paths; + +import static org.junit.jupiter.api.Assertions.assertTrue; /* * @test * @bug 8215330 * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest - * @run testng catalog.GroupTest + * @run junit catalog.GroupTest * @summary Tests catalog with Group entries. */ +@TestInstance(Lifecycle.PER_CLASS) public class GroupTest extends CatalogSupportBase { String catalogGroup; /* * Initializing fields */ - @BeforeClass + @BeforeAll public void setUpClass() throws Exception { super.setUp(); catalogGroup = Paths.get(filepath + "GroupTest.xml").toUri().toASCIIString(); @@ -60,13 +65,14 @@ public class GroupTest extends CatalogSupportBase { * @param expected the expected result string * @throws Exception */ - @Test(dataProvider = "data_group") + @ParameterizedTest + @MethodSource("getDataDOM") public void testGroup(String catalog, String uri, String expected) throws Exception { CatalogResolver resolver = CatalogManager.catalogResolver( CatalogFeatures.defaults(), URI.create(catalog)); Source src = resolver.resolve(uri, null); - Assert.assertTrue(src.getSystemId().endsWith(expected), "uriSuffix match"); + assertTrue(src.getSystemId().endsWith(expected), "uriSuffix match"); } @@ -74,7 +80,6 @@ public class GroupTest extends CatalogSupportBase { DataProvider: for testing catalogs with group entries Data: catalog file, uri, expected result string */ - @DataProvider(name = "data_group") public Object[][] getDataDOM() { return new Object[][]{ {catalogGroup, "http://openjdk_java_net/xml/catalog/A/CommonFileA1.xml", "LocalFileA1.xml"}, diff --git a/test/jaxp/javax/xml/jaxp/unittest/datatype/Bug6320118.java b/test/jaxp/javax/xml/jaxp/unittest/datatype/Bug6320118.java index f22e95837bd..fa27d5102d4 100644 --- a/test/jaxp/javax/xml/jaxp/unittest/datatype/Bug6320118.java +++ b/test/jaxp/javax/xml/jaxp/unittest/datatype/Bug6320118.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * 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,26 +23,28 @@ package datatype; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + import javax.xml.datatype.DatatypeConfigurationException; import javax.xml.datatype.DatatypeFactory; import javax.xml.datatype.XMLGregorianCalendar; -import org.testng.Assert; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; /* * @test * @bug 6320118 * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest - * @run testng/othervm datatype.Bug6320118 + * @run junit/othervm datatype.Bug6320118 * @summary Test xml datatype XMLGregorianCalendar. */ public class Bug6320118 { DatatypeFactory df; - @BeforeClass + @BeforeEach public void createDataTypeFactory() throws DatatypeConfigurationException { df = DatatypeFactory.newInstance(); } @@ -50,30 +52,30 @@ public class Bug6320118 { @Test public void test1() { XMLGregorianCalendar calendar = df.newXMLGregorianCalendar(1970, 1, 1, 24, 0, 0, 0, 0); - Assert.assertEquals(calendar.getYear(), 1970); - Assert.assertEquals(calendar.getMonth(), 1); - Assert.assertEquals(calendar.getDay(), 2); - Assert.assertEquals(calendar.getHour(), 0, "hour 24 needs to be treated as hour 0 of next day"); + assertEquals(1970, calendar.getYear()); + assertEquals(1, calendar.getMonth()); + assertEquals(2, calendar.getDay()); + assertEquals(0, calendar.getHour(), "hour 24 needs to be treated as hour 0 of next day"); } @Test public void test2() { XMLGregorianCalendar calendar = df.newXMLGregorianCalendarTime(24, 0, 0, 0); - Assert.assertEquals(calendar.getHour(), 0, "hour 24 needs to be treated as hour 0 of next day"); + assertEquals(0, calendar.getHour(), "hour 24 needs to be treated as hour 0 of next day"); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test public void test3() { XMLGregorianCalendar calendar = df.newXMLGregorianCalendar(); // Must fail as other params are not 0 but undefined - calendar.setHour(24); + assertThrows(IllegalArgumentException.class, () -> calendar.setHour(24)); } @Test public void test4() { XMLGregorianCalendar calendar = df.newXMLGregorianCalendar(); calendar.setTime(24, 0, 0, 0); - Assert.assertEquals(calendar.getHour(), 0, "hour 24 needs to be treated as hour 0 of next day"); + assertEquals(0, calendar.getHour(), "hour 24 needs to be treated as hour 0 of next day"); } } diff --git a/test/jaxp/javax/xml/jaxp/unittest/datatype/Bug6937951Test.java b/test/jaxp/javax/xml/jaxp/unittest/datatype/Bug6937951Test.java index d1e5aea93da..bc32bc0374d 100644 --- a/test/jaxp/javax/xml/jaxp/unittest/datatype/Bug6937951Test.java +++ b/test/jaxp/javax/xml/jaxp/unittest/datatype/Bug6937951Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * 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,18 +23,19 @@ package datatype; +import org.junit.jupiter.api.Test; + import javax.xml.datatype.DatatypeConfigurationException; import javax.xml.datatype.DatatypeFactory; import javax.xml.datatype.XMLGregorianCalendar; -import org.testng.Assert; -import org.testng.annotations.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; /* * @test * @bug 6937951 * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest - * @run testng/othervm datatype.Bug6937951Test + * @run junit/othervm datatype.Bug6937951Test * @summary Test midnight is same as the start of the next day in XMLGregorianCalendar. */ public class Bug6937951Test { @@ -44,13 +45,10 @@ public class Bug6937951Test { DatatypeFactory dtf = DatatypeFactory.newInstance(); XMLGregorianCalendar c1 = dtf.newXMLGregorianCalendar("1999-12-31T24:00:00"); XMLGregorianCalendar c2 = dtf.newXMLGregorianCalendar("2000-01-01T00:00:00"); - System.out.println("c1: " + c1.getYear() + "-" + c1.getMonth() + "-" + c1.getDay() + "T" + c1.getHour()); - System.out.println(c1.equals(c2) ? "pass" : "fail"); // fails - if (!c1.equals(c2)) - Assert.fail("hour 24 needs to be treated as equal to hour 0 of the next day"); - if (c1.getYear() != 2000 && c1.getHour() != 0) - Assert.fail("hour 24 needs to be treated as equal to hour 0 of the next day"); + assertEquals(2000, c1.getYear()); + assertEquals(0, c1.getHour()); + assertEquals(c1, c2, "hour 24 should treated as equal to hour 0 of the next day"); } } diff --git a/test/jaxp/javax/xml/jaxp/unittest/datatype/Bug6937964Test.java b/test/jaxp/javax/xml/jaxp/unittest/datatype/Bug6937964Test.java index 8aa5d6369a3..571ca1b97d3 100644 --- a/test/jaxp/javax/xml/jaxp/unittest/datatype/Bug6937964Test.java +++ b/test/jaxp/javax/xml/jaxp/unittest/datatype/Bug6937964Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * 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,31 +23,29 @@ package datatype; -import java.math.BigDecimal; -import java.math.BigInteger; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; import javax.xml.datatype.DatatypeConfigurationException; import javax.xml.datatype.DatatypeConstants; import javax.xml.datatype.DatatypeFactory; import javax.xml.datatype.Duration; import javax.xml.namespace.QName; +import java.math.BigDecimal; +import java.math.BigInteger; -import org.testng.Assert; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; /* * @test * @bug 6937964 * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest - * @run testng/othervm datatype.Bug6937964Test + * @run junit/othervm datatype.Bug6937964Test * @summary Test Duration is normalized. */ public class Bug6937964Test { - /** - * Print debugging to System.err. - */ - private static final boolean DEBUG = false; /** * Constant to indicate expected lexical test failure. */ @@ -57,7 +55,7 @@ public class Bug6937964Test { public void test() throws DatatypeConfigurationException { DatatypeFactory dtf = DatatypeFactory.newInstance(); Duration d = dtf.newDurationYearMonth("P20Y15M"); - System.out.println(d.getYears() == 21 ? "pass" : "fail"); + assertEquals(21, d.getYears()); } @Test @@ -65,7 +63,7 @@ public class Bug6937964Test { DatatypeFactory dtf = DatatypeFactory.newInstance(); Duration d = dtf.newDurationYearMonth("P20Y15M"); int years = d.getYears(); - Assert.assertEquals(years, 21, "Return value should be normalized"); + assertEquals(21, years, "Return value should be normalized"); } @Test @@ -73,8 +71,7 @@ public class Bug6937964Test { DatatypeFactory dtf = DatatypeFactory.newInstance(); Duration d = dtf.newDurationYearMonth(671976000000L); int years = d.getYears(); - System.out.println("Years: " + years); - Assert.assertEquals(years, 21, "Return value should be normalized"); + assertEquals(21, years, "Return value should be normalized"); } @Test @@ -84,7 +81,7 @@ public class Bug6937964Test { BigInteger mon = new BigInteger("15"); Duration d = dtf.newDurationYearMonth(true, year, mon); int years = d.getYears(); - Assert.assertEquals(years, 21, "Return value should be normalized"); + assertEquals(21, years, "Return value should be normalized"); } @Test @@ -92,7 +89,7 @@ public class Bug6937964Test { DatatypeFactory dtf = DatatypeFactory.newInstance(); Duration d = dtf.newDurationYearMonth(true, 20, 15); int years = d.getYears(); - Assert.assertEquals(years, 21, "Return value should be normalized"); + assertEquals(21, years, "Return value should be normalized"); } @Test @@ -100,7 +97,7 @@ public class Bug6937964Test { DatatypeFactory dtf = DatatypeFactory.newInstance(); Duration d = dtf.newDurationDayTime("P1DT23H59M65S"); int days = d.getDays(); - Assert.assertEquals(days, 2, "Return value should be normalized"); + assertEquals(2, days, "Return value should be normalized"); } @Test @@ -108,7 +105,7 @@ public class Bug6937964Test { DatatypeFactory dtf = DatatypeFactory.newInstance(); Duration d = dtf.newDurationDayTime(172805000L); int days = d.getDays(); - Assert.assertEquals(days, 2, "Return value should be normalized"); + assertEquals(2, days, "Return value should be normalized"); } @Test @@ -120,8 +117,7 @@ public class Bug6937964Test { BigInteger sec = new BigInteger("65"); Duration d = dtf.newDurationDayTime(true, day, hour, min, sec); int days = d.getDays(); - System.out.println("Days: " + days); - Assert.assertEquals(days, 2, "Return value should be normalized"); + assertEquals(2, days, "Return value should be normalized"); } @Test @@ -129,117 +125,88 @@ public class Bug6937964Test { DatatypeFactory dtf = DatatypeFactory.newInstance(); Duration d = dtf.newDurationDayTime(true, 1, 23, 59, 65); int days = d.getDays(); - System.out.println("Days: " + days); - Assert.assertEquals(days, 2, "Return value should be normalized"); + assertEquals(2, days, "Return value should be normalized"); } - @DataProvider(name = "lexicalvalues") - public Object[][] actualAndExpectedLexicals() { - Object actualAndExpected [][] = { - {"P13M", "P1Y1M"}, - {"-P13M", "-P1Y1M"}, - {"P1Y", "P1Y"}, - {"-P1Y", "-P1Y"}, - {"P1Y25M", "P3Y1M"}, - {"-P1Y25M", "-P3Y1M"} + public static Object[][] lexicalvalues() { + return new Object[][] { + { "P13M", "P1Y1M" }, + { "-P13M", "-P1Y1M" }, + { "P1Y", "P1Y" }, + { "-P1Y", "-P1Y" }, + { "P1Y25M", "P3Y1M" }, + { "-P1Y25M", "-P3Y1M" } }; - return actualAndExpected; } - @Test(dataProvider = "lexicalvalues") - public void testNewDurationYearMonthLexicalRepresentation1(String actualLex, String expectedLex) { - /** - * Lexical test values to test. - */ - - DatatypeFactory datatypeFactory = null; - try { - datatypeFactory = DatatypeFactory.newInstance(); - } catch (DatatypeConfigurationException datatypeConfigurationException) { - Assert.fail(datatypeConfigurationException.toString()); - } - - if (DEBUG) { - System.err.println("DatatypeFactory created: " + datatypeFactory.toString()); - } - if (DEBUG) { - System.err.println("testing value: \"" + actualLex + "\", expecting: \"" + expectedLex + "\""); - } + @ParameterizedTest + @MethodSource("lexicalvalues") + public void testNewDurationYearMonthLexicalRepresentation1(String actualLex, String expectedLex) + throws DatatypeConfigurationException { + DatatypeFactory datatypeFactory = DatatypeFactory.newInstance(); try { Duration duration = datatypeFactory.newDurationYearMonth(actualLex); - if (DEBUG) { - System.err.println("Duration created: \"" + duration.toString() + "\""); - } - // was this expected to fail? - Assert.assertNotEquals(expectedLex, TEST_VALUE_FAIL, "the value \"" + actualLex + "\" is invalid " + - "yet it created the Duration \"" + duration.toString() + "\"" ); + assertNotEquals(TEST_VALUE_FAIL, expectedLex, "the value \"" + actualLex + "\" is invalid " + + "yet it created the Duration \"" + duration.toString() + "\""); // right XMLSchemaType? // TODO: enable test, it should pass, it fails with Exception(s) // for now due to a bug try { QName xmlSchemaType = duration.getXMLSchemaType(); - Assert.assertEquals(xmlSchemaType, DatatypeConstants.DURATION_YEARMONTH, "Duration created with " + + assertEquals(DatatypeConstants.DURATION_YEARMONTH, xmlSchemaType, "Duration created with " + "XMLSchemaType of\"" + xmlSchemaType + "\" was expected to be \"" - + DatatypeConstants.DURATION_YEARMONTH + "\" and has the value \"" + duration.toString() + "\""); - } catch (IllegalStateException illegalStateException) { - // TODO; this test really should pass - System.err.println("Please fix this bug that is being ignored, for now: " + illegalStateException.getMessage()); - } - - // does it have the right value? - Assert.assertEquals(duration.toString(), expectedLex, "Duration created with \"" + actualLex + - "\" was expected to be \"" + expectedLex + "\" and has the value \"" + duration.toString() + "\""); - // Duration created with correct value - } catch (Exception exception) { - if (DEBUG) { - System.err.println("Exception in creating duration: \"" + exception.toString() + "\""); - } - - // was this expected to succed? - Assert.assertEquals(TEST_VALUE_FAIL, expectedLex, "the value \"" + actualLex + "\" is valid yet " + - "it failed with \"" + exception.toString() + "\""); - // expected failure + + DatatypeConstants.DURATION_YEARMONTH + "\" and has the value \"" + duration + "\""); + } catch (IllegalStateException illegalStateException) { + // TODO; this test really should pass + System.err.println("Please fix this bug that is being ignored, for now: " + illegalStateException.getMessage()); } + + // does it have the right value? + assertEquals(expectedLex, duration.toString(), "Duration created with \"" + actualLex + + "\" was expected to be \"" + expectedLex + "\" and has the value \"" + duration + "\""); + // Duration created with correct value + } catch (Exception exception) { + // was this expected to succed? + assertEquals(TEST_VALUE_FAIL, expectedLex, "the value \"" + actualLex + "\" is valid yet " + + "it failed with \"" + exception + "\""); + // expected failure + } } - @DataProvider(name = "lexDayTime") - public Object[][] lexDayTimeData() { + public static Object[][] lexDayTimeData() { BigInteger one = new BigInteger("1"); BigInteger zero = new BigInteger("0"); BigDecimal bdZero = new BigDecimal("0"); BigDecimal bdOne = new BigDecimal("1"); - Object[][] values = { + return new Object[][] { // lex, isPositive, years, month, days, hours, minutes, seconds - { "P1D", Boolean.TRUE, null, null, one, zero, zero, bdZero }, { "PT1H", Boolean.TRUE, null, null, zero, one, zero, bdZero }, - { "PT1M", Boolean.TRUE, null, null, zero, zero, one, bdZero }, { "PT1.1S", Boolean.TRUE, null, null, zero, zero, zero, bdOne }, + { "P1D", Boolean.TRUE, null, null, one, zero, zero, bdZero }, + { "PT1H", Boolean.TRUE, null, null, zero, one, zero, bdZero }, + { "PT1M", Boolean.TRUE, null, null, zero, zero, one, bdZero }, + { "PT1.1S", Boolean.TRUE, null, null, zero, zero, zero, bdOne }, { "-PT1H1.1S", Boolean.FALSE, null, null, zero, one, zero, bdOne }, }; - return values; } /** * TCK test failure */ - @Test(dataProvider = "lexDayTime") + @ParameterizedTest + @MethodSource("lexDayTimeData") public void testNewDurationDayTime005(String lex, boolean isPositive, BigInteger year, BigInteger month, BigInteger days, - BigInteger hour, BigInteger minutes, BigDecimal seconds) { - StringBuffer result = new StringBuffer(); - DatatypeFactory df = null; - - try { - df = DatatypeFactory.newInstance(); - } catch (DatatypeConfigurationException e) { - Assert.fail(e.toString()); - } + BigInteger hour, BigInteger minutes, BigDecimal seconds) + throws DatatypeConfigurationException { + StringBuilder result = new StringBuilder(); + DatatypeFactory df = DatatypeFactory.newInstance(); Duration duration = null; try { duration = df.newDurationDayTime(isPositive, days, hour, minutes, seconds.toBigInteger()); } catch (IllegalArgumentException e) { - result.append("; unexpected " + e + " trying to create duration \'" + lex + "\'"); + result.append("; unexpected " + e + " trying to create duration '" + lex + "'"); } if (duration != null) { if ((duration.getSign() == 1) != isPositive) { @@ -248,43 +215,39 @@ public class Bug6937964Test { Number value = duration.getField(DatatypeConstants.YEARS); if ((value != null && year == null) || (value == null && year != null) || (value != null && !value.equals(year))) { - result.append("; " + lex + ": wrong value of the field " + DatatypeConstants.YEARS + ": \'" + value + "\'" + ", expected \'" - + year + "\'"); + result.append("; " + lex + ": wrong value of the field " + DatatypeConstants.YEARS + ": '" + value + "'" + ", expected '" + + year + "'"); } value = duration.getField(DatatypeConstants.MONTHS); if ((value != null && month == null) || (value == null && month != null) || (value != null && !value.equals(month))) { - result.append("; " + lex + ": wrong value of the field " + DatatypeConstants.MONTHS + ": \'" + value + "\'" + ", expected \'" - + month + "\'"); + result.append("; " + lex + ": wrong value of the field " + DatatypeConstants.MONTHS + ": '" + value + "'" + ", expected '" + + month + "'"); } value = duration.getField(DatatypeConstants.DAYS); if ((value != null && days == null) || (value == null && days != null) || (value != null && !value.equals(days))) { - result.append("; " + lex + ": wrong value of the field " + DatatypeConstants.DAYS + ": \'" + value + "\'" + ", expected \'" - + days + "\'"); + result.append("; " + lex + ": wrong value of the field " + DatatypeConstants.DAYS + ": '" + value + "'" + ", expected '" + + days + "'"); } value = duration.getField(DatatypeConstants.HOURS); if ((value != null && hour == null) || (value == null && hour != null) || (value != null && !value.equals(hour))) { - result.append("; " + lex + ": wrong value of the field " + DatatypeConstants.HOURS + ": \'" + value + "\'" + ", expected \'" - + hour + "\'"); + result.append("; " + lex + ": wrong value of the field " + DatatypeConstants.HOURS + ": '" + value + "'" + ", expected '" + + hour + "'"); } value = duration.getField(DatatypeConstants.MINUTES); if ((value != null && minutes == null) || (value == null && minutes != null) || (value != null && !value.equals(minutes))) { - result.append("; " + lex + ": wrong value of the field " + DatatypeConstants.MINUTES + ": \'" + value + "\'" + ", expected \'" - + minutes + "\'"); + result.append("; " + lex + ": wrong value of the field " + DatatypeConstants.MINUTES + ": '" + value + "'" + ", expected '" + + minutes + "'"); } value = duration.getField(DatatypeConstants.SECONDS); - if ((value != null && seconds == null) || (value == null && seconds != null) || (value != null && !value.equals(seconds))) { - result.append("; " + lex + ": wrong value of the field " + DatatypeConstants.SECONDS + ": \'" + value + "\'" + ", expected \'" - + seconds + "\'"); + if (value == null || !value.equals(seconds)) { + result.append("; " + lex + ": wrong value of the field " + DatatypeConstants.SECONDS + ": '" + value + "'" + ", expected '" + + seconds + "'"); } } - if(result.length() > 0) { - Assert.fail(result.substring(2)); - } - System.out.println("OK"); } } diff --git a/test/jaxp/javax/xml/jaxp/unittest/datatype/Bug7042647Test.java b/test/jaxp/javax/xml/jaxp/unittest/datatype/Bug7042647Test.java index c6b143c1d5a..b434db0e4c4 100644 --- a/test/jaxp/javax/xml/jaxp/unittest/datatype/Bug7042647Test.java +++ b/test/jaxp/javax/xml/jaxp/unittest/datatype/Bug7042647Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * 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,21 +23,21 @@ package datatype; -import java.util.Calendar; -import java.util.GregorianCalendar; +import org.junit.jupiter.api.Test; import javax.xml.datatype.DatatypeConfigurationException; import javax.xml.datatype.DatatypeFactory; import javax.xml.datatype.XMLGregorianCalendar; +import java.util.Calendar; +import java.util.GregorianCalendar; -import org.testng.Assert; -import org.testng.annotations.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; /* * @test * @bug 7042647 * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest - * @run testng/othervm datatype.Bug7042647Test + * @run junit/othervm datatype.Bug7042647Test * @summary Test getFirstDayOfWeek is correct after converting XMLGregorianCalendar to a GregorianCalendar. */ public class Bug7042647Test { @@ -49,11 +49,7 @@ public class Bug7042647Test { int firstDayOfWeek = calendar.getFirstDayOfWeek(); Calendar defaultCalendar = Calendar.getInstance(); int defaultFirstDayOfWeek = defaultCalendar.getFirstDayOfWeek(); - if (firstDayOfWeek != defaultFirstDayOfWeek) { - Assert.fail("Failed firstDayOfWeek=" + firstDayOfWeek + " != defaultFirstDayOfWeek=" + defaultFirstDayOfWeek); - } else { - System.out.println("Success firstDayOfWeek=" + firstDayOfWeek + " == defaultFirstDayOfWeek=" + defaultFirstDayOfWeek); - } + assertEquals(defaultFirstDayOfWeek, firstDayOfWeek); } } diff --git a/test/jaxp/javax/xml/jaxp/unittest/datatype/DatatypeFactoryTest.java b/test/jaxp/javax/xml/jaxp/unittest/datatype/DatatypeFactoryTest.java index 3866ae6a70c..da5862f5adb 100644 --- a/test/jaxp/javax/xml/jaxp/unittest/datatype/DatatypeFactoryTest.java +++ b/test/jaxp/javax/xml/jaxp/unittest/datatype/DatatypeFactoryTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * 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,7 @@ package datatype; -import java.math.BigDecimal; -import java.math.BigInteger; +import org.junit.jupiter.api.Test; import javax.xml.datatype.DatatypeConfigurationException; import javax.xml.datatype.DatatypeConstants; @@ -32,14 +31,15 @@ import javax.xml.datatype.DatatypeFactory; import javax.xml.datatype.Duration; import javax.xml.datatype.XMLGregorianCalendar; import javax.xml.namespace.QName; +import java.math.BigDecimal; +import java.math.BigInteger; -import org.testng.Assert; -import org.testng.annotations.Test; +import static org.junit.jupiter.api.Assertions.fail; /* * @test * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest - * @run testng/othervm datatype.DatatypeFactoryTest + * @run junit/othervm datatype.DatatypeFactoryTest * @summary Test DatatypeFactory. */ public class DatatypeFactoryTest { @@ -120,7 +120,7 @@ public class DatatypeFactoryTest { try { datatypeFactory = DatatypeFactory.newInstance(); } catch (DatatypeConfigurationException datatypeConfigurationException) { - Assert.fail(datatypeConfigurationException.toString()); + fail(datatypeConfigurationException.toString()); } if (DEBUG) { @@ -144,20 +144,20 @@ public class DatatypeFactoryTest { // was this expected to fail? if (TEST_VALUES_MILLISECONDS_RESULTS[onTestValue].equals(TEST_VALUE_FAIL)) { - Assert.fail("the value \"" + TEST_VALUES_MILLISECONDS[onTestValue] + "\" is invalid yet it created the Duration \"" + duration.toString() + fail("the value \"" + TEST_VALUES_MILLISECONDS[onTestValue] + "\" is invalid yet it created the Duration \"" + duration.toString() + "\""); } // right XMLSchemaType? QName xmlSchemaType = duration.getXMLSchemaType(); if (!xmlSchemaType.equals(DatatypeConstants.DURATION)) { - Assert.fail("Duration created with XMLSchemaType of\"" + xmlSchemaType + "\" was expected to be \"" + DatatypeConstants.DURATION + fail("Duration created with XMLSchemaType of\"" + xmlSchemaType + "\" was expected to be \"" + DatatypeConstants.DURATION + "\" and has the value \"" + duration.toString() + "\""); } // does it have the right value? if (!TEST_VALUES_MILLISECONDS_RESULTS[onTestValue].equals(duration.toString())) { - Assert.fail("Duration created with \"" + TEST_VALUES_MILLISECONDS[onTestValue] + "\" was expected to be \"" + fail("Duration created with \"" + TEST_VALUES_MILLISECONDS[onTestValue] + "\" was expected to be \"" + TEST_VALUES_MILLISECONDS_RESULTS[onTestValue] + "\" and has the value \"" + duration.toString() + "\""); } @@ -170,7 +170,7 @@ public class DatatypeFactoryTest { // was this expected to succed? if (!TEST_VALUES_MILLISECONDS_RESULTS[onTestValue].equals(TEST_VALUE_FAIL)) { - Assert.fail("the value \"" + TEST_VALUES_MILLISECONDS[onTestValue] + "\" is valid yet it failed with \"" + exception.toString() + "\""); + fail("the value \"" + TEST_VALUES_MILLISECONDS[onTestValue] + "\" is valid yet it failed with \"" + exception.toString() + "\""); } // expected failure } @@ -195,7 +195,7 @@ public class DatatypeFactoryTest { try { datatypeFactory = DatatypeFactory.newInstance(); } catch (DatatypeConfigurationException datatypeConfigurationException) { - Assert.fail(datatypeConfigurationException.toString()); + fail(datatypeConfigurationException.toString()); } if (DEBUG) { @@ -218,7 +218,7 @@ public class DatatypeFactoryTest { // was this expected to fail? if (TEST_VALUES_LEXICAL[onTestValue + 1].equals(TEST_VALUE_FAIL)) { - Assert.fail("the value \"" + TEST_VALUES_LEXICAL[onTestValue] + "\" is invalid yet it created the Duration \"" + duration.toString() + "\""); + fail("the value \"" + TEST_VALUES_LEXICAL[onTestValue] + "\" is invalid yet it created the Duration \"" + duration.toString() + "\""); } // right XMLSchemaType? @@ -227,7 +227,7 @@ public class DatatypeFactoryTest { try { QName xmlSchemaType = duration.getXMLSchemaType(); if (!xmlSchemaType.equals(DatatypeConstants.DURATION_YEARMONTH)) { - Assert.fail("Duration created with XMLSchemaType of\"" + xmlSchemaType + "\" was expected to be \"" + fail("Duration created with XMLSchemaType of\"" + xmlSchemaType + "\" was expected to be \"" + DatatypeConstants.DURATION_YEARMONTH + "\" and has the value \"" + duration.toString() + "\""); } } catch (IllegalStateException illegalStateException) { @@ -237,7 +237,7 @@ public class DatatypeFactoryTest { // does it have the right value? if (!TEST_VALUES_LEXICAL[onTestValue + 1].equals(duration.toString())) { - Assert.fail("Duration created with \"" + TEST_VALUES_LEXICAL[onTestValue] + "\" was expected to be \"" + fail("Duration created with \"" + TEST_VALUES_LEXICAL[onTestValue] + "\" was expected to be \"" + TEST_VALUES_LEXICAL[onTestValue + 1] + "\" and has the value \"" + duration.toString() + "\""); } @@ -250,7 +250,7 @@ public class DatatypeFactoryTest { // was this expected to succed? if (!TEST_VALUES_LEXICAL[onTestValue + 1].equals(TEST_VALUE_FAIL)) { - Assert.fail("the value \"" + TEST_VALUES_LEXICAL[onTestValue] + "\" is valid yet it failed with \"" + exception.toString() + "\""); + fail("the value \"" + TEST_VALUES_LEXICAL[onTestValue] + "\" is valid yet it failed with \"" + exception.toString() + "\""); } // expected failure } @@ -287,7 +287,7 @@ public class DatatypeFactoryTest { try { datatypeFactory = DatatypeFactory.newInstance(); } catch (DatatypeConfigurationException datatypeConfigurationException) { - Assert.fail(datatypeConfigurationException.toString()); + fail(datatypeConfigurationException.toString()); } if (DEBUG) { @@ -311,20 +311,20 @@ public class DatatypeFactoryTest { // was this expected to fail? if (TEST_VALUES_MILLISECONDS_RESULTS[onTestValue].equals(TEST_VALUE_FAIL)) { - Assert.fail("the value \"" + TEST_VALUES_MILLISECONDS[onTestValue] + "\" is invalid yet it created the Duration \"" + duration.toString() + fail("the value \"" + TEST_VALUES_MILLISECONDS[onTestValue] + "\" is invalid yet it created the Duration \"" + duration.toString() + "\""); } // right XMLSchemaType? QName xmlSchemaType = duration.getXMLSchemaType(); if (!xmlSchemaType.equals(DatatypeConstants.DURATION_YEARMONTH)) { - Assert.fail("Duration created with XMLSchemaType of\"" + xmlSchemaType + "\" was expected to be \"" + DatatypeConstants.DURATION_YEARMONTH + fail("Duration created with XMLSchemaType of\"" + xmlSchemaType + "\" was expected to be \"" + DatatypeConstants.DURATION_YEARMONTH + "\" and has the value \"" + duration.toString() + "\""); } // does it have the right value? if (!TEST_VALUES_MILLISECONDS_RESULTS[onTestValue].equals(duration.toString())) { - Assert.fail("Duration created with \"" + TEST_VALUES_MILLISECONDS[onTestValue] + "\" was expected to be \"" + fail("Duration created with \"" + TEST_VALUES_MILLISECONDS[onTestValue] + "\" was expected to be \"" + TEST_VALUES_MILLISECONDS_RESULTS[onTestValue] + "\" and has the value \"" + duration.toString() + "\""); } @@ -333,7 +333,7 @@ public class DatatypeFactoryTest { int hours = duration.getHours(); int minutes = duration.getMinutes(); if (days != 0 || hours != 0 || minutes != 0) { - Assert.fail("xdt:yearMonthDuration created without discarding remaining milliseconds: " + " days = " + days + ", hours = " + hours + fail("xdt:yearMonthDuration created without discarding remaining milliseconds: " + " days = " + days + ", hours = " + hours + ", minutess = " + minutes); } @@ -346,7 +346,7 @@ public class DatatypeFactoryTest { // was this expected to succed? if (!TEST_VALUES_MILLISECONDS_RESULTS[onTestValue].equals(TEST_VALUE_FAIL)) { - Assert.fail("the value \"" + TEST_VALUES_MILLISECONDS[onTestValue] + "\" is valid yet it failed with \"" + exception.toString() + "\""); + fail("the value \"" + TEST_VALUES_MILLISECONDS[onTestValue] + "\" is valid yet it failed with \"" + exception.toString() + "\""); } // expected failure } @@ -382,7 +382,7 @@ public class DatatypeFactoryTest { try { datatypeFactory = DatatypeFactory.newInstance(); } catch (DatatypeConfigurationException datatypeConfigurationException) { - Assert.fail(datatypeConfigurationException.toString()); + fail(datatypeConfigurationException.toString()); } if (DEBUG) { @@ -406,7 +406,7 @@ public class DatatypeFactoryTest { // was this expected to fail? if (TEST_VALUES_MILLISECONDS_RESULTS[onTestValue].equals(TEST_VALUE_FAIL)) { - Assert.fail("the value \"" + TEST_VALUES_MILLISECONDS[onTestValue] + "\" is invalid yet it created the Duration \"" + duration.toString() + fail("the value \"" + TEST_VALUES_MILLISECONDS[onTestValue] + "\" is invalid yet it created the Duration \"" + duration.toString() + "\""); } @@ -414,7 +414,7 @@ public class DatatypeFactoryTest { if (!TEST_VALUES_MILLISECONDS_RESULTS[onTestValue].equals(duration.toString())) { // TODO: this is bug that should be fixed if (false) { - Assert.fail("Duration created with \"" + TEST_VALUES_MILLISECONDS[onTestValue] + "\" was expected to be \"" + fail("Duration created with \"" + TEST_VALUES_MILLISECONDS[onTestValue] + "\" was expected to be \"" + TEST_VALUES_MILLISECONDS_RESULTS[onTestValue] + "\" and has the value \"" + duration.toString() + "\""); } else { System.err.println("Please fix this bug: " + "Duration created with \"" + TEST_VALUES_MILLISECONDS[onTestValue] @@ -431,7 +431,7 @@ public class DatatypeFactoryTest { if (!xmlSchemaType.equals(DatatypeConstants.DURATION_DAYTIME) || years != 0 || months != 0) { // TODO: this is bug that should be fixed if (false) { - Assert.fail("xdt:dayTimeDuration created without discarding remaining milliseconds: " + " XMLSchemaType = " + xmlSchemaType + fail("xdt:dayTimeDuration created without discarding remaining milliseconds: " + " XMLSchemaType = " + xmlSchemaType + ", years = " + years + ", months = " + months); } else { System.err.println("Please fix this bug: " + "xdt:dayTimeDuration created without discarding remaining milliseconds: " @@ -448,7 +448,7 @@ public class DatatypeFactoryTest { // was this expected to succed? if (!TEST_VALUES_MILLISECONDS_RESULTS[onTestValue].equals(TEST_VALUE_FAIL)) { - Assert.fail("the value \"" + TEST_VALUES_MILLISECONDS[onTestValue] + "\" is valid yet it failed with \"" + exception.toString() + "\""); + fail("the value \"" + TEST_VALUES_MILLISECONDS[onTestValue] + "\" is valid yet it failed with \"" + exception.toString() + "\""); } // expected failure } @@ -482,7 +482,7 @@ public class DatatypeFactoryTest { try { datatypeFactory = DatatypeFactory.newInstance(); } catch (DatatypeConfigurationException datatypeConfigurationException) { - Assert.fail(datatypeConfigurationException.toString()); + fail(datatypeConfigurationException.toString()); } if (DEBUG) { @@ -505,13 +505,13 @@ public class DatatypeFactoryTest { // was this expected to fail? if (TEST_VALUES_LEXICAL[onTestValue + 1].equals(TEST_VALUE_FAIL)) { - Assert.fail("the value \"" + TEST_VALUES_LEXICAL[onTestValue] + "\" is invalid yet it created the XMLGregorianCalendar \"" + fail("the value \"" + TEST_VALUES_LEXICAL[onTestValue] + "\" is invalid yet it created the XMLGregorianCalendar \"" + xmlGregorianCalendar.toString() + "\""); } // does it have the right value? if (!TEST_VALUES_LEXICAL[onTestValue + 1].equals(xmlGregorianCalendar.toString())) { - Assert.fail("XMLGregorianCalendar created with \"" + TEST_VALUES_LEXICAL[onTestValue] + "\" was expected to be \"" + fail("XMLGregorianCalendar created with \"" + TEST_VALUES_LEXICAL[onTestValue] + "\" was expected to be \"" + TEST_VALUES_LEXICAL[onTestValue + 1] + "\" and has the value \"" + xmlGregorianCalendar.toString() + "\""); } @@ -524,7 +524,7 @@ public class DatatypeFactoryTest { // was this expected to succed? if (!TEST_VALUES_LEXICAL[onTestValue + 1].equals(TEST_VALUE_FAIL)) { - Assert.fail("the value \"" + TEST_VALUES_LEXICAL[onTestValue] + "\" is valid yet it failed with \"" + exception.toString() + "\""); + fail("the value \"" + TEST_VALUES_LEXICAL[onTestValue] + "\" is valid yet it failed with \"" + exception.toString() + "\""); } // expected failure } @@ -563,7 +563,7 @@ public class DatatypeFactoryTest { try { datatypeFactory = DatatypeFactory.newInstance(); } catch (DatatypeConfigurationException datatypeConfigurationException) { - Assert.fail(datatypeConfigurationException.toString()); + fail(datatypeConfigurationException.toString()); } if (DEBUG) { @@ -591,7 +591,7 @@ public class DatatypeFactoryTest { } // unexpected success, should have failed - Assert.fail("expected IllegalArgumentException " + "for DatatypeFactory.newXMLGregorianCalendar(" + invalidDates[valueIndex][0] + ", " + fail("expected IllegalArgumentException " + "for DatatypeFactory.newXMLGregorianCalendar(" + invalidDates[valueIndex][0] + ", " + invalidDates[valueIndex][1] + ", " + invalidDates[valueIndex][2] + ", " + invalidDates[valueIndex][3] + ", " + invalidDates[valueIndex][4] + ", " + invalidDates[valueIndex][5] + ", " + invalidDates[valueIndex][6] + ", " + invalidDates[valueIndex][7] + "). " + "Instead, XMLGregorianCalendar: \"" + xmlGregorianCalendar.toString() + "\" was created."); @@ -624,7 +624,7 @@ public class DatatypeFactoryTest { } // unexpected success, should have failed - Assert.fail("expected IllegalArgumentException " + "for DatatypeFactory.newXMLGregorianCalendar(" + invalidDates[valueIndex][0] + ", " + fail("expected IllegalArgumentException " + "for DatatypeFactory.newXMLGregorianCalendar(" + invalidDates[valueIndex][0] + ", " + invalidDates[valueIndex][1] + ", " + invalidDates[valueIndex][2] + ", " + invalidDates[valueIndex][3] + ", " + invalidDates[valueIndex][4] + ", " + invalidDates[valueIndex][5] + ", " + invalidDates[valueIndex][6] + ", " + invalidDates[valueIndex][7] + "). " + "Instead, XMLGregorianCalendar: \"" + xmlGregorianCalendar.toString() + "\" was created."); diff --git a/test/jaxp/javax/xml/jaxp/unittest/datatype/DurationTest.java b/test/jaxp/javax/xml/jaxp/unittest/datatype/DurationTest.java index d4d96449f82..6de8fe91370 100644 --- a/test/jaxp/javax/xml/jaxp/unittest/datatype/DurationTest.java +++ b/test/jaxp/javax/xml/jaxp/unittest/datatype/DurationTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * 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,16 @@ package datatype; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import javax.xml.datatype.DatatypeConfigurationException; +import javax.xml.datatype.DatatypeConstants; +import javax.xml.datatype.DatatypeFactory; +import javax.xml.datatype.Duration; +import javax.xml.namespace.QName; import java.math.BigDecimal; import java.math.BigInteger; import java.util.Calendar; @@ -30,47 +40,37 @@ import java.util.Date; import java.util.GregorianCalendar; import java.util.TimeZone; -import javax.xml.datatype.DatatypeConfigurationException; -import javax.xml.datatype.DatatypeConstants; -import javax.xml.datatype.DatatypeFactory; -import javax.xml.datatype.Duration; -import javax.xml.namespace.QName; - -import org.testng.Assert; -import org.testng.AssertJUnit; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; /* * @test * @bug 8190835 * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest - * @run testng/othervm datatype.DurationTest + * @run junit/othervm datatype.DurationTest * @summary Test Duration. */ public class DurationTest { private final static boolean DEBUG = true; - protected Duration duration = null; + private DatatypeFactory factory = null; + private Duration duration = null; - @BeforeMethod - public void setUp() { - try { - duration = DatatypeFactory.newInstance().newDuration(100); - } catch (DatatypeConfigurationException dce) { - dce.printStackTrace(); - Assert.fail("Failed to create instance of DatatypeFactory " + dce.getMessage()); - } + @BeforeEach + public void setUp() throws DatatypeConfigurationException { + factory = DatatypeFactory.newInstance(); + duration = factory.newDuration(100); } /* DataProvider: for testDurationSubtract1 Data: minuend, subtrahend, expected result */ - @DataProvider(name = "DurationSubtract1") - public Object[][] getSubtract1() { + public static Object[][] getSubtract1() { return new Object[][]{ {"P2Y2M", "P1Y5M", "P9M"}, @@ -84,8 +84,7 @@ public class DurationTest { }; } - @DataProvider(name = "DurationSubtract2") - public Object[][] getSubtract2() { + public static Object[][] getSubtract2() { return new Object[][]{ {"P2Y20D", "P1Y125D"}, @@ -96,67 +95,60 @@ public class DurationTest { /* * Verifies valid substraction operations. */ - @Test(dataProvider = "DurationSubtract1") - public void testDurationSubtract1(String t1, String t2, String e) throws Exception { - DatatypeFactory factory = DatatypeFactory.newInstance(); + @ParameterizedTest + @MethodSource("getSubtract1") + public void testDurationSubtract1(String t1, String t2, String e) { Duration dt1 = factory.newDuration(t1); Duration dt2 = factory.newDuration(t2); Duration result = dt1.subtract(dt2); - Duration expected = factory.newDuration(e); - Assert.assertTrue(result.equals(expected), "The result should be " + e); + assertEquals(factory.newDuration(e), result, "The result should be " + e); } /* * Verifies invalid substraction operations. These operations are invalid * since days in a month are indeterminate. - */ - @Test(dataProvider = "DurationSubtract2", expectedExceptions = IllegalStateException.class) - public void testDurationSubtract2(String t1, String t2) throws Exception { - DatatypeFactory factory = DatatypeFactory.newInstance(); + */ + @ParameterizedTest + @MethodSource("getSubtract2") + public void testDurationSubtract2(String t1, String t2) { Duration dt1 = factory.newDuration(t1); Duration dt2 = factory.newDuration(t2); - Duration result = dt1.subtract(dt2); + assertThrows(IllegalStateException.class, () -> dt1.subtract(dt2)); } @Test public void testDurationSubtract() { - try { - Duration bigDur = DatatypeFactory.newInstance().newDuration(20000); - Duration smallDur = DatatypeFactory.newInstance().newDuration(10000); - if (smallDur.subtract(bigDur).getSign() != -1) { - Assert.fail("smallDur.subtract(bigDur).getSign() is not -1"); - } - if (bigDur.subtract(smallDur).getSign() != 1) { - Assert.fail("bigDur.subtract(smallDur).getSign() is not 1"); - } - if (smallDur.subtract(smallDur).getSign() != 0) { - Assert.fail("smallDur.subtract(smallDur).getSign() is not 0"); - } - } catch (DatatypeConfigurationException e) { - e.printStackTrace(); + Duration bigDur = factory.newDuration(20000); + Duration smallDur = factory.newDuration(10000); + if (smallDur.subtract(bigDur).getSign() != -1) { + fail("smallDur.subtract(bigDur).getSign() is not -1"); } + if (bigDur.subtract(smallDur).getSign() != 1) { + fail("bigDur.subtract(smallDur).getSign() is not 1"); + } + if (smallDur.subtract(smallDur).getSign() != 0) { + fail("smallDur.subtract(smallDur).getSign() is not 0"); + } + } @Test public void testDurationMultiply() { int num = 5000; // millisends. 5 seconds int factor = 2; - try { - Duration dur = DatatypeFactory.newInstance().newDuration(num); - if (dur.multiply(factor).getSeconds() != 10) { - Assert.fail("duration.multiply() return wrong value"); - } - // factor is 2*10^(-1) - if (dur.multiply(new BigDecimal(new BigInteger("2"), 1)).getSeconds() != 1) { - Assert.fail("duration.multiply() return wrong value"); - } - if (dur.subtract(DatatypeFactory.newInstance().newDuration(1000)).multiply(new BigDecimal(new BigInteger("2"), 1)).getSeconds() != 0) { - Assert.fail("duration.multiply() return wrong value"); - } - } catch (DatatypeConfigurationException e) { - e.printStackTrace(); + + Duration dur = factory.newDuration(num); + if (dur.multiply(factor).getSeconds() != 10) { + fail("duration.multiply() return wrong value"); + } + // factor is 2*10^(-1) + if (dur.multiply(new BigDecimal(new BigInteger("2"), 1)).getSeconds() != 1) { + fail("duration.multiply() return wrong value"); + } + if (dur.subtract(factory.newDuration(1000)).multiply(new BigDecimal(new BigInteger("2"), 1)).getSeconds() != 0) { + fail("duration.multiply() return wrong value"); } } @@ -169,73 +161,55 @@ public class DurationTest { int min = 5; int sec = 6; String lexicalRepresentation = "P" + year + "Y" + month + "M" + day + "DT" + hour + "H" + min + "M" + sec + "S"; - try { - Duration dur = DatatypeFactory.newInstance().newDuration(lexicalRepresentation); - System.out.println(dur.toString()); - AssertJUnit.assertTrue("year should be 1", dur.getYears() == year); - AssertJUnit.assertTrue("month should be 2", dur.getMonths() == month); - AssertJUnit.assertTrue("day should be 3", dur.getDays() == day); - AssertJUnit.assertTrue("hour should be 4", dur.getHours() == hour); - AssertJUnit.assertTrue("minute should be 5", dur.getMinutes() == min); - AssertJUnit.assertTrue("second should be 6", dur.getSeconds() == sec); - } catch (DatatypeConfigurationException e) { - e.printStackTrace(); - } + + Duration dur = factory.newDuration(lexicalRepresentation); + System.out.println(dur.toString()); + assertEquals(year, dur.getYears(), "year should be 1"); + assertEquals(month, dur.getMonths(), "month should be 2"); + assertEquals(day, dur.getDays(), "day should be 3"); + assertEquals(hour, dur.getHours(), "hour should be 4"); + assertEquals(min, dur.getMinutes(), "minute should be 5"); + assertEquals(sec, dur.getSeconds(), "second should be 6"); } @Test public void testDurationAndCalendar2() { - try { - AssertJUnit.assertTrue("10.00099S means 10 sec since it will be rounded to zero", DatatypeFactory.newInstance().newDuration("PT10.00099S") - .getTimeInMillis(new Date()) == 10000); - AssertJUnit.assertTrue("10.00099S means 10 sec since it will be rounded to zero", DatatypeFactory.newInstance().newDuration("-PT10.00099S") - .getTimeInMillis(new Date()) == -10000); - AssertJUnit.assertTrue("10.00099S means 10 sec since it will be rounded to zero", DatatypeFactory.newInstance().newDuration("PT10.00099S") - .getTimeInMillis(new GregorianCalendar()) == 10000); - AssertJUnit.assertTrue("10.00099S means 10 sec since it will be rounded to zero", DatatypeFactory.newInstance().newDuration("-PT10.00099S") - .getTimeInMillis(new GregorianCalendar()) == -10000); - } catch (DatatypeConfigurationException e) { - e.printStackTrace(); - } + assertEquals(10000, factory.newDuration("PT10.00099S") + .getTimeInMillis(new Date()), "10.00099S means 10 sec since it will be rounded to zero"); + assertEquals(-10000, factory.newDuration("-PT10.00099S") + .getTimeInMillis(new Date()), "10.00099S means 10 sec since it will be rounded to zero"); + assertEquals(10000, factory.newDuration("PT10.00099S") + .getTimeInMillis(new GregorianCalendar()), "10.00099S means 10 sec since it will be rounded to zero"); + assertEquals(-10000, factory.newDuration("-PT10.00099S") + .getTimeInMillis(new GregorianCalendar()), "10.00099S means 10 sec since it will be rounded to zero"); } @Test public void testDurationAndCalendar3() { - try { - Calendar cal = new GregorianCalendar(); - cal.set(Calendar.SECOND, 59); - DatatypeFactory.newInstance().newDuration(10000).addTo(cal); - AssertJUnit.assertTrue("sec will be 9", cal.get(Calendar.SECOND) == 9); + Calendar cal = new GregorianCalendar(); + cal.set(Calendar.SECOND, 59); + factory.newDuration(10000).addTo(cal); + assertEquals(9, cal.get(Calendar.SECOND), "sec will be 9"); - Date date = new Date(); - date.setSeconds(59); - DatatypeFactory.newInstance().newDuration(10000).addTo(date); - AssertJUnit.assertTrue("sec will be 9", date.getSeconds() == 9); - } catch (DatatypeConfigurationException e) { - e.printStackTrace(); - } + Date date = new Date(); + date.setSeconds(59); + factory.newDuration(10000).addTo(date); + assertEquals(9, date.getSeconds(), "sec will be 9"); } @Test public void testEqualsWithDifferentObjectParam() { - - AssertJUnit.assertFalse("equals method should return false for any object other than Duration", duration.equals(new Integer(0))); + assertFalse(duration.equals(new Integer(0)), "equals method should return false for any object other than Duration"); } @Test public void testEqualsWithNullObjectParam() { - - AssertJUnit.assertFalse("equals method should return false for null parameter", duration.equals(null)); + assertFalse(duration.equals(null), "equals method should return false for null parameter"); } @Test public void testEqualsWithEqualObjectParam() { - try { - AssertJUnit.assertTrue("equals method is expected to return true", duration.equals(DatatypeFactory.newInstance().newDuration(100))); - } catch (DatatypeConfigurationException dce) { - dce.printStackTrace(); - Assert.fail("Failed to create instance of DatatypeFactory " + dce.getMessage()); - } + assertTrue(duration.equals(factory.newDuration(100)), "equals method is expected to return true"); } /** @@ -250,13 +224,7 @@ public class DurationTest { { "PT2678400S", "<>", "P1M" }, { "PT31536000S", "<>", "P1Y" }, { "PT31622400S", "<>", "P1Y" }, { "PT525600M", "<>", "P1Y" }, { "PT527040M", "<>", "P1Y" }, { "PT8760H", "<>", "P1Y" }, { "PT8784H", "<>", "P1Y" }, { "P365D", "<>", "P1Y" }, }; - DatatypeFactory df = null; - try { - df = DatatypeFactory.newInstance(); - } catch (DatatypeConfigurationException ex) { - ex.printStackTrace(); - Assert.fail(ex.toString()); - } + DatatypeFactory df = factory; boolean compareErrors = false; @@ -272,7 +240,7 @@ public class DurationTest { // tested if (expected != cmp) { compareErrors = true; - System.err.println("returned " + cmp2str(cmp) + " for durations \'" + duration1 + "\' and " + duration2 + "\', but expected " + System.err.println("returned " + cmp2str(cmp) + " for durations '" + duration1 + "' and " + duration2 + "', but expected " + cmp2str(expected)); } } @@ -280,7 +248,7 @@ public class DurationTest { if (compareErrors) { // TODO; fix bug, these tests should pass if (false) { - Assert.fail("Errors in comparing indeterminate relations, see Stderr"); + fail("Errors in comparing indeterminate relations, see Stderr"); } else { System.err.println("Please fix this bug: " + "Errors in comparing indeterminate relations, see Stderr"); } @@ -297,7 +265,7 @@ public class DurationTest { * description concerning return values range. */ @Test - public void testNormalizedReturnValues() throws Exception { + public void testNormalizedReturnValues() { final Object[] TEST_VALUES = { // test 61 seconds -> 1 minute, 1 second @@ -348,9 +316,9 @@ public class DurationTest { }; for (int onValue = 0; onValue < TEST_VALUES.length; onValue += 9) { - newDurationTester(((Boolean) TEST_VALUES[onValue]).booleanValue(), // isPositive, - ((Boolean) NORM_VALUES[onValue]).booleanValue(), // normalized - // isPositive, + newDurationTester((Boolean) TEST_VALUES[onValue], // isPositive, + (Boolean) NORM_VALUES[onValue], // normalized + // isPositive, (BigInteger) TEST_VALUES[onValue + 1], // years, (BigInteger) NORM_VALUES[onValue + 1], // normalized years, (BigInteger) TEST_VALUES[onValue + 2], // months @@ -363,16 +331,16 @@ public class DurationTest { (BigInteger) NORM_VALUES[onValue + 5], // normalized minutes (BigDecimal) TEST_VALUES[onValue + 6], // seconds (BigDecimal) NORM_VALUES[onValue + 6], // normalized seconds - ((Long) TEST_VALUES[onValue + 7]).longValue(), // durationInMilliSeconds, - ((Long) NORM_VALUES[onValue + 7]).longValue(), // normalized - // durationInMilliSeconds, + (Long) TEST_VALUES[onValue + 7], // durationInMilliSeconds, + (Long) NORM_VALUES[onValue + 7], // normalized + // durationInMilliSeconds, (String) TEST_VALUES[onValue + 8], // lexicalRepresentation (String) NORM_VALUES[onValue + 8]); // normalized // lexicalRepresentation - newDurationDayTimeTester(((Boolean) TEST_VALUES[onValue]).booleanValue(), // isPositive, - ((Boolean) NORM_VALUES[onValue]).booleanValue(), // normalized - // isPositive, + newDurationDayTimeTester((Boolean) TEST_VALUES[onValue], // isPositive, + (Boolean) NORM_VALUES[onValue], // normalized + // isPositive, BigInteger.ZERO, // years, BigInteger.ZERO, // normalized years, BigInteger.ZERO, // months @@ -385,9 +353,9 @@ public class DurationTest { (BigInteger) NORM_VALUES[onValue + 5], // normalized minutes (BigDecimal) TEST_VALUES[onValue + 6], // seconds (BigDecimal) NORM_VALUES[onValue + 6], // normalized seconds - ((Long) TEST_VALUES[onValue + 7]).longValue(), // durationInMilliSeconds, - ((Long) NORM_VALUES[onValue + 7]).longValue(), // normalized - // durationInMilliSeconds, + (Long) TEST_VALUES[onValue + 7], // durationInMilliSeconds, + (Long) NORM_VALUES[onValue + 7], // normalized + // durationInMilliSeconds, (String) TEST_VALUES[onValue + 8], // lexicalRepresentation (String) NORM_VALUES[onValue + 8]); // normalized // lexicalRepresentation @@ -399,33 +367,24 @@ public class DurationTest { BigInteger normalizedMinutes, BigDecimal seconds, BigDecimal normalizedSeconds, long durationInMilliSeconds, long normalizedDurationInMilliSeconds, String lexicalRepresentation, String normalizedLexicalRepresentation) { - DatatypeFactory datatypeFactory = null; - try { - datatypeFactory = DatatypeFactory.newInstance(); - } catch (DatatypeConfigurationException ex) { - ex.printStackTrace(); - Assert.fail(ex.toString()); - } - // create 4 Durations using the 4 different constructors - - Duration durationBigInteger = datatypeFactory.newDuration(isPositive, years, months, days, hours, minutes, seconds); + Duration durationBigInteger = factory.newDuration(isPositive, years, months, days, hours, minutes, seconds); durationAssertEquals(durationBigInteger, DatatypeConstants.DURATION, normalizedIsPositive, normalizedYears.intValue(), normalizedMonths.intValue(), normalizedDays.intValue(), normalizedHours.intValue(), normalizedMinutes.intValue(), normalizedSeconds.intValue(), normalizedDurationInMilliSeconds, normalizedLexicalRepresentation); - Duration durationInt = datatypeFactory.newDuration(isPositive, years.intValue(), months.intValue(), days.intValue(), hours.intValue(), + Duration durationInt = factory.newDuration(isPositive, years.intValue(), months.intValue(), days.intValue(), hours.intValue(), minutes.intValue(), seconds.intValue()); durationAssertEquals(durationInt, DatatypeConstants.DURATION, normalizedIsPositive, normalizedYears.intValue(), normalizedMonths.intValue(), normalizedDays.intValue(), normalizedHours.intValue(), normalizedMinutes.intValue(), normalizedSeconds.intValue(), normalizedDurationInMilliSeconds, normalizedLexicalRepresentation); - Duration durationMilliseconds = datatypeFactory.newDuration(durationInMilliSeconds); + Duration durationMilliseconds = factory.newDuration(durationInMilliSeconds); durationAssertEquals(durationMilliseconds, DatatypeConstants.DURATION, normalizedIsPositive, normalizedYears.intValue(), normalizedMonths.intValue(), normalizedDays.intValue(), normalizedHours.intValue(), normalizedMinutes.intValue(), normalizedSeconds.intValue(), normalizedDurationInMilliSeconds, normalizedLexicalRepresentation); - Duration durationLexical = datatypeFactory.newDuration(lexicalRepresentation); + Duration durationLexical = factory.newDuration(lexicalRepresentation); durationAssertEquals(durationLexical, DatatypeConstants.DURATION, normalizedIsPositive, normalizedYears.intValue(), normalizedMonths.intValue(), normalizedDays.intValue(), normalizedHours.intValue(), normalizedMinutes.intValue(), normalizedSeconds.intValue(), normalizedDurationInMilliSeconds, normalizedLexicalRepresentation); @@ -436,17 +395,8 @@ public class DurationTest { BigInteger normalizedMinutes, BigDecimal seconds, BigDecimal normalizedSeconds, long durationInMilliSeconds, long normalizedDurationInMilliSeconds, String lexicalRepresentation, String normalizedLexicalRepresentation) { - DatatypeFactory datatypeFactory = null; - try { - datatypeFactory = DatatypeFactory.newInstance(); - } catch (DatatypeConfigurationException ex) { - ex.printStackTrace(); - Assert.fail(ex.toString()); - } - // create 4 dayTime Durations using the 4 different constructors - - Duration durationDayTimeBigInteger = datatypeFactory.newDurationDayTime(isPositive, days, hours, minutes, seconds.toBigInteger()); + Duration durationDayTimeBigInteger = factory.newDurationDayTime(isPositive, days, hours, minutes, seconds.toBigInteger()); durationAssertEquals(durationDayTimeBigInteger, DatatypeConstants.DURATION_DAYTIME, normalizedIsPositive, normalizedYears.intValue(), normalizedMonths.intValue(), normalizedDays.intValue(), normalizedHours.intValue(), normalizedMinutes.intValue(), normalizedSeconds.intValue(), normalizedDurationInMilliSeconds, normalizedLexicalRepresentation); @@ -482,7 +432,7 @@ public class DurationTest { // sign if (DEBUG) { - boolean actual = (duration.getSign() == 1) ? true : false; + boolean actual = duration.getSign() == 1; System.out.println("sign:"); System.out.println(" expected: \"" + isPositive + "\""); System.out.println(" actual: \"" + actual + "\""); diff --git a/test/jaxp/javax/xml/jaxp/unittest/datatype/FactoryFindTest.java b/test/jaxp/javax/xml/jaxp/unittest/datatype/FactoryFindTest.java index 47a965e8665..5c37c4f435c 100644 --- a/test/jaxp/javax/xml/jaxp/unittest/datatype/FactoryFindTest.java +++ b/test/jaxp/javax/xml/jaxp/unittest/datatype/FactoryFindTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * 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,48 +23,48 @@ package datatype; +import org.junit.jupiter.api.Test; + +import javax.xml.datatype.DatatypeFactory; import java.net.URL; import java.net.URLClassLoader; -import javax.xml.datatype.DatatypeFactory; -import org.testng.Assert; -import org.testng.annotations.Test; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; /* * @test * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest - * @run testng/othervm datatype.FactoryFindTest + * @run junit/othervm datatype.FactoryFindTest * @summary Test Classloader for DatatypeFactory. */ public class FactoryFindTest { - boolean myClassLoaderUsed = false; - @Test public void testFactoryFind() throws Exception { DatatypeFactory factory = DatatypeFactory.newInstance(); - Assert.assertTrue(factory.getClass().getClassLoader() == null); + assertNull(factory.getClass().getClassLoader()); Thread.currentThread().setContextClassLoader(null); - factory = DatatypeFactory.newInstance(); - Assert.assertTrue(factory.getClass().getClassLoader() == null); + assertNull(factory.getClass().getClassLoader()); - Thread.currentThread().setContextClassLoader(new MyClassLoader()); - factory = DatatypeFactory.newInstance(); - if (System.getSecurityManager() == null) - Assert.assertTrue(myClassLoaderUsed); - else - Assert.assertFalse(myClassLoaderUsed); + MyClassLoader customLoader = new MyClassLoader(); + Thread.currentThread().setContextClassLoader(customLoader); + assertNotNull(DatatypeFactory.newInstance()); + assertTrue(customLoader.wasUsed); } - class MyClassLoader extends URLClassLoader { + static class MyClassLoader extends URLClassLoader { + boolean wasUsed = false; public MyClassLoader() { super(new URL[0]); } - public Class loadClass(String name) throws ClassNotFoundException { - myClassLoaderUsed = true; + public Class loadClass(String name) throws ClassNotFoundException { + wasUsed = true; return super.loadClass(name); } } diff --git a/test/jaxp/javax/xml/jaxp/unittest/datatype/HashCodeTest.java b/test/jaxp/javax/xml/jaxp/unittest/datatype/HashCodeTest.java index 6d16c676918..9ade9bceb63 100644 --- a/test/jaxp/javax/xml/jaxp/unittest/datatype/HashCodeTest.java +++ b/test/jaxp/javax/xml/jaxp/unittest/datatype/HashCodeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * 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,19 @@ package datatype; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + import javax.xml.datatype.DatatypeFactory; import javax.xml.datatype.XMLGregorianCalendar; -import org.testng.annotations.Test; -import org.testng.Assert; -import org.testng.annotations.DataProvider; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; /* * @test * @bug 8246816 - * @run testng datatype.HashCodeTest + * @run junit datatype.HashCodeTest * @summary Test hashCode generation. */ public class HashCodeTest { @@ -40,26 +43,26 @@ public class HashCodeTest { DataProvider: for testHashCode Data: datetime1, datetime2, flag indicating if their hashCodes are equal */ - @DataProvider(name = "testHashCode") - public Object[][] getData() { + public static Object[][] getData() { - return new Object[][]{ - // the reported case: identical hash codes before the patch - {"2020-04-24T12:53:00+02:00", "2020-06-04T06:58:17.727Z", false}, - // a case mentioned in the dev note of hashCode() implementation - {"2000-01-15T12:00:00-05:00", "2000-01-15T13:00:00-04:00", true}, - /** - * Comparing with a datetime that needs to be normalized. - * Before the patch, XMLGregorianCalendarImpl called the normalizeToTimezone - * method that will set UNDEFINED fractional second to zero. - */ - {"2000-01-01T03:19:04Z", "1999-12-31T23:49:04-03:30", true}, - // another case mentioned in the javadoc of XMLGregorianCalendar::normalize() - {"2000-03-04T23:00:00+03:00", "2000-03-04T20:00:00Z", true}, + return new Object[][] { + // the reported case: identical hash codes before the patch + { "2020-04-24T12:53:00+02:00", "2020-06-04T06:58:17.727Z", false }, + // a case mentioned in the dev note of hashCode() implementation + { "2000-01-15T12:00:00-05:00", "2000-01-15T13:00:00-04:00", true }, + /* + * Comparing with a datetime that needs to be normalized. + * Before the patch, XMLGregorianCalendarImpl called the normalizeToTimezone + * method that will set UNDEFINED fractional second to zero. + */ + { "2000-01-01T03:19:04Z", "1999-12-31T23:49:04-03:30", true }, + // another case mentioned in the javadoc of XMLGregorianCalendar::normalize() + { "2000-03-04T23:00:00+03:00", "2000-03-04T20:00:00Z", true }, }; } - @Test(dataProvider = "testHashCode") + @ParameterizedTest + @MethodSource("getData") public final void testHashCode(String dt1, String dt2, boolean equal) throws Exception { DatatypeFactory dataTypeFactory = DatatypeFactory.newInstance(); XMLGregorianCalendar cal1 = dataTypeFactory.newXMLGregorianCalendar(dt1); @@ -70,11 +73,11 @@ public class HashCodeTest { int hashCode2 = cal2.hashCode(); if (equal) { - Assert.assertTrue(cal1.equals(cal2)); - Assert.assertEquals(hashCode1, hashCode2); + assertEquals(cal1, cal2); + assertEquals(hashCode1, hashCode2); } else { - Assert.assertFalse(cal1.equals(cal2)); - Assert.assertNotEquals(hashCode1, hashCode2); + assertNotEquals(cal1, cal2); + assertNotEquals(hashCode1, hashCode2); } } } diff --git a/test/jaxp/javax/xml/jaxp/unittest/datatype/JDK8068839Test.java b/test/jaxp/javax/xml/jaxp/unittest/datatype/JDK8068839Test.java index 7fe96d741ee..cebdf563946 100644 --- a/test/jaxp/javax/xml/jaxp/unittest/datatype/JDK8068839Test.java +++ b/test/jaxp/javax/xml/jaxp/unittest/datatype/JDK8068839Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * 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,18 +22,19 @@ */ package datatype; +import org.junit.jupiter.api.Test; + import javax.xml.datatype.DatatypeConfigurationException; import javax.xml.datatype.DatatypeFactory; import javax.xml.datatype.Duration; -import org.testng.Assert; -import org.testng.annotations.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; /* * @test * @bug 8068839 * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest - * @run testng/othervm datatype.JDK8068839Test + * @run junit/othervm datatype.JDK8068839Test * @summary Verifies that Duration's edge cases */ public class JDK8068839Test { @@ -42,9 +43,9 @@ public class JDK8068839Test { public void test() throws DatatypeConfigurationException { DatatypeFactory df = DatatypeFactory.newInstance(); Duration durationx = df.newDuration(Long.MIN_VALUE); - Assert.assertEquals(durationx.toString(), "-P292277024Y7M16DT7H12M55.808S"); + assertEquals("-P292277024Y7M16DT7H12M55.808S", durationx.toString()); durationx = df.newDuration(Long.MAX_VALUE); - Assert.assertEquals(durationx.toString(), "P292277024Y7M16DT7H12M55.807S"); + assertEquals("P292277024Y7M16DT7H12M55.807S", durationx.toString()); } } diff --git a/test/jaxp/javax/xml/jaxp/unittest/datatype/XMLGregorianCalendarTest.java b/test/jaxp/javax/xml/jaxp/unittest/datatype/XMLGregorianCalendarTest.java index df97f5c7a2b..3a5be07b02d 100644 --- a/test/jaxp/javax/xml/jaxp/unittest/datatype/XMLGregorianCalendarTest.java +++ b/test/jaxp/javax/xml/jaxp/unittest/datatype/XMLGregorianCalendarTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * 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,19 +23,23 @@ package datatype; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + import javax.xml.datatype.DatatypeConfigurationException; import javax.xml.datatype.DatatypeConstants; import javax.xml.datatype.DatatypeFactory; import javax.xml.datatype.XMLGregorianCalendar; -import org.testng.Assert; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; /* * @test * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest - * @run testng/othervm datatype.XMLGregorianCalendarTest + * @run junit/othervm datatype.XMLGregorianCalendarTest * @summary Test XMLGregorianCalendar. */ public class XMLGregorianCalendarTest { @@ -46,41 +50,26 @@ public class XMLGregorianCalendarTest { private static final int TEST_VALUE_PASS = 1; + private DatatypeFactory factory; private XMLGregorianCalendar calendar; - @BeforeMethod - public void setUp() { - try { - calendar = DatatypeFactory.newInstance().newXMLGregorianCalendar(); - } catch (DatatypeConfigurationException dce) { - dce.printStackTrace(); - Assert.fail("Failed to create instance of DatatypeFactory " + dce.getMessage()); - } + @BeforeEach + public void setUp() throws DatatypeConfigurationException { + factory = DatatypeFactory.newInstance(); + calendar = factory.newXMLGregorianCalendar(); } @Test public final void testSetTime() { - /** + /* * Hour, minute, second values to test and expected result. */ final int[] TEST_VALUES = { 24, 0, 0, TEST_VALUE_PASS, 24, 1, 0, TEST_VALUE_FAIL, 24, 0, 1, TEST_VALUE_FAIL, 24, DatatypeConstants.FIELD_UNDEFINED, 0, TEST_VALUE_FAIL, 24, 0, DatatypeConstants.FIELD_UNDEFINED, TEST_VALUE_FAIL }; - // create DatatypeFactory - DatatypeFactory datatypeFactory = null; - try { - datatypeFactory = DatatypeFactory.newInstance(); - } catch (DatatypeConfigurationException datatypeConfigurationException) { - Assert.fail(datatypeConfigurationException.toString()); - } - - if (DEBUG) { - System.err.println("DatatypeFactory created: " + datatypeFactory.toString()); - } - // create XMLGregorianCalendar - XMLGregorianCalendar xmlGregorianCalendar = datatypeFactory.newXMLGregorianCalendar(); + XMLGregorianCalendar xmlGregorianCalendar = factory.newXMLGregorianCalendar(); // test each value for (int onTestValue = 0; onTestValue < TEST_VALUES.length; onTestValue = onTestValue + 4) { @@ -95,24 +84,24 @@ public class XMLGregorianCalendarTest { xmlGregorianCalendar.setTime(TEST_VALUES[onTestValue], TEST_VALUES[onTestValue + 1], TEST_VALUES[onTestValue + 2]); if (DEBUG) { - System.err.println("XMLGregorianCalendar created: \"" + xmlGregorianCalendar.toString() + "\""); + System.err.println("XMLGregorianCalendar created: \"" + xmlGregorianCalendar + "\""); } // was this expected to fail? if (TEST_VALUES[onTestValue + 3] == TEST_VALUE_FAIL) { - Assert.fail("the values: (" + TEST_VALUES[onTestValue] + ", " + TEST_VALUES[onTestValue + 1] + ", " + TEST_VALUES[onTestValue + 2] - + ") are invalid, " + "yet it created the XMLGregorianCalendar \"" + xmlGregorianCalendar.toString() + "\""); + fail("the values: (" + TEST_VALUES[onTestValue] + ", " + TEST_VALUES[onTestValue + 1] + ", " + TEST_VALUES[onTestValue + 2] + + ") are invalid, " + "yet it created the XMLGregorianCalendar \"" + xmlGregorianCalendar + "\""); } } catch (Exception exception) { if (DEBUG) { - System.err.println("Exception in creating XMLGregorianCalendar: \"" + exception.toString() + "\""); + System.err.println("Exception in creating XMLGregorianCalendar: \"" + exception + "\""); } // was this expected to succed? if (TEST_VALUES[onTestValue + 3] == TEST_VALUE_PASS) { - Assert.fail("the values: (" + TEST_VALUES[onTestValue] + ", " + TEST_VALUES[onTestValue + 1] + ", " + TEST_VALUES[onTestValue + 2] - + ") are valid yet it failed with \"" + exception.toString() + "\""); + fail("the values: (" + TEST_VALUES[onTestValue] + ", " + TEST_VALUES[onTestValue + 1] + ", " + TEST_VALUES[onTestValue + 2] + + ") are valid yet it failed with \"" + exception + "\""); } // expected failure } @@ -122,7 +111,7 @@ public class XMLGregorianCalendarTest { @Test public final void testSetHour() { - /** + /* * Hour values to test and expected result. */ final int[] TEST_VALUES = { @@ -133,20 +122,8 @@ public class XMLGregorianCalendarTest { // violates Schema Errata 0, 0, 1, 24, TEST_VALUE_FAIL }; - // create DatatypeFactory - DatatypeFactory datatypeFactory = null; - try { - datatypeFactory = DatatypeFactory.newInstance(); - } catch (DatatypeConfigurationException datatypeConfigurationException) { - Assert.fail(datatypeConfigurationException.toString()); - } - - if (DEBUG) { - System.err.println("DatatypeFactory created: " + datatypeFactory.toString()); - } - // create XMLGregorianCalendar - XMLGregorianCalendar xmlGregorianCalendar = datatypeFactory.newXMLGregorianCalendar(); + XMLGregorianCalendar xmlGregorianCalendar = factory.newXMLGregorianCalendar(); // test each value for (int onTestValue = 0; onTestValue < TEST_VALUES.length; onTestValue = onTestValue + 5) { @@ -163,25 +140,25 @@ public class XMLGregorianCalendarTest { xmlGregorianCalendar.setHour(TEST_VALUES[onTestValue + 3]); if (DEBUG) { - System.err.println("XMLGregorianCalendar created: \"" + xmlGregorianCalendar.toString() + "\""); + System.err.println("XMLGregorianCalendar created: \"" + xmlGregorianCalendar + "\""); } // was this expected to fail? if (TEST_VALUES[onTestValue + 4] == TEST_VALUE_FAIL) { - Assert.fail("the values: (" + TEST_VALUES[onTestValue] + ", " + TEST_VALUES[onTestValue + 1] + ", " + TEST_VALUES[onTestValue + 2] + ", " - + TEST_VALUES[onTestValue + 3] + ") are invalid, " + "yet it created the XMLGregorianCalendar \"" + xmlGregorianCalendar.toString() + fail("the values: (" + TEST_VALUES[onTestValue] + ", " + TEST_VALUES[onTestValue + 1] + ", " + TEST_VALUES[onTestValue + 2] + ", " + + TEST_VALUES[onTestValue + 3] + ") are invalid, " + "yet it created the XMLGregorianCalendar \"" + xmlGregorianCalendar + "\""); } } catch (Exception exception) { if (DEBUG) { - System.err.println("Exception in creating XMLGregorianCalendar: \"" + exception.toString() + "\""); + System.err.println("Exception in creating XMLGregorianCalendar: \"" + exception + "\""); } // was this expected to succed? if (TEST_VALUES[onTestValue + 4] == TEST_VALUE_PASS) { - Assert.fail("the values: (" + TEST_VALUES[onTestValue] + ", " + TEST_VALUES[onTestValue + 1] + ", " + TEST_VALUES[onTestValue + 2] + ", " - + TEST_VALUES[onTestValue + 3] + ") are valid yet it failed with \"" + exception.toString() + "\""); + fail("the values: (" + TEST_VALUES[onTestValue] + ", " + TEST_VALUES[onTestValue + 1] + ", " + TEST_VALUES[onTestValue + 2] + ", " + + TEST_VALUES[onTestValue + 3] + ") are valid yet it failed with \"" + exception + "\""); } // expected failure } @@ -190,38 +167,24 @@ public class XMLGregorianCalendarTest { @Test public void testEqualsWithDifferentObjectParam() { - - Assert.assertFalse(calendar.equals(new Integer(0)), "equals method should return false for any object other" + " than XMLGregorianCalendar"); + assertFalse(calendar.equals(new Integer(0)), "equals method should return false for any object other" + " than XMLGregorianCalendar"); } @Test public void testEqualsWithNullObjectParam() { - - Assert.assertFalse(calendar.equals(null), "equals method should return false for null parameter"); + assertFalse(calendar.equals(null), "equals method should return false for null parameter"); } @Test public void testEqualsWithEqualObjectParam() { - - try { - Assert.assertTrue(calendar.equals(DatatypeFactory.newInstance().newXMLGregorianCalendar()), "equals method is expected to return true"); - } catch (DatatypeConfigurationException dce) { - dce.printStackTrace(); - Assert.fail("Failed to create instance of DatatypeFactory " + dce.getMessage()); - } + assertTrue(calendar.equals(factory.newXMLGregorianCalendar()), "equals method is expected to return true"); } @Test public void testToString() { - try { - String inputDateTime = "2006-10-23T22:15:01.000000135+08:00"; - DatatypeFactory factory = DatatypeFactory.newInstance(); - XMLGregorianCalendar calendar = factory.newXMLGregorianCalendar(inputDateTime); - String toStr = calendar.toString(); - Assert.assertTrue(toStr.indexOf("E") == -1, "String value cannot contain exponent"); - } catch (DatatypeConfigurationException dce) { - dce.printStackTrace(); - Assert.fail("Failed to create instance of DatatypeFactory " + dce.getMessage()); - } + String inputDateTime = "2006-10-23T22:15:01.000000135+08:00"; + XMLGregorianCalendar calendar = factory.newXMLGregorianCalendar(inputDateTime); + String toStr = calendar.toString(); + assertEquals(-1, toStr.indexOf("E"), "String value cannot contain exponent"); } } diff --git a/test/jaxp/javax/xml/jaxp/unittest/sax/Attributes2ImplTest.java b/test/jaxp/javax/xml/jaxp/unittest/sax/Attributes2ImplTest.java index 8de2d8b1b22..71cbcb6a838 100644 --- a/test/jaxp/javax/xml/jaxp/unittest/sax/Attributes2ImplTest.java +++ b/test/jaxp/javax/xml/jaxp/unittest/sax/Attributes2ImplTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * 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,14 +23,18 @@ package sax; -import org.testng.Assert; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import org.xml.sax.ext.Attributes2Impl; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + /* * @test * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest - * @run testng/othervm sax.Attributes2ImplTest + * @run junit/othervm sax.Attributes2ImplTest * @summary Test Attributes2Impl. */ public class Attributes2ImplTest { @@ -43,42 +47,25 @@ public class Attributes2ImplTest { impl.addAttribute("http://www.cars.com/xml", "attr2", "Qname2", "type", "value"); impl.addAttribute("http://www.cars.com/xml", "attr3", "Qname3", "type", "value"); - Assert.assertTrue(impl.isDeclared(0)); + assertTrue(impl.isDeclared(0)); impl.setDeclared(0, false); - Assert.assertFalse(impl.isDeclared(0)); + assertFalse(impl.isDeclared(0)); - Assert.assertTrue(impl.isDeclared("Qname2")); + assertTrue(impl.isDeclared("Qname2")); impl.setDeclared(1, false); - Assert.assertFalse(impl.isDeclared("Qname2")); + assertFalse(impl.isDeclared("Qname2")); - Assert.assertTrue(impl.isDeclared("http://www.cars.com/xml", "attr3")); + assertTrue(impl.isDeclared("http://www.cars.com/xml", "attr3")); impl.setDeclared(2, false); - Assert.assertFalse(impl.isDeclared(2)); + assertFalse(impl.isDeclared(2)); - try { - impl.isDeclared(3); - } catch (ArrayIndexOutOfBoundsException e) { - System.out.println("Expected ArrayIndexOutOfBoundsException"); - } + assertThrows(ArrayIndexOutOfBoundsException.class, () -> impl.isDeclared(3)); - try { - impl.isDeclared("wrongQname"); - } catch (IllegalArgumentException e) { - System.out.println("Expected IllegalArgumentException"); - } - - try { - impl.isDeclared("http://www.cars.com/xml", "attr4"); - } catch (IllegalArgumentException e) { - System.out.println("Expected IllegalArgumentException"); - } + assertThrows(IllegalArgumentException.class, () -> impl.isDeclared("wrongQname")); + assertThrows(IllegalArgumentException.class, () -> impl.isDeclared("http://www.cars.com/xml", "attr4")); impl.removeAttribute(2); - try { - impl.isDeclared(2); - } catch (ArrayIndexOutOfBoundsException e) { - System.out.println("Expected ArrayIndexOutOfBoundsException on index=2 after removing"); - } + assertThrows(ArrayIndexOutOfBoundsException.class, () -> impl.isDeclared(2)); } @Test @@ -89,42 +76,25 @@ public class Attributes2ImplTest { impl.addAttribute("http://www.cars.com/xml", "attr2", "Qname2", "type", "value"); impl.addAttribute("http://www.cars.com/xml", "attr3", "Qname3", "type", "value"); - Assert.assertTrue(impl.isSpecified(0)); + assertTrue(impl.isSpecified(0)); impl.setSpecified(0, false); - Assert.assertFalse(impl.isSpecified(0)); + assertFalse(impl.isSpecified(0)); - Assert.assertTrue(impl.isSpecified("Qname2")); + assertTrue(impl.isSpecified("Qname2")); impl.setSpecified(1, false); - Assert.assertFalse(impl.isSpecified("Qname2")); + assertFalse(impl.isSpecified("Qname2")); - Assert.assertTrue(impl.isSpecified("http://www.cars.com/xml", "attr3")); + assertTrue(impl.isSpecified("http://www.cars.com/xml", "attr3")); impl.setSpecified(2, false); - Assert.assertFalse(impl.isSpecified(2)); + assertFalse(impl.isSpecified(2)); - try { - impl.isSpecified(3); - } catch (ArrayIndexOutOfBoundsException e) { - System.out.println("Expected ArrayIndexOutOfBoundsException"); - } + assertThrows(ArrayIndexOutOfBoundsException.class, () -> impl.isSpecified(3)); - try { - impl.isSpecified("wrongQname"); - } catch (IllegalArgumentException e) { - System.out.println("Expected IllegalArgumentException"); - } - - try { - impl.isSpecified("http://www.cars.com/xml", "attr4"); - } catch (IllegalArgumentException e) { - System.out.println("Expected IllegalArgumentException"); - } + assertThrows(IllegalArgumentException.class, () -> impl.isSpecified("wrongQname")); + assertThrows(IllegalArgumentException.class, () -> impl.isSpecified("http://www.cars.com/xml", "attr4")); impl.removeAttribute(2); - try { - impl.isSpecified(2); - } catch (ArrayIndexOutOfBoundsException e) { - System.out.println("Expected ArrayIndexOutOfBoundsException on index=2 after removing"); - } + assertThrows(ArrayIndexOutOfBoundsException.class, () -> impl.isSpecified(2)); } @Test @@ -140,13 +110,13 @@ public class Attributes2ImplTest { Attributes2Impl impl3 = new Attributes2Impl(); impl3.setAttributes(impl1); - Assert.assertTrue(impl1.getQName(0).equals(impl2.getQName(0))); - Assert.assertTrue(impl1.getQName(0).equals(impl3.getQName(0))); + assertEquals(impl1.getQName(0), impl2.getQName(0)); + assertEquals(impl1.getQName(0), impl3.getQName(0)); - Assert.assertTrue(impl1.getQName(1).equals(impl2.getQName(1))); - Assert.assertTrue(impl1.getQName(1).equals(impl3.getQName(1))); + assertEquals(impl1.getQName(1), impl2.getQName(1)); + assertEquals(impl1.getQName(1), impl3.getQName(1)); - Assert.assertTrue(impl1.getQName(2).equals(impl2.getQName(2))); - Assert.assertTrue(impl1.getQName(2).equals(impl3.getQName(2))); + assertEquals(impl1.getQName(2), impl2.getQName(2)); + assertEquals(impl1.getQName(2), impl3.getQName(2)); } } diff --git a/test/jaxp/javax/xml/jaxp/unittest/sax/Bug6889654Test.java b/test/jaxp/javax/xml/jaxp/unittest/sax/Bug6889654Test.java index 89f0ceebe61..62f16021af2 100644 --- a/test/jaxp/javax/xml/jaxp/unittest/sax/Bug6889654Test.java +++ b/test/jaxp/javax/xml/jaxp/unittest/sax/Bug6889654Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * 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,64 +23,26 @@ package sax; -import java.io.IOException; -import java.io.StringReader; - -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.parsers.SAXParserFactory; - -import org.testng.Assert; -import org.testng.annotations.Test; -import org.xml.sax.InputSource; +import org.junit.jupiter.api.Test; import org.xml.sax.SAXException; -import org.xml.sax.helpers.DefaultHandler; + +import static org.junit.jupiter.api.Assertions.assertTrue; /* * @test * @bug 6889654 * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest - * @run testng/othervm sax.Bug6889654Test + * @run junit/othervm sax.Bug6889654Test * @summary Test SAXException includes whole information. */ public class Bug6889654Test { - - final String MSG = "Failed to parse XML"; - @Test public void testException() { - try { - parse(); - } catch (SAXException e) { - // e.printStackTrace(); - String msg = e.toString(); - if (msg.indexOf("systemId") == -1) { - Assert.fail("CR6889654 -- details should be returned."); - } - if (msg.indexOf(MSG) == -1) { - Assert.fail("CR6889649 -- additional error message not returned."); - } - System.out.println("error message:\n" + msg); - } + RuntimeException cause = new RuntimeException(""); + // The toString() of a SAXException includes the message of its cause. + SAXException wrapped = new SAXException("", cause); + + assertTrue(wrapped.toString().contains("")); + assertTrue(wrapped.toString().contains("")); } - - void parse() throws SAXException { - String xml = "\n\u0000"; - - try { - InputSource is = new InputSource(new StringReader(xml)); - is.setSystemId("file:///path/to/some.xml"); - // notice that exception thrown here doesn't include the line number - // information when reported by JVM -- CR6889654 - SAXParserFactory.newInstance().newSAXParser().parse(is, new DefaultHandler()); - } catch (SAXException e) { - // notice that this message isn't getting displayed -- CR6889649 - throw new SAXException(MSG, e); - } catch (ParserConfigurationException pce) { - - } catch (IOException ioe) { - - } - - } - } diff --git a/test/jaxp/javax/xml/jaxp/unittest/sax/Bug6925410Test.java b/test/jaxp/javax/xml/jaxp/unittest/sax/Bug6925410Test.java index d0a41dc0cf1..4f6a88874d9 100644 --- a/test/jaxp/javax/xml/jaxp/unittest/sax/Bug6925410Test.java +++ b/test/jaxp/javax/xml/jaxp/unittest/sax/Bug6925410Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * 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,37 +23,30 @@ package sax; -import javax.xml.datatype.DatatypeConfigurationException; - -import org.testng.annotations.Test; -import org.testng.Assert; +import org.junit.jupiter.api.Test; +import org.xml.sax.SAXException; import org.xml.sax.helpers.XMLReaderFactory; +import javax.xml.datatype.DatatypeConfigurationException; + /* * @test * @bug 6925410 * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest - * @run testng/othervm sax.Bug6925410Test + * @run junit/othervm sax.Bug6925410Test * @summary Test XMLReaderFactory can createXMLReader repeatedly. */ public class Bug6925410Test { @Test - public void test() throws DatatypeConfigurationException { - try { - int times = 100; - long start = System.currentTimeMillis(); - for (int i = 0; i < times; i++) { - XMLReaderFactory.createXMLReader(); - } - long end = System.currentTimeMillis(); - double speed = ((end - start)); - System.out.println(speed + "ms"); - } catch (Throwable e) { - e.printStackTrace(); - Assert.fail(e.toString()); + public void test() throws DatatypeConfigurationException, SAXException { + int times = 100; + long start = System.currentTimeMillis(); + for (int i = 0; i < times; i++) { + XMLReaderFactory.createXMLReader(); } - + long end = System.currentTimeMillis(); + double speed = ((end - start)); + System.out.println(speed + "ms"); } - } diff --git a/test/jaxp/javax/xml/jaxp/unittest/sax/Bug6949607Test.java b/test/jaxp/javax/xml/jaxp/unittest/sax/Bug6949607Test.java index 4aeb8ed603d..e1372e6fdb6 100644 --- a/test/jaxp/javax/xml/jaxp/unittest/sax/Bug6949607Test.java +++ b/test/jaxp/javax/xml/jaxp/unittest/sax/Bug6949607Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * 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,57 +23,52 @@ package sax; -import java.io.ByteArrayInputStream; - -import javax.xml.parsers.SAXParser; -import javax.xml.parsers.SAXParserFactory; - -import org.testng.Assert; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; +import java.io.ByteArrayInputStream; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + /* * @test * @bug 6949607 * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest - * @run testng/othervm sax.Bug6949607Test + * @run junit/othervm sax.Bug6949607Test * @summary Test Attributes.getValue returns null when parameter uri is empty. */ public class Bug6949607Test { - - final String MSG = "Failed to parse XML"; - String textXML = ""; + private static final String TEXT_XML = + ""; @Test - public void testException() { - try { - SAXParserFactory factory = SAXParserFactory.newInstance(); - factory.setNamespaceAware(true); - factory.setValidating(true); - SAXParser saxParser = factory.newSAXParser(); + public void testException() throws Exception { + SAXParserFactory factory = SAXParserFactory.newInstance(); + factory.setNamespaceAware(true); + factory.setValidating(true); + SAXParser saxParser = factory.newSAXParser(); - saxParser.parse(new ByteArrayInputStream(textXML.getBytes()), new TestFilter()); - - } catch (Throwable t) { - t.printStackTrace(); - } + TestFilter filter = new TestFilter(); + saxParser.parse(new ByteArrayInputStream(TEXT_XML.getBytes()), filter); + assertTrue(filter.wasTested); } - class TestFilter extends DefaultHandler { + static class TestFilter extends DefaultHandler { + boolean wasTested = false; + @Override public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException { super.startElement(uri, localName, qName, atts); - String attr_WithNs = atts.getValue("something", "attr"); - String attr_NoNs = atts.getValue("", "attr"); - - System.out.println("withNs: " + attr_WithNs); - System.out.println("NoNs: " + attr_NoNs); - - Assert.assertTrue(attr_NoNs == null, "Should return null when uri is empty."); - + assertEquals("attrValue", atts.getValue("something", "attr")); + assertNull(atts.getValue("", "attr"), "Should return null when uri is empty."); + wasTested = true; } } diff --git a/test/jaxp/javax/xml/jaxp/unittest/sax/Bug6992561Test.java b/test/jaxp/javax/xml/jaxp/unittest/sax/Bug6992561Test.java index 58bdee54aca..37fe7f9976a 100644 --- a/test/jaxp/javax/xml/jaxp/unittest/sax/Bug6992561Test.java +++ b/test/jaxp/javax/xml/jaxp/unittest/sax/Bug6992561Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * 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,63 +23,49 @@ package sax; -import java.io.ByteArrayInputStream; -import java.io.IOException; - -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.parsers.SAXParser; -import javax.xml.parsers.SAXParserFactory; - -import org.testng.Assert; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import org.xml.sax.ContentHandler; import org.xml.sax.InputSource; import org.xml.sax.Locator; -import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import org.xml.sax.helpers.DefaultHandler; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; +import java.io.ByteArrayInputStream; + +import static org.junit.jupiter.api.Assertions.assertFalse; + /* * @test * @bug 6992561 * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest - * @run testng/othervm sax.Bug6992561Test + * @run junit/othervm sax.Bug6992561Test * @summary Test encoding of SystemId in Locator. */ public class Bug6992561Test { @Test - public void test() { + public void test() throws Exception { ContentHandler handler = new DefaultHandler() { public void setDocumentLocator(Locator locator) { String sysId = locator.getSystemId(); System.out.println(locator.getSystemId()); - if (sysId.indexOf("%7") > 0) { - Assert.fail("the original system id should be left as is and not encoded."); - } + assertFalse(sysId.contains("%7"), "the original system id should be left as is and not encoded."); } }; SAXParserFactory spf = SAXParserFactory.newInstance(); SAXParser parser; - try { - parser = spf.newSAXParser(); + parser = spf.newSAXParser(); - XMLReader reader = parser.getXMLReader(); - reader.setContentHandler(handler); - String xml = "abc"; - ByteArrayInputStream bis = new ByteArrayInputStream(xml.getBytes()); - InputSource is = new InputSource("file:/home2/ramapulavarthi/w/bugs/jaxws861/foo~bla/test/src/wsdl/HelloTypes.xsd"); - is.setByteStream(bis); - reader.parse(is); - - } catch (ParserConfigurationException ex) { - Assert.fail(ex.toString()); - } catch (SAXException ex) { - Assert.fail(ex.toString()); - } catch (IOException ex) { - Assert.fail(ex.toString()); - } + XMLReader reader = parser.getXMLReader(); + reader.setContentHandler(handler); + String xml = "abc"; + ByteArrayInputStream bis = new ByteArrayInputStream(xml.getBytes()); + InputSource is = new InputSource("file:/home2/ramapulavarthi/w/bugs/jaxws861/foo~bla/test/src/wsdl/HelloTypes.xsd"); + is.setByteStream(bis); + reader.parse(is); } } diff --git a/test/jaxp/javax/xml/jaxp/unittest/sax/Bug7057778.xml b/test/jaxp/javax/xml/jaxp/unittest/sax/Bug7057778.xml deleted file mode 100644 index b28b04f6431..00000000000 --- a/test/jaxp/javax/xml/jaxp/unittest/sax/Bug7057778.xml +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/test/jaxp/javax/xml/jaxp/unittest/sax/Bug7057778Test.java b/test/jaxp/javax/xml/jaxp/unittest/sax/Bug7057778Test.java index c2d377f7d7b..9c2e772c83f 100644 --- a/test/jaxp/javax/xml/jaxp/unittest/sax/Bug7057778Test.java +++ b/test/jaxp/javax/xml/jaxp/unittest/sax/Bug7057778Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * 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,171 +23,43 @@ package sax; -import static jaxp.library.JAXPTestUtilities.USER_DIR; -import static jaxp.library.JAXPTestUtilities.getSystemProperty; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.UnsupportedEncodingException; -import java.io.Writer; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.parsers.SAXParser; -import javax.xml.parsers.SAXParserFactory; -import org.testng.Assert; -import org.testng.annotations.Test; -import org.xml.sax.Attributes; -import org.xml.sax.ErrorHandler; -import org.xml.sax.SAXException; +import org.junit.jupiter.api.Test; import org.xml.sax.SAXParseException; import org.xml.sax.XMLReader; import org.xml.sax.ext.DefaultHandler2; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + /* * @test * @bug 7057778 * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest - * @run testng/othervm sax.Bug7057778Test + * @run junit/othervm sax.Bug7057778Test * @summary Test the file can be deleted after SAXParser.parse(File, DefaultHandler). */ public class Bug7057778Test { - - static final String xml = "Bug7057778.xml"; - static final String xml1 = "Bug7057778_1.xml"; - @Test - public void testParse() { - File src = new File(getClass().getResource(xml).getFile()); - File dst = new File(USER_DIR + xml1); - try { - copyFile(src, dst); - SAXParserFactory spf = SAXParserFactory.newInstance(); - SAXParser parser = spf.newSAXParser(); - XMLReader xmlReader = parser.getXMLReader(); - xmlReader.setProperty("http://xml.org/sax/properties/lexical-handler", new MyHandler1()); - parser.parse(dst, new MyHandler1()); - } catch (SAXException ex) { - ex.printStackTrace(); - } catch (IOException ex) { - // shouldn't happen - } catch (ParserConfigurationException ex) { - // shouldn't happen - } catch (Exception ex) { - } - if (dst != null) { - if (dst.delete()) { - System.out.println("Delete: OK"); - } else { - System.out.println("Delete: NG"); - Assert.fail("Error: denied to delete the file"); - } - } + public void testParse() throws Exception { + Path badXml = Path.of("bad.xml"); + Files.writeString(badXml, "\n\n\n\n"); - } - - private void copyFile(File src, File dst) throws FileNotFoundException, IOException { - InputStream in = new FileInputStream(src); - OutputStream out = new FileOutputStream(dst); - // Transfer bytes - byte[] buf = new byte[1024]; - int len; - while ((len = in.read(buf)) > 0) { - out.write(buf, 0, len); - } - in.close(); - out.close(); - } - - public class MyHandler1 extends DefaultHandler2 implements ErrorHandler { - private Writer out; - - StringBuffer textBuffer; - private String indentString = " "; // Amount to indent - private int indentLevel = 0; - - public MyHandler1() { - try { - out = new OutputStreamWriter(System.out, "UTF8"); - } catch (UnsupportedEncodingException ex) { - ex.printStackTrace(); - } - } - - public void startDocument() throws SAXException { - } - - public void endDocument() throws SAXException { - } - - public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { - try { - System.out.println("uri: " + uri); - System.out.println("localName: " + localName); - System.out.println("qName: " + qName); - } catch (Exception e) { - throw new SAXException(e); - } - - } - - public void endElement(String uri, String localName, String qName) throws SAXException { - } - - public void characters(char ch[], int start, int length) throws SAXException { - } - - public void comment(char[] ch, int start, int length) { - String text = new String(ch, start, length); - // System.out.println(text); - try { - nl(); - emit("COMMENT: " + text); - } catch (Exception e) { - e.printStackTrace(); - } - } - - public void error(SAXParseException exception) { - exception.printStackTrace(); - } - - public void fatalError(SAXParseException exception) { - exception.printStackTrace(); - } - - public void warning(SAXParseException exception) { - exception.printStackTrace(); - } - - // Wrap I/O exceptions in SAX exceptions, to - // suit handler signature requirements - private void emit(String s) throws SAXException { - try { - out.write(s); - out.flush(); - } catch (IOException e) { - throw new SAXException("I/O error", e); - } - } - - // Start a new line - // and indent the next line appropriately - private void nl() throws SAXException { - String lineEnd = getSystemProperty("line.separator"); - - try { - out.write(lineEnd); - - for (int i = 0; i < indentLevel; i++) - out.write(indentString); - } catch (IOException e) { - throw new SAXException("I/O error", e); - } - } + SAXParserFactory spf = SAXParserFactory.newInstance(); + SAXParser parser = spf.newSAXParser(); + XMLReader xmlReader = parser.getXMLReader(); + DefaultHandler2 noopHandler = new DefaultHandler2(); + xmlReader.setProperty("http://xml.org/sax/properties/lexical-handler", noopHandler); + // Test file is empty and fails parsing. + File dst = badXml.toFile(); + assertThrows(SAXParseException.class, () -> parser.parse(dst, noopHandler)); + // But parse failure should not keep the destination file open. + assertTrue(dst.delete(), "could not delete the file"); } } diff --git a/test/jaxp/javax/xml/jaxp/unittest/sax/DeclarationTest.java b/test/jaxp/javax/xml/jaxp/unittest/sax/DeclarationTest.java index f9d9b2a117e..19871b5ddf8 100644 --- a/test/jaxp/javax/xml/jaxp/unittest/sax/DeclarationTest.java +++ b/test/jaxp/javax/xml/jaxp/unittest/sax/DeclarationTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * 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,25 +23,25 @@ package sax; -import java.io.File; -import java.io.StringReader; -import javax.xml.parsers.SAXParser; -import javax.xml.parsers.SAXParserFactory; -import org.testng.Assert; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Listeners; -import org.testng.annotations.Test; -import org.xml.sax.ContentHandler; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import org.xml.sax.helpers.DefaultHandler; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; +import java.io.File; +import java.io.StringReader; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; /* * @test * @bug 8230814 - * @run testng sax.DeclarationTest + * @run junit sax.DeclarationTest * @summary Test SAX Parser's handling of XML Declarations. */ public class DeclarationTest { @@ -56,12 +56,8 @@ public class DeclarationTest { * * Fields: * XML string, expected version, encoding and standalone strings - * - * @return data array for the test - * @throws Exception */ - @DataProvider(name = "default") - public Object[][] forDefaultHandler() throws Exception { + public static Object[][] defaultHandlerData() throws Exception { return new Object[][] { { XML_NO_DECLARATION, null, null, null}, { XML_NO_STANDALONE, null, null, null}, @@ -75,12 +71,8 @@ public class DeclarationTest { * * Fields: * XML string, expected version, encoding and standalone strings - * - * @return data array for the test - * @throws Exception */ - @DataProvider(name = "sax-data") - public Object[][] xmlSAXData() throws Exception { + public static Object[][] xmlSAXData() throws Exception { return new Object[][] { { XML_NO_DECLARATION, null, null, null}, { XML_NO_STANDALONE, "1.0", "ISO-8859-1", null}, @@ -95,12 +87,8 @@ public class DeclarationTest { * * Fields: * Source files, expected version, encoding and standalone strings - * - * @return data array for the test - * @throws Exception */ - @DataProvider(name = "sax-data-files") - public Object[][] xmlSAXDataFiles() throws Exception { + public static Object[][] xmlSAXDataFiles() throws Exception { return new Object[][] { //the source contains no declaration { new File(SRC_DIR + "/../transform/SourceTest.xml"), null, null, null}, @@ -129,7 +117,8 @@ public class DeclarationTest { * @param standalone expected standalone string * @throws Exception if the test fails */ - @Test(dataProvider = "default") + @ParameterizedTest + @MethodSource("defaultHandlerData") public void testDefault(String xml, String version, String encoding, String standalone) throws Exception { DefaultImpl h = new DefaultImpl(); @@ -145,7 +134,8 @@ public class DeclarationTest { * @param standalone expected standalone string * @throws Exception if the test fails */ - @Test(dataProvider = "sax-data") + @ParameterizedTest + @MethodSource("xmlSAXData") public void test(String xml, String version, String encoding, String standalone) throws Exception { NewMethodImpl h = new NewMethodImpl(); @@ -161,15 +151,16 @@ public class DeclarationTest { * @param standalone expected standalone string * @throws Exception if the test fails */ - @Test(dataProvider = "sax-data-files") + @ParameterizedTest + @MethodSource("xmlSAXDataFiles") public void testFiles(File xml, String version, String encoding, String standalone) throws Exception { SAXParser parser = SAXParserFactory.newDefaultInstance().newSAXParser(); NewMethodImpl h = new NewMethodImpl(); parser.parse(xml, h); - Assert.assertEquals(h.version, version); - Assert.assertEquals(h.encoding, encoding); - Assert.assertEquals(h.standalone, standalone); + assertEquals(version, h.version); + assertEquals(encoding, h.encoding); + assertEquals(standalone, h.standalone); } /** @@ -187,12 +178,12 @@ public class DeclarationTest { XMLReader r = SAXParserFactory.newDefaultInstance().newSAXParser().getXMLReader(); r.setContentHandler(h); r.parse(new InputSource(new StringReader(xml))); - Assert.assertEquals(h.version, version); - Assert.assertEquals(h.encoding, encoding); - Assert.assertEquals(h.standalone, standalone); + assertEquals(version, h.version); + assertEquals(encoding, h.encoding); + assertEquals(standalone, h.standalone); } - class DefaultImpl extends DefaultHandler{ + static class DefaultImpl extends DefaultHandler { boolean startDocumentInvoked = false; String version, encoding, standalone; @@ -202,7 +193,7 @@ public class DeclarationTest { } } - class NewMethodImpl extends DefaultImpl { + static class NewMethodImpl extends DefaultImpl { public void startDocument() throws SAXException { super.startDocument(); @@ -213,7 +204,7 @@ public class DeclarationTest { throws SAXException { super.declaration(version, encoding, standalone); - Assert.assertTrue(startDocumentInvoked, "declaration follows startDocument"); + assertTrue(startDocumentInvoked, "declaration follows startDocument"); this.version = version; this.encoding = encoding; this.standalone = standalone; diff --git a/test/jaxp/javax/xml/jaxp/unittest/sax/DefaultHandler2Test.java b/test/jaxp/javax/xml/jaxp/unittest/sax/DefaultHandler2Test.java index 85e447783ca..4f50b23e8d6 100644 --- a/test/jaxp/javax/xml/jaxp/unittest/sax/DefaultHandler2Test.java +++ b/test/jaxp/javax/xml/jaxp/unittest/sax/DefaultHandler2Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * 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,7 @@ package sax; -import java.io.IOException; - -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.parsers.SAXParser; -import javax.xml.parsers.SAXParserFactory; - -import org.testng.Assert; -import org.testng.AssertJUnit; -import org.testng.annotations.Test; -import org.xml.sax.SAXException; +import org.junit.jupiter.api.Test; import org.xml.sax.SAXNotRecognizedException; import org.xml.sax.XMLReader; import org.xml.sax.ext.DefaultHandler2; @@ -41,210 +32,135 @@ import org.xml.sax.helpers.ParserAdapter; import org.xml.sax.helpers.XMLFilterImpl; import org.xml.sax.helpers.XMLReaderFactory; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; + +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertThrows; + /* * @test * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest - * @run testng/othervm sax.DefaultHandler2Test + * @run junit/othervm sax.DefaultHandler2Test * @summary Test DefaultHandler2. */ public class DefaultHandler2Test { @Test - public void testParse01() { - System.out.println("===in testParse01==="); - try { - DefaultHandler handler = new MyDefaultHandler2(); - SAXParserFactory saxFac = SAXParserFactory.newInstance(); - System.out.println(saxFac.getFeature("http://xml.org/sax/features/use-locator2")); + public void testParse01() throws Exception { + DefaultHandler handler = new MyDefaultHandler2(); + SAXParserFactory saxFac = SAXParserFactory.newInstance(); + System.out.println(saxFac.getFeature("http://xml.org/sax/features/use-locator2")); - // set use-entity-resolver2 as FALSE to use EntityResolver firstly. - saxFac.setFeature("http://xml.org/sax/features/use-entity-resolver2", false); - saxFac.setValidating(true); + // set use-entity-resolver2 as FALSE to use EntityResolver firstly. + saxFac.setFeature("http://xml.org/sax/features/use-entity-resolver2", false); + saxFac.setValidating(true); - SAXParser parser = saxFac.newSAXParser(); - parser.setProperty("http://xml.org/sax/properties/lexical-handler", handler); - parser.setProperty("http://xml.org/sax/properties/declaration-handler", handler); + SAXParser parser = saxFac.newSAXParser(); + parser.setProperty("http://xml.org/sax/properties/lexical-handler", handler); + parser.setProperty("http://xml.org/sax/properties/declaration-handler", handler); - parser.parse(this.getClass().getResource("toys.xml").getFile(), handler); - } catch (ParserConfigurationException e) { - e.printStackTrace(); - Assert.fail("ParserConfigurationException in testParse01()"); - } catch (SAXException e) { - e.printStackTrace(); - Assert.fail("SAXException in testParse01()"); - } catch (IOException e) { - e.printStackTrace(); - Assert.fail("IOException in testParse01()"); - } + parser.parse(this.getClass().getResource("toys.xml").getFile(), handler); } @Test - public void testParse02() { - System.out.println("===in testParse02==="); - try { - DefaultHandler handler = new MyDefaultHandler2(); - SAXParserFactory saxFac = SAXParserFactory.newInstance(); - System.out.println(saxFac.getFeature("http://xml.org/sax/features/use-locator2")); + public void testParse02() throws Exception { + DefaultHandler handler = new MyDefaultHandler2(); + SAXParserFactory saxFac = SAXParserFactory.newInstance(); + System.out.println(saxFac.getFeature("http://xml.org/sax/features/use-locator2")); - // Enable namespace parsing - System.out.println(saxFac.getFeature("http://xml.org/sax/features/namespaces")); - saxFac.setNamespaceAware(true); + // Enable namespace parsing + System.out.println(saxFac.getFeature("http://xml.org/sax/features/namespaces")); + saxFac.setNamespaceAware(true); - saxFac.setValidating(true); - SAXParser parser = saxFac.newSAXParser(); - parser.setProperty("http://xml.org/sax/properties/lexical-handler", handler); - parser.setProperty("http://xml.org/sax/properties/declaration-handler", handler); + saxFac.setValidating(true); + SAXParser parser = saxFac.newSAXParser(); + parser.setProperty("http://xml.org/sax/properties/lexical-handler", handler); + parser.setProperty("http://xml.org/sax/properties/declaration-handler", handler); - parser.parse(this.getClass().getResource("toys.xml").getFile(), handler); - } catch (ParserConfigurationException e) { - e.printStackTrace(); - Assert.fail("ParserConfigurationException in testParse02()"); - } catch (SAXException e) { - e.printStackTrace(); - Assert.fail("SAXException in testParse02()"); - } catch (IOException e) { - e.printStackTrace(); - Assert.fail("IOException in testParse02()"); - } + parser.parse(this.getClass().getResource("toys.xml").getFile(), handler); } @Test - public void testParse03() { - System.out.println("===in testParse03==="); - try { - DefaultHandler handler = new MyDefaultHandler2(); + public void testParse03() throws Exception { + DefaultHandler handler = new MyDefaultHandler2(); - XMLReader xmlReader = XMLReaderFactory.createXMLReader(); - xmlReader.setProperty("http://xml.org/sax/properties/declaration-handler", handler); - System.out.println("XMLReader : " + xmlReader.getProperty("http://xml.org/sax/properties/declaration-handler")); + XMLReader xmlReader = XMLReaderFactory.createXMLReader(); + xmlReader.setProperty("http://xml.org/sax/properties/declaration-handler", handler); + System.out.println("XMLReader : " + xmlReader.getProperty("http://xml.org/sax/properties/declaration-handler")); - SAXParserFactory saxFac = SAXParserFactory.newInstance(); - SAXParser parser = saxFac.newSAXParser(); - parser.setProperty("http://xml.org/sax/properties/declaration-handler", handler); - System.out.println("SAXParser : " + parser.getProperty("http://xml.org/sax/properties/declaration-handler")); - - // From https://docs.oracle.com/javase/7/docs/api, - // ParserAdapter.setProperty() and ParserAdapter.getProperty() does - // not support any property currently. - try { - ParserAdapter adapter = new ParserAdapter(parser.getParser()); - System.out.println("ParserAdapter : " + adapter.getProperty("http://xml.org/sax/properties/declaration-handler")); - } catch (SAXNotRecognizedException e) { - System.out.println("Expected SAXNotRecognizedException since ParserAdapter.getProperty() does not support any property currently"); - } - try { - ParserAdapter adapter = new ParserAdapter(parser.getParser()); - adapter.setProperty("http://xml.org/sax/properties/declaration-handler", handler); - } catch (SAXNotRecognizedException e) { - System.out.println("Expected SAXNotRecognizedException since ParserAdapter.setProperty() does not support any property currently"); - } - } catch (SAXException e) { - e.printStackTrace(); - Assert.fail("SAXException in testParse03()"); - } catch (ParserConfigurationException e) { - e.printStackTrace(); - Assert.fail("ParserConfigurationException in testParse03()"); - } + SAXParserFactory saxFac = SAXParserFactory.newInstance(); + SAXParser parser = saxFac.newSAXParser(); + parser.setProperty("http://xml.org/sax/properties/declaration-handler", handler); + System.out.println("SAXParser : " + parser.getProperty("http://xml.org/sax/properties/declaration-handler")); + // From https://docs.oracle.com/javase/7/docs/api, + // ParserAdapter.setProperty() and ParserAdapter.getProperty() does + // not support any property currently. + ParserAdapter adapter = new ParserAdapter(parser.getParser()); + assertThrows(SAXNotRecognizedException.class, () -> adapter.getProperty("http://xml.org/sax/properties/declaration-handler")); + assertThrows(SAXNotRecognizedException.class, () -> adapter.setProperty("http://xml.org/sax/properties/declaration-handler", handler)); } @Test - public void testParse04() { - System.out.println("===in testParse04==="); - try { - DefaultHandler handler = new MyDefaultHandler2(); - XMLReader xmlReader = XMLReaderFactory.createXMLReader(); - System.out.println(xmlReader.getFeature("http://xml.org/sax/features/namespaces")); - xmlReader.setProperty("http://xml.org/sax/properties/declaration-handler", handler); - xmlReader.setProperty("http://xml.org/sax/properties/lexical-handler", handler); - xmlReader.setContentHandler(handler); + public void testParse04() throws Exception { + DefaultHandler handler = new MyDefaultHandler2(); + XMLReader xmlReader = XMLReaderFactory.createXMLReader(); + System.out.println(xmlReader.getFeature("http://xml.org/sax/features/namespaces")); + xmlReader.setProperty("http://xml.org/sax/properties/declaration-handler", handler); + xmlReader.setProperty("http://xml.org/sax/properties/lexical-handler", handler); + xmlReader.setContentHandler(handler); - xmlReader.parse(this.getClass().getResource("toys.xml").getFile()); - - } catch (SAXException e) { - e.printStackTrace(); - Assert.fail("SAXException in testParse04()"); - } catch (IOException e) { - e.printStackTrace(); - Assert.fail("IOException in testParse04()"); - } + xmlReader.parse(this.getClass().getResource("toys.xml").getFile()); } @Test - public void testParse05() { - System.out.println("===in testParse05==="); - try { - DefaultHandler handler = new MyDefaultHandler2(); - XMLReader xmlReader = XMLReaderFactory.createXMLReader(); - XMLFilterImpl filterImpl = new XMLFilterImpl(xmlReader); - System.out.println(xmlReader.getFeature("http://xml.org/sax/features/namespaces")); - filterImpl.setProperty("http://xml.org/sax/properties/declaration-handler", handler); - filterImpl.setProperty("http://xml.org/sax/properties/lexical-handler", handler); - filterImpl.setContentHandler(handler); + public void testParse05() throws Exception { + DefaultHandler handler = new MyDefaultHandler2(); + XMLReader xmlReader = XMLReaderFactory.createXMLReader(); + XMLFilterImpl filterImpl = new XMLFilterImpl(xmlReader); + System.out.println(xmlReader.getFeature("http://xml.org/sax/features/namespaces")); + filterImpl.setProperty("http://xml.org/sax/properties/declaration-handler", handler); + filterImpl.setProperty("http://xml.org/sax/properties/lexical-handler", handler); + filterImpl.setContentHandler(handler); - filterImpl.parse(this.getClass().getResource("toys.xml").getFile()); - - } catch (SAXException e) { - e.printStackTrace(); - Assert.fail("SAXException in testParse05()"); - } catch (IOException e) { - e.printStackTrace(); - Assert.fail("IOException in testParse05()"); - } + filterImpl.parse(this.getClass().getResource("toys.xml").getFile()); } @Test - public void testParse06() { - System.out.println("===in testParse06==="); - try { - DefaultHandler handler = new MyDefaultHandler2(); - XMLReader xmlReader = XMLReaderFactory.createXMLReader(); - XMLFilterImpl filterImpl = new XMLFilterImpl(xmlReader); - System.out.println(xmlReader.getFeature("http://xml.org/sax/features/namespaces")); - filterImpl.setProperty("http://xml.org/sax/properties/declaration-handler", handler); - filterImpl.setProperty("http://xml.org/sax/properties/lexical-handler", handler); - filterImpl.setContentHandler(handler); + public void testParse06() throws Exception { + DefaultHandler handler = new MyDefaultHandler2(); + XMLReader xmlReader = XMLReaderFactory.createXMLReader(); + XMLFilterImpl filterImpl = new XMLFilterImpl(xmlReader); + System.out.println(xmlReader.getFeature("http://xml.org/sax/features/namespaces")); + filterImpl.setProperty("http://xml.org/sax/properties/declaration-handler", handler); + filterImpl.setProperty("http://xml.org/sax/properties/lexical-handler", handler); + filterImpl.setContentHandler(handler); - AssertJUnit.assertTrue(filterImpl.getProperty("http://xml.org/sax/properties/declaration-handler") instanceof DefaultHandler2); + assertInstanceOf(DefaultHandler2.class, filterImpl.getProperty("http://xml.org/sax/properties/declaration-handler")); - // filterImpl.setFeature("http://xml.org/sax/features/external-general-entities", - // false) ; - // filterImpl.setFeature("http://xml.org/sax/features/external-parameter-entities", - // false) ; - filterImpl.skippedEntity("name2"); + // filterImpl.setFeature("http://xml.org/sax/features/external-general-entities", + // false) ; + // filterImpl.setFeature("http://xml.org/sax/features/external-parameter-entities", + // false) ; + filterImpl.skippedEntity("name2"); - filterImpl.parse(this.getClass().getResource("toys.xml").getFile()); - } catch (SAXException e) { - e.printStackTrace(); - Assert.fail("SAXException in testParse06()"); - } catch (IOException e) { - e.printStackTrace(); - Assert.fail("IOException in testParse06()"); - } + filterImpl.parse(this.getClass().getResource("toys.xml").getFile()); } @Test - public void testParse07() { - System.out.println("===in testParse07==="); - try { - DefaultHandler handler = new MyDefaultHandler2(); - XMLReader xmlReader = XMLReaderFactory.createXMLReader(); - XMLFilterImpl filterImpl = new XMLFilterImpl(xmlReader); - System.out.println(xmlReader.getFeature("http://xml.org/sax/features/namespaces")); - filterImpl.setProperty("http://xml.org/sax/properties/declaration-handler", handler); - filterImpl.setProperty("http://xml.org/sax/properties/lexical-handler", handler); - filterImpl.setContentHandler(handler); - filterImpl.setErrorHandler(handler); - AssertJUnit.assertTrue(filterImpl.getProperty("http://xml.org/sax/properties/declaration-handler") instanceof DefaultHandler2); + public void testParse07() throws Exception { + DefaultHandler handler = new MyDefaultHandler2(); + XMLReader xmlReader = XMLReaderFactory.createXMLReader(); + XMLFilterImpl filterImpl = new XMLFilterImpl(xmlReader); + System.out.println(xmlReader.getFeature("http://xml.org/sax/features/namespaces")); + filterImpl.setProperty("http://xml.org/sax/properties/declaration-handler", handler); + filterImpl.setProperty("http://xml.org/sax/properties/lexical-handler", handler); + filterImpl.setContentHandler(handler); + filterImpl.setErrorHandler(handler); + assertInstanceOf(DefaultHandler2.class, filterImpl.getProperty("http://xml.org/sax/properties/declaration-handler")); - filterImpl.setFeature("http://apache.org/xml/features/continue-after-fatal-error", true); - filterImpl.parse(this.getClass().getResource("toys_error.xml").getFile()); - } catch (SAXException e) { - e.printStackTrace(); - Assert.fail("SAXException in testParse07()"); - } catch (IOException e) { - e.printStackTrace(); - Assert.fail("IOException in testParse07()"); - } + filterImpl.setFeature("http://apache.org/xml/features/continue-after-fatal-error", true); + filterImpl.parse(this.getClass().getResource("toys_error.xml").getFile()); } } diff --git a/test/jaxp/javax/xml/jaxp/unittest/sax/IssueTracker56Test.java b/test/jaxp/javax/xml/jaxp/unittest/sax/IssueTracker56Test.java index bbec3104208..6588d787bfe 100644 --- a/test/jaxp/javax/xml/jaxp/unittest/sax/IssueTracker56Test.java +++ b/test/jaxp/javax/xml/jaxp/unittest/sax/IssueTracker56Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * 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,78 +23,50 @@ package sax; -import java.io.IOException; -import java.io.StringReader; - -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.parsers.SAXParser; -import javax.xml.parsers.SAXParserFactory; - -import org.testng.Assert; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import org.xml.sax.Attributes; import org.xml.sax.ErrorHandler; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; +import java.io.StringReader; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + /* * @test * @bug 6809409 * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest - * @run testng/othervm sax.IssueTracker56Test + * @run junit/othervm sax.IssueTracker56Test * @summary Test SAXException has Cause. */ public class IssueTracker56Test { @Test - public void testException() { - try { - SAXParserFactory spf = SAXParserFactory.newInstance(); - SAXParser parser = spf.newSAXParser(); - String xmlToParse = "Issue 56: SAXException does not do the exception chaining properly"; - InputSource source = new InputSource(new StringReader(xmlToParse)); - parser.parse(source, new MyHandler()); - } catch (SAXException ex) { - System.out.println(ex.getCause()); - if (ex.getCause() == null) - Assert.fail("failed chaining exception properly."); - // ex.printStackTrace(); //will not print out root cause without the - // fix - } catch (IOException ex) { - // shouldn't happen - } catch (ParserConfigurationException ex) { - // shouldn't happen - } + public void testException() throws Exception { + SAXParserFactory spf = SAXParserFactory.newInstance(); + SAXParser parser = spf.newSAXParser(); + String xmlToParse = "Issue 56: SAXException does not do the exception chaining properly"; + InputSource source = new InputSource(new StringReader(xmlToParse)); + + SAXException ex = assertThrows(SAXException.class, () -> parser.parse(source, new MyHandler())); + assertNotNull(ex.getCause(), "failed chaining exception properly."); } @Test public void testWorkAround() throws Exception { - try { - SAXParserFactory spf = SAXParserFactory.newInstance(); - SAXParser parser = spf.newSAXParser(); - String xmlToParse = "Issue 56: SAXException does not do the exception chaining properly"; - InputSource source = new InputSource(new StringReader(xmlToParse)); - parser.parse(source, new MyHandler1()); - } catch (SAXException ex) { - System.out.println(ex.getCause()); - // ex.printStackTrace(); //will print out root cause - } catch (IOException ex) { - // shouldn't happen - } catch (ParserConfigurationException ex) { - // shouldn't happen - } - + SAXParserFactory spf = SAXParserFactory.newInstance(); + SAXParser parser = spf.newSAXParser(); + String xmlToParse = "Issue 56: SAXException does not do the exception chaining properly"; + InputSource source = new InputSource(new StringReader(xmlToParse)); + assertThrows(SAXException.class, () -> parser.parse(source, new MyHandler1())); } - public class MyHandler extends DefaultHandler implements ErrorHandler { - - public void startDocument() throws SAXException { - } - - public void endDocument() throws SAXException { - } - + public static class MyHandler extends DefaultHandler implements ErrorHandler { public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { try { System.out.println(uri); @@ -104,23 +76,9 @@ public class IssueTracker56Test { } } - - public void endElement(String uri, String localName, String qName) throws SAXException { - } - - public void characters(char ch[], int start, int length) throws SAXException { - } - } - public class MyHandler1 extends DefaultHandler implements ErrorHandler { - - public void startDocument() throws SAXException { - } - - public void endDocument() throws SAXException { - } - + public static class MyHandler1 extends DefaultHandler implements ErrorHandler { public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXExceptionExt { try { System.out.println(uri); @@ -130,12 +88,5 @@ public class IssueTracker56Test { } } - - public void endElement(String uri, String localName, String qName) throws SAXException { - } - - public void characters(char ch[], int start, int length) throws SAXException { - } - } } diff --git a/test/jaxp/javax/xml/jaxp/unittest/sax/NSSupportTest.java b/test/jaxp/javax/xml/jaxp/unittest/sax/NSSupportTest.java index 7630d96a023..d4b05a0c366 100644 --- a/test/jaxp/javax/xml/jaxp/unittest/sax/NSSupportTest.java +++ b/test/jaxp/javax/xml/jaxp/unittest/sax/NSSupportTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,17 +23,20 @@ package sax; +import org.junit.jupiter.api.Test; +import org.xml.sax.helpers.NamespaceSupport; + import java.util.Enumeration; -import org.testng.Assert; -import org.testng.AssertJUnit; -import org.testng.annotations.Test; -import org.xml.sax.helpers.NamespaceSupport; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; /* * @test * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest - * @run testng/othervm sax.NSSupportTest + * @run junit/othervm sax.NSSupportTest * @summary Test NamespaceSupport. */ public class NSSupportTest { @@ -48,14 +51,14 @@ public class NSSupportTest { String[] parts = new String[3]; nssupport.processName("dc:name1", parts, false); - Assert.assertTrue(parts[0].equals("http://www.purl.org/dc")); - Assert.assertTrue(parts[1].equals("name1")); - Assert.assertTrue(parts[2].equals("dc:name1")); + assertEquals("http://www.purl.org/dc", parts[0]); + assertEquals("name1", parts[1]); + assertEquals("dc:name1", parts[2]); nssupport.processName("name2", parts, false); - Assert.assertTrue(parts[0].equals("http://www.java.com")); - Assert.assertTrue(parts[1].equals("name2")); - Assert.assertTrue(parts[2].equals("name2")); + assertEquals("http://www.java.com", parts[0]); + assertEquals("name2", parts[1]); + assertEquals("name2", parts[2]); } @Test @@ -64,30 +67,30 @@ public class NSSupportTest { NamespaceSupport nssupport = new NamespaceSupport(); nssupport.pushContext(); - Assert.assertFalse(nssupport.isNamespaceDeclUris()); + assertFalse(nssupport.isNamespaceDeclUris()); nssupport.declarePrefix("xmlns", ""); nssupport.processName("xmlns:name", parts, true); - Assert.assertNull(parts[0]); - Assert.assertNull(parts[1]); - Assert.assertNull(parts[2]); + assertNull(parts[0]); + assertNull(parts[1]); + assertNull(parts[2]); nssupport.reset(); nssupport.setNamespaceDeclUris(true); nssupport.declarePrefix("xmlns", ""); nssupport.processName("xmlns:name", parts, true); - Assert.assertTrue(parts[0].equals(NamespaceSupport.NSDECL)); - Assert.assertTrue(parts[1].equals("name")); - Assert.assertTrue(parts[2].equals("xmlns:name")); + assertEquals(NamespaceSupport.NSDECL, parts[0]); + assertEquals("name", parts[1]); + assertEquals("xmlns:name", parts[2]); nssupport.reset(); nssupport.setNamespaceDeclUris(true); nssupport.declarePrefix("xml", ""); nssupport.processName("xml:name", parts, true); - Assert.assertTrue(parts[0].equals(NamespaceSupport.XMLNS)); - Assert.assertTrue(parts[1].equals("name")); - Assert.assertTrue(parts[2].equals("xml:name")); + assertEquals(NamespaceSupport.XMLNS, parts[0]); + assertEquals("name", parts[1]); + assertEquals("xml:name", parts[2]); } @@ -98,14 +101,14 @@ public class NSSupportTest { nssupport.pushContext(); nssupport.declarePrefix("dc", "http://www.purl.org/dc"); - Assert.assertEquals(nssupport.getPrefix("http://www.purl.org/dc"), "dc"); + assertEquals("dc", nssupport.getPrefix("http://www.purl.org/dc")); nssupport.popContext(); - Assert.assertNull(nssupport.getPrefix("http://www.purl.org/dc")); + assertNull(nssupport.getPrefix("http://www.purl.org/dc")); nssupport.processName("dc:name1", parts, false); - Assert.assertNull(parts[0]); - Assert.assertNull(parts[1]); - Assert.assertNull(parts[2]); + assertNull(parts[0]); + assertNull(parts[1]); + assertNull(parts[2]); } @Test @@ -124,9 +127,9 @@ public class NSSupportTest { nssupport.declarePrefix("dc2", "http://www.purl.org/dc2"); nssupport.declarePrefix("dcnew", "http://www.purl.org/dcnew"); - Enumeration enu1 = nssupport.getDeclaredPrefixes(); + Enumeration enu1 = nssupport.getDeclaredPrefixes(); while (enu1.hasMoreElements()) { - String str = (String) enu1.nextElement(); + String str = enu1.nextElement(); if (str.equals("dc")) { hasdc = true; } else if (str.equals("dc1")) { @@ -137,8 +140,8 @@ public class NSSupportTest { hasdcnew = true; } } - AssertJUnit.assertTrue(hasdcnew && hasdc1 && hasdc2); - AssertJUnit.assertFalse(hasdc); + assertTrue(hasdcnew && hasdc1 && hasdc2); + assertFalse(hasdc); } @Test @@ -157,9 +160,9 @@ public class NSSupportTest { nssupport.declarePrefix("dc2", "http://www.purl.org/dc2"); nssupport.declarePrefix("dcnew", "http://www.purl.org/dcnew"); - Enumeration enu1 = nssupport.getPrefixes(); + Enumeration enu1 = nssupport.getPrefixes(); while (enu1.hasMoreElements()) { - String str = (String) enu1.nextElement(); + String str = enu1.nextElement(); if (str.equals("dc")) { hasdc = true; } else if (str.equals("dc1")) { @@ -170,7 +173,7 @@ public class NSSupportTest { hasdcnew = true; } } - AssertJUnit.assertTrue(hasdcnew && hasdc1 && hasdc2 && hasdc); + assertTrue(hasdcnew && hasdc1 && hasdc2 && hasdc); } @Test @@ -189,9 +192,9 @@ public class NSSupportTest { nssupport.declarePrefix("dc2", "http://www.purl.org/dc2"); nssupport.declarePrefix("dcnew", "http://www.purl.org/dcnew"); - Enumeration enu1 = nssupport.getPrefixes("http://www.purl.org/dc"); + Enumeration enu1 = nssupport.getPrefixes("http://www.purl.org/dc"); while (enu1.hasMoreElements()) { - String str = (String) enu1.nextElement(); + String str = enu1.nextElement(); if (str.equals("dc")) { hasdc = true; } else if (str.equals("dc1")) { @@ -202,9 +205,9 @@ public class NSSupportTest { hasdcnew = true; } } - AssertJUnit.assertTrue(hasdc1 && hasdc); - AssertJUnit.assertFalse(hasdc2); - AssertJUnit.assertFalse(hasdcnew); + assertTrue(hasdc1 && hasdc); + assertFalse(hasdc2); + assertFalse(hasdcnew); } @Test @@ -219,13 +222,13 @@ public class NSSupportTest { nssupport.declarePrefix("dc2", "http://www.purl.org/dc2"); nssupport.declarePrefix("dcnew", "http://www.purl.org/dcnew"); - AssertJUnit.assertTrue(nssupport.getURI("dc").equals("http://www.purl.org/dc")); - AssertJUnit.assertTrue(nssupport.getURI("dc1").equals("http://www.purl.org/dc")); - AssertJUnit.assertTrue(nssupport.getURI("dc2").equals("http://www.purl.org/dc2")); - AssertJUnit.assertTrue(nssupport.getURI("dcnew").equals("http://www.purl.org/dcnew")); + assertEquals("http://www.purl.org/dc", nssupport.getURI("dc")); + assertEquals("http://www.purl.org/dc", nssupport.getURI("dc1")); + assertEquals("http://www.purl.org/dc2", nssupport.getURI("dc2")); + assertEquals("http://www.purl.org/dcnew", nssupport.getURI("dcnew")); // Negative test - Assert.assertNull(nssupport.getURI("wrong_prefix")); - Assert.assertNull(nssupport.getURI("")); + assertNull(nssupport.getURI("wrong_prefix")); + assertNull(nssupport.getURI("")); } } diff --git a/test/jaxp/javax/xml/jaxp/unittest/sax/SAXExceptionInitCause.java b/test/jaxp/javax/xml/jaxp/unittest/sax/SAXExceptionInitCause.java index 4e5307b42ec..ee028d74611 100644 --- a/test/jaxp/javax/xml/jaxp/unittest/sax/SAXExceptionInitCause.java +++ b/test/jaxp/javax/xml/jaxp/unittest/sax/SAXExceptionInitCause.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,12 +27,15 @@ * @summary The initCause() incorrectly initialize the cause in * SAXException class when used with SAXException(String) * constructor. - * @run testng/othervm sax.SAXExceptionInitCause + * @run junit/othervm sax.SAXExceptionInitCause * @author aleksej.efimov@oracle.com */ package sax; +import org.junit.jupiter.api.Test; +import org.xml.sax.SAXException; + import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -40,9 +43,11 @@ import java.io.InvalidClassException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; -import org.testng.Assert; -import org.testng.annotations.Test; -import org.xml.sax.SAXException; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; public class SAXExceptionInitCause { @@ -55,8 +60,8 @@ public class SAXExceptionInitCause { serialSAX = pickleException(noCauseException); deserializedException = unpickleException(serialSAX); - Assert.assertNull(deserializedException.getCause()); - Assert.assertEquals(deserializedException.getMessage(), SAX_MESSAGE); + assertNull(deserializedException.getCause()); + assertEquals(SAX_MESSAGE, deserializedException.getMessage()); } @Test @@ -69,18 +74,18 @@ public class SAXExceptionInitCause { serialSAX = pickleException(withCauseException); deserializedException = unpickleException(serialSAX); - Assert.assertNotNull(deserializedException.getCause()); - Assert.assertEquals(deserializedException.getMessage(), SAX_MESSAGE); - Assert.assertEquals(deserializedException.getCause().getMessage(), SAX_CAUSE_MESSAGE); + assertNotNull(deserializedException.getCause()); + assertEquals(SAX_MESSAGE, deserializedException.getMessage()); + assertEquals(SAX_CAUSE_MESSAGE, deserializedException.getCause().getMessage()); } @Test - public void testCauseInitByCtor() throws Exception { + public void testCauseInitByCtor() { // Check that constructor properly initializes cause Exception cause = new Exception(SAX_CAUSE_MESSAGE); SAXException exception = new SAXException(cause); - Assert.assertSame(exception.getCause(), cause); - Assert.assertSame(exception.getException(), cause); + assertSame(cause, exception.getCause()); + assertSame(cause, exception.getException()); } @Test @@ -89,8 +94,8 @@ public class SAXExceptionInitCause { SAXException exception = new SAXException(); Exception cause = new Exception(SAX_CAUSE_MESSAGE); exception.initCause(cause); - Assert.assertSame(exception.getCause(), cause); - Assert.assertSame(exception.getException(), cause); + assertSame(cause, exception.getCause()); + assertSame(cause, exception.getException()); } @Test @@ -100,48 +105,51 @@ public class SAXExceptionInitCause { SAXException exception = new SAXException(); Throwable cause = new Throwable(SAX_CAUSE_MESSAGE); exception.initCause(cause); - Assert.assertSame(exception.getCause(),cause); - Assert.assertNull(exception.getException()); + assertSame(cause, exception.getCause()); + assertNull(exception.getException()); } - @Test(expectedExceptions = IllegalStateException.class) + @Test public void testInitCauseTwice() { SAXException exception = new SAXException(new Exception(SAX_CAUSE_MESSAGE)); - // Expecting IllegalStateException at this point - exception.initCause(new Exception(SAX_CAUSE_MESSAGE)); + assertThrows( + IllegalStateException.class, + () -> exception.initCause(new Exception(SAX_CAUSE_MESSAGE))); } @Test public void testLegacySerialCtor() throws Exception { SAXException saxException8 = unpickleException(JDK8_SET_WITH_CTOR_ONLY); - Assert.assertNotNull(saxException8.getCause()); - Assert.assertNotNull(saxException8.getException()); + assertNotNull(saxException8.getCause()); + assertNotNull(saxException8.getException()); } @Test public void testLegacySerialCtorAndInit() throws Exception { SAXException saxException8 = unpickleException(JDK8_SET_WITH_CTOR_AND_INIT); - Assert.assertNotNull(saxException8.getCause()); - Assert.assertNotNull(saxException8.getException()); + assertNotNull(saxException8.getCause()); + assertNotNull(saxException8.getException()); } @Test public void testLegacySerialInitCause() throws Exception { SAXException saxException8 = unpickleException(JDK8_WITH_INIT_ONLY); - Assert.assertNotNull(saxException8.getCause()); - Assert.assertNotNull(saxException8.getException()); + assertNotNull(saxException8.getCause()); + assertNotNull(saxException8.getException()); } @Test public void testLegacySerialNothingSet() throws Exception { SAXException saxException8 = unpickleException(JDK8_NOTHING_SET); - Assert.assertNull(saxException8.getCause()); - Assert.assertNull(saxException8.getException()); + assertNull(saxException8.getCause()); + assertNull(saxException8.getException()); } - @Test(expectedExceptions = InvalidClassException.class) - public void testReadObjectIllegalStateException() throws Exception { - SAXException saxException8 = unpickleException(JDK8_CHECK_ILLEGAL_STATE_EXCEPTION); + @Test + public void testReadObjectIllegalStateException() { + assertThrows( + InvalidClassException.class, + () -> unpickleException(JDK8_CHECK_ILLEGAL_STATE_EXCEPTION)); } // Serialize SAXException to byte array @@ -164,8 +172,8 @@ public class SAXExceptionInitCause { return saxException; } - private static String SAX_MESSAGE = "SAXException message"; - private static String SAX_CAUSE_MESSAGE = "SAXException cause message"; + private static final String SAX_MESSAGE = "SAXException message"; + private static final String SAX_CAUSE_MESSAGE = "SAXException cause message"; /* This is a serial form of ordinary SAXException serialized * by the following JDK8 code: diff --git a/test/jaxp/javax/xml/jaxp/unittest/sax/SAXParserTest.java b/test/jaxp/javax/xml/jaxp/unittest/sax/SAXParserTest.java index 708ae2178b0..ee7e81df5fb 100644 --- a/test/jaxp/javax/xml/jaxp/unittest/sax/SAXParserTest.java +++ b/test/jaxp/javax/xml/jaxp/unittest/sax/SAXParserTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,24 +23,25 @@ package sax; -import static jaxp.library.JAXPTestUtilities.getSystemProperty; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import javax.xml.parsers.SAXParser; -import javax.xml.parsers.SAXParserFactory; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +import static org.junit.jupiter.api.Assertions.assertThrows; + /* * @test * @bug 8213734 * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest - * @run testng sax.SAXParserTest - * @summary Tests functionalities for SAXParser. + * @run junit sax.SAXParserTest + * @summary Tests that failed parsing closes the file correctly. */ public class SAXParserTest { @@ -51,35 +52,24 @@ public class SAXParserTest { */ @Test public void testCloseReaders() throws Exception { - if (!getSystemProperty("os.name").contains("Windows")) { - System.out.println("This test only needs to be run on Windows."); - return; - } - Path testFile = createTestFile(null, "Test"); + Path testFile = createTestFile("Test"); System.out.println("Test file: " + testFile.toString()); SAXParserFactory factory = SAXParserFactory.newDefaultInstance(); SAXParser parser = factory.newSAXParser(); - try { - parser.parse(testFile.toFile(), new DefaultHandler() { - @Override - public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { - throw new SAXException("Stop the parser."); - } - }); - } catch (SAXException e) { - // Do nothing - } - - // deletion failes on Windows when the file is not closed - Files.deleteIfExists(testFile); + DefaultHandler explodingHandler = new DefaultHandler() { + @Override + public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { + throw new SAXException("Stop the parser."); + } + }; + assertThrows(SAXException.class, () -> parser.parse(testFile.toFile(), explodingHandler)); + // Deletion would fail on Windows if the file was not closed. + Files.delete(testFile); } - private static Path createTestFile(Path dir, String name) throws IOException { + private static Path createTestFile(String name) throws IOException { Path path = Files.createTempFile(name, ".xml"); - byte[] bytes = "" - .getBytes(StandardCharsets.UTF_8); - - Files.write(path, bytes); + Files.writeString(path, ""); return path; } } diff --git a/test/jaxp/javax/xml/jaxp/unittest/sax/SymbolTableResetTest.java b/test/jaxp/javax/xml/jaxp/unittest/sax/SymbolTableResetTest.java index ff961e8e9e2..6a934aed291 100644 --- a/test/jaxp/javax/xml/jaxp/unittest/sax/SymbolTableResetTest.java +++ b/test/jaxp/javax/xml/jaxp/unittest/sax/SymbolTableResetTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * 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,20 +23,23 @@ package sax; -import java.io.StringReader; -import javax.xml.parsers.SAXParser; -import javax.xml.parsers.SAXParserFactory; -import org.testng.Assert; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import org.xml.sax.InputSource; import org.xml.sax.helpers.DefaultHandler; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; +import java.io.StringReader; + +import static org.junit.jupiter.api.Assertions.assertNotSame; +import static org.junit.jupiter.api.Assertions.assertSame; + /* * @test * @bug 8173390 8176168 * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest - * @run testng/othervm -Djdk.xml.resetSymbolTable=false sax.SymbolTableResetTest - * @run testng/othervm -Djdk.xml.resetSymbolTable=true sax.SymbolTableResetTest + * @run junit/othervm -Djdk.xml.resetSymbolTable=false sax.SymbolTableResetTest + * @run junit/othervm -Djdk.xml.resetSymbolTable=true sax.SymbolTableResetTest * @summary Test that SAXParser reallocates symbol table during * subsequent parse operations */ @@ -115,9 +118,9 @@ public class SymbolTableResetTest { // Check symbol table references after two subsequent parse operations if (resetExpected) { - Assert.assertNotSame(symTable1, symTable2, "Symbol table references"); + assertNotSame(symTable1, symTable2, "Symbol table references"); } else { - Assert.assertSame(symTable1, symTable2, "Symbol table references"); + assertSame(symTable1, symTable2, "Symbol table references"); } } diff --git a/test/jaxp/javax/xml/jaxp/unittest/sax/XMLReaderTest.java b/test/jaxp/javax/xml/jaxp/unittest/sax/XMLReaderTest.java index ae235f32549..d625f835a52 100644 --- a/test/jaxp/javax/xml/jaxp/unittest/sax/XMLReaderTest.java +++ b/test/jaxp/javax/xml/jaxp/unittest/sax/XMLReaderTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * 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,36 +23,26 @@ package sax; -import static jaxp.library.JAXPTestUtilities.clearSystemProperty; -import static jaxp.library.JAXPTestUtilities.setSystemProperty; - -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.parsers.SAXParserFactory; - -import org.testng.annotations.AfterClass; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import org.xml.sax.helpers.XMLReaderAdapter; import org.xml.sax.helpers.XMLReaderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParserFactory; + +import static org.junit.jupiter.api.Assertions.assertThrows; + /* * @test * @bug 8158246 8316383 * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest - * @run testng/othervm sax.XMLReaderTest + * @run junit/othervm sax.XMLReaderTest * @summary This class contains tests that cover the creation of XMLReader. */ public class XMLReaderTest { - private final String SAX_PROPNAME = "org.xml.sax.driver"; - - /* - * Clean up after test - */ - @AfterClass - public void cleanUp() throws Exception { - clearSystemProperty(SAX_PROPNAME); - } + private static final String SAX_PROPNAME = "org.xml.sax.driver"; /* * @bug 8158246 @@ -61,12 +51,16 @@ public class XMLReaderTest { * * Except test format, this test is the same as JCK's test Ctor003. */ - @Test(expectedExceptions = SAXException.class) + @Test public void testcreateXMLReader() throws SAXException, ParserConfigurationException { String className = SAXParserFactory.newInstance().newSAXParser() - .getXMLReader().getClass().getName(); - setSystemProperty(SAX_PROPNAME, className + "nosuch"); - XMLReaderAdapter adapter = new XMLReaderAdapter(); + .getXMLReader().getClass().getName(); + System.setProperty(SAX_PROPNAME, className + "nosuch"); + try { + assertThrows(SAXException.class, XMLReaderAdapter::new); + } finally { + System.clearProperty(SAX_PROPNAME); + } } /* diff --git a/test/jaxp/javax/xml/jaxp/unittest/sbd/test/ExternalRefTest.java b/test/jaxp/javax/xml/jaxp/unittest/sbd/test/ExternalRefTest.java index 0b9daed0d83..273278f23e5 100644 --- a/test/jaxp/javax/xml/jaxp/unittest/sbd/test/ExternalRefTest.java +++ b/test/jaxp/javax/xml/jaxp/unittest/sbd/test/ExternalRefTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. * 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,19 +22,21 @@ */ package sbd.test; -import java.io.File; -import javax.xml.parsers.SAXParser; -import javax.xml.parsers.SAXParserFactory; -import org.testng.Assert; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import org.xml.sax.SAXParseException; import org.xml.sax.helpers.DefaultHandler; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; +import java.io.File; + +import static org.junit.jupiter.api.Assertions.assertThrows; + /* * @test * @bug 8326915 * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest - * @run testng/othervm sbd.test.ExternalRefTest + * @run junit/othervm sbd.test.ExternalRefTest * @summary Part of the Secure-By-Default (SBD) project. This test verifies issues * and error message improvements related to external references. */ @@ -43,11 +45,10 @@ public class ExternalRefTest { * @bug 8326915 * Verifies that SAXParseException rather than NPE is thrown when a validating * parser is restricted from processing external references. - * @throws Exception if the test fails */ @Test - public void testValidatingParser() throws Exception { - Assert.assertThrows(SAXParseException.class, () -> validateWithParser()); + public void testValidatingParser() { + assertThrows(SAXParseException.class, this::validateWithParser); } private void validateWithParser() throws Exception { From dfe438d0570ada60de9d8dd7cdf97d229d91fc48 Mon Sep 17 00:00:00 2001 From: Ruben Ayrapetyan Date: Tue, 31 Mar 2026 10:14:26 +0000 Subject: [PATCH 117/359] 8366441: AArch64: Support WFET in OnSpinWait Co-authored-by: Stuart Monteith Co-authored-by: Andrew Haley Reviewed-by: aph, eastigeevich --- src/hotspot/cpu/aarch64/assembler_aarch64.hpp | 4 + src/hotspot/cpu/aarch64/globals_aarch64.hpp | 14 +- .../cpu/aarch64/macroAssembler_aarch64.cpp | 25 + .../cpu/aarch64/macroAssembler_aarch64.hpp | 9 + src/hotspot/cpu/aarch64/spin_wait_aarch64.cpp | 3 + src/hotspot/cpu/aarch64/spin_wait_aarch64.hpp | 17 +- .../cpu/aarch64/vm_version_aarch64.cpp | 26 +- .../cpu/aarch64/vm_version_aarch64.hpp | 4 +- .../os_cpu/bsd_aarch64/os_bsd_aarch64.cpp | 2 + .../vm_version_linux_aarch64.cpp | 13 + .../flags/jvmFlagConstraintsRuntime.cpp | 16 +- .../classes/jdk/vm/ci/aarch64/AArch64.java | 2 + test/hotspot/gtest/aarch64/aarch64-asmtest.py | 13 +- test/hotspot/gtest/aarch64/asmtest.out.h | 2253 +++++++++-------- .../onSpinWait/TestOnSpinWaitAArch64.java | 38 +- 15 files changed, 1299 insertions(+), 1140 deletions(-) diff --git a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp b/src/hotspot/cpu/aarch64/assembler_aarch64.hpp index 67cf77989d2..ebd8f3a9e03 100644 --- a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/assembler_aarch64.hpp @@ -1095,6 +1095,10 @@ public: #undef INSN + void wfet(Register rt) { + system(0b00, 0b011, 0b0001, 0b0000, 0b000, rt); + } + // we only provide mrs and msr for the special purpose system // registers where op1 (instr[20:19]) == 11 // n.b msr has L (instr[21]) == 0 mrs has L == 1 diff --git a/src/hotspot/cpu/aarch64/globals_aarch64.hpp b/src/hotspot/cpu/aarch64/globals_aarch64.hpp index e6de2c798b1..0ca5cb25e0c 100644 --- a/src/hotspot/cpu/aarch64/globals_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/globals_aarch64.hpp @@ -115,14 +115,18 @@ define_pd_global(intx, InlineSmallCode, 1000); "Value -1 means off.") \ range(-1, 4096) \ product(ccstr, OnSpinWaitInst, "yield", DIAGNOSTIC, \ - "The instruction to use to implement " \ - "java.lang.Thread.onSpinWait()." \ - "Valid values are: none, nop, isb, yield, sb.") \ + "The instruction to use for java.lang.Thread.onSpinWait(). " \ + "Valid values are: none, nop, isb, yield, sb, wfet.") \ constraint(OnSpinWaitInstNameConstraintFunc, AtParse) \ product(uint, OnSpinWaitInstCount, 1, DIAGNOSTIC, \ - "The number of OnSpinWaitInst instructions to generate." \ - "It cannot be used with OnSpinWaitInst=none.") \ + "The number of OnSpinWaitInst instructions to generate. " \ + "It cannot be used with OnSpinWaitInst=none. " \ + "For OnSpinWaitInst=wfet it must be 1.") \ range(1, 99) \ + product(uint, OnSpinWaitDelay, 40, DIAGNOSTIC, \ + "The minimum delay (in nanoseconds) of the OnSpinWait loop. " \ + "It can only be used with -XX:OnSpinWaitInst=wfet.") \ + range(1, 1000) \ product(ccstr, UseBranchProtection, "none", \ "Branch Protection to use: none, standard, pac-ret") \ product(bool, AlwaysMergeDMB, true, DIAGNOSTIC, \ diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp index 732d94180ae..ebbc35ce20a 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp @@ -6807,6 +6807,9 @@ void MacroAssembler::spin_wait() { assert(VM_Version::supports_sb(), "current CPU does not support SB instruction"); sb(); break; + case SpinWait::WFET: + spin_wait_wfet(VM_Version::spin_wait_desc().delay()); + break; default: ShouldNotReachHere(); } @@ -6814,6 +6817,28 @@ void MacroAssembler::spin_wait() { block_comment("}"); } +void MacroAssembler::spin_wait_wfet(int delay_ns) { + // The sequence assumes CNTFRQ_EL0 is fixed to 1GHz. The assumption is valid + // starting from Armv8.6, according to the "D12.1.2 The system counter" of the + // Arm Architecture Reference Manual for A-profile architecture version M.a.a. + // This is sufficient because FEAT_WFXT is introduced from Armv8.6. + Register target = rscratch1; + Register current = rscratch2; + get_cntvctss_el0(current); + add(target, current, delay_ns); + + Label L_wait_loop; + bind(L_wait_loop); + + wfet(target); + get_cntvctss_el0(current); + + cmp(current, target); + br(LT, L_wait_loop); + + sb(); +} + // Stack frame creation/removal void MacroAssembler::enter(bool strip_ret_addr) { diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp index fa32f3055b9..994fbe3c80f 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp @@ -660,6 +660,14 @@ public: msr(0b011, 0b0100, 0b0010, 0b000, reg); } + // CNTVCTSS_EL0: op1 == 011 + // CRn == 1110 + // CRm == 0000 + // op2 == 110 + inline void get_cntvctss_el0(Register reg) { + mrs(0b011, 0b1110, 0b0000, 0b110, reg); + } + // idiv variant which deals with MINLONG as dividend and -1 as divisor int corrected_idivl(Register result, Register ra, Register rb, bool want_remainder, Register tmp = rscratch1); @@ -1724,6 +1732,7 @@ public: // Code for java.lang.Thread::onSpinWait() intrinsic. void spin_wait(); + void spin_wait_wfet(int delay_ns); void fast_lock(Register basic_lock, Register obj, Register t1, Register t2, Register t3, Label& slow); void fast_unlock(Register obj, Register t1, Register t2, Register t3, Label& slow); diff --git a/src/hotspot/cpu/aarch64/spin_wait_aarch64.cpp b/src/hotspot/cpu/aarch64/spin_wait_aarch64.cpp index 7da0151d834..97a981ab815 100644 --- a/src/hotspot/cpu/aarch64/spin_wait_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/spin_wait_aarch64.cpp @@ -32,6 +32,7 @@ bool SpinWait::supports(const char *name) { strcmp(name, "isb") == 0 || strcmp(name, "yield") == 0 || strcmp(name, "sb") == 0 || + strcmp(name, "wfet") == 0 || strcmp(name, "none") == 0); } @@ -46,6 +47,8 @@ SpinWait::Inst SpinWait::from_name(const char* name) { return SpinWait::YIELD; } else if (strcmp(name, "sb") == 0) { return SpinWait::SB; + } else if (strcmp(name, "wfet") == 0) { + return SpinWait::WFET; } return SpinWait::NONE; diff --git a/src/hotspot/cpu/aarch64/spin_wait_aarch64.hpp b/src/hotspot/cpu/aarch64/spin_wait_aarch64.hpp index 0e96a4b7157..6ebcd2477a8 100644 --- a/src/hotspot/cpu/aarch64/spin_wait_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/spin_wait_aarch64.hpp @@ -24,6 +24,8 @@ #ifndef CPU_AARCH64_SPIN_WAIT_AARCH64_HPP #define CPU_AARCH64_SPIN_WAIT_AARCH64_HPP +#include "utilities/debug.hpp" + class SpinWait { public: enum Inst { @@ -31,21 +33,30 @@ public: NOP, ISB, YIELD, - SB + SB, + WFET }; private: Inst _inst; int _count; + int _delay; Inst from_name(const char *name); public: - SpinWait(Inst inst = NONE, int count = 0) : _inst(inst), _count(inst == NONE ? 0 : count) {} - SpinWait(const char *name, int count) : SpinWait(from_name(name), count) {} + SpinWait(Inst inst = NONE, int count = 0, int delay = -1) + : _inst(inst), _count(inst == NONE ? 0 : count), _delay(delay) {} + SpinWait(const char *name, int count, int delay) + : SpinWait(from_name(name), count, delay) {} Inst inst() const { return _inst; } int inst_count() const { return _count; } + int delay() const { + assert(_inst == WFET, "Specifying the delay value is only supported for WFET"); + assert(_delay > 0, "The delay value must be positive"); + return _delay; + } static bool supports(const char *name); }; diff --git a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp index 4423d9c5b58..8ccffac25a8 100644 --- a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp @@ -1,7 +1,7 @@ /* * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2015, 2020, Red Hat Inc. All rights reserved. - * Copyright 2025 Arm Limited and/or its affiliates. + * Copyright 2025, 2026 Arm Limited 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 @@ -55,11 +55,33 @@ SpinWait VM_Version::_spin_wait; const char* VM_Version::_features_names[MAX_CPU_FEATURES] = { nullptr }; static SpinWait get_spin_wait_desc() { - SpinWait spin_wait(OnSpinWaitInst, OnSpinWaitInstCount); + SpinWait spin_wait(OnSpinWaitInst, OnSpinWaitInstCount, OnSpinWaitDelay); if (spin_wait.inst() == SpinWait::SB && !VM_Version::supports_sb()) { vm_exit_during_initialization("OnSpinWaitInst is SB but current CPU does not support SB instruction"); } + if (spin_wait.inst() == SpinWait::WFET) { + if (!VM_Version::supports_wfxt()) { + vm_exit_during_initialization("OnSpinWaitInst is WFET but the CPU does not support the WFET instruction"); + } + + if (!VM_Version::supports_ecv()) { + vm_exit_during_initialization("The CPU does not support the FEAT_ECV required by the -XX:OnSpinWaitInst=wfet implementation"); + } + + if (!VM_Version::supports_sb()) { + vm_exit_during_initialization("The CPU does not support the SB instruction required by the -XX:OnSpinWaitInst=wfet implementation"); + } + + if (OnSpinWaitInstCount != 1) { + vm_exit_during_initialization("OnSpinWaitInstCount for OnSpinWaitInst 'wfet' must be 1"); + } + } else { + if (!FLAG_IS_DEFAULT(OnSpinWaitDelay)) { + vm_exit_during_initialization("OnSpinWaitDelay can only be used with -XX:OnSpinWaitInst=wfet"); + } + } + return spin_wait; } diff --git a/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp b/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp index e8681611234..378524fe168 100644 --- a/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp @@ -159,7 +159,9 @@ public: /* flags above must follow Linux HWCAP */ \ decl(SVEBITPERM, svebitperm, 27) \ decl(SVE2, sve2, 28) \ - decl(A53MAC, a53mac, 31) + decl(A53MAC, a53mac, 31) \ + decl(ECV, ecv, 32) \ + decl(WFXT, wfxt, 33) enum Feature_Flag { #define DECLARE_CPU_FEATURE_FLAG(id, name, bit) CPU_##id = bit, diff --git a/src/hotspot/os_cpu/bsd_aarch64/os_bsd_aarch64.cpp b/src/hotspot/os_cpu/bsd_aarch64/os_bsd_aarch64.cpp index 36599594842..49d879731ff 100644 --- a/src/hotspot/os_cpu/bsd_aarch64/os_bsd_aarch64.cpp +++ b/src/hotspot/os_cpu/bsd_aarch64/os_bsd_aarch64.cpp @@ -620,6 +620,8 @@ extern "C" { assert(VM_Version::supports_sb(), "current CPU does not support SB instruction"); asm volatile(".inst 0xd50330ff" : : : "memory"); break; + case SpinWait::WFET: + ShouldNotReachHere(); #ifdef ASSERT default: ShouldNotReachHere(); diff --git a/src/hotspot/os_cpu/linux_aarch64/vm_version_linux_aarch64.cpp b/src/hotspot/os_cpu/linux_aarch64/vm_version_linux_aarch64.cpp index 1fe06dc640d..168fc622a0b 100644 --- a/src/hotspot/os_cpu/linux_aarch64/vm_version_linux_aarch64.cpp +++ b/src/hotspot/os_cpu/linux_aarch64/vm_version_linux_aarch64.cpp @@ -95,6 +95,13 @@ #define HWCAP2_SVEBITPERM (1 << 4) #endif +#ifndef HWCAP2_ECV +#define HWCAP2_ECV (1 << 19) +#endif + +#ifndef HWCAP2_WFXT +#define HWCAP2_WFXT (1u << 31) +#endif #ifndef PR_SVE_GET_VL // For old toolchains which do not have SVE related macros defined. #define PR_SVE_SET_VL 50 @@ -158,6 +165,12 @@ void VM_Version::get_os_cpu_info() { if (auxv2 & HWCAP2_SVEBITPERM) { set_feature(CPU_SVEBITPERM); } + if (auxv2 & HWCAP2_ECV) { + set_feature(CPU_ECV); + } + if (auxv2 & HWCAP2_WFXT) { + set_feature(CPU_WFXT); + } uint64_t ctr_el0; uint64_t dczid_el0; diff --git a/src/hotspot/share/runtime/flags/jvmFlagConstraintsRuntime.cpp b/src/hotspot/share/runtime/flags/jvmFlagConstraintsRuntime.cpp index 1e6efd893c8..1f16fada239 100644 --- a/src/hotspot/share/runtime/flags/jvmFlagConstraintsRuntime.cpp +++ b/src/hotspot/share/runtime/flags/jvmFlagConstraintsRuntime.cpp @@ -153,6 +153,20 @@ JVMFlag::Error OnSpinWaitInstNameConstraintFunc(ccstr value, bool verbose) { return JVMFlag::VIOLATES_CONSTRAINT; } +#ifdef LINUX + if (strcmp(value, "wfet") == 0) { + if (UnlockExperimentalVMOptions) { + return JVMFlag::SUCCESS; + } else { + JVMFlag::printError(verbose, + "'wfet' value for OnSpinWaitInst is experimental and " + "must be enabled via -XX:+UnlockExperimentalVMOptions.\n" + "Error: The unlock option must precede 'OnSpinWaitInst'.\n"); + return JVMFlag::VIOLATES_CONSTRAINT; + } + } +#endif + if (strcmp(value, "nop") != 0 && strcmp(value, "isb") != 0 && strcmp(value, "yield") != 0 && @@ -160,7 +174,7 @@ JVMFlag::Error OnSpinWaitInstNameConstraintFunc(ccstr value, bool verbose) { strcmp(value, "none") != 0) { JVMFlag::printError(verbose, "Unrecognized value %s for OnSpinWaitInst. Must be one of the following: " - "nop, isb, yield, sb, none\n", + "nop, isb, yield, sb," LINUX_ONLY(" wfet,") " none\n", value); return JVMFlag::VIOLATES_CONSTRAINT; } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/aarch64/AArch64.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/aarch64/AArch64.java index 391ac224609..7790a9abd7c 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/aarch64/AArch64.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/aarch64/AArch64.java @@ -184,6 +184,8 @@ public class AArch64 extends Architecture { SVEBITPERM, SVE2, A53MAC, + ECV, + WFXT, FPHP, ASIMDHP, } diff --git a/test/hotspot/gtest/aarch64/aarch64-asmtest.py b/test/hotspot/gtest/aarch64/aarch64-asmtest.py index 1ac2e1a89cd..bcf786d6f1f 100644 --- a/test/hotspot/gtest/aarch64/aarch64-asmtest.py +++ b/test/hotspot/gtest/aarch64/aarch64-asmtest.py @@ -391,6 +391,11 @@ class SystemRegOp(Instruction): self.CRn = 0b0100 self.CRm = 0b0010 self.op2 = 0b000 + elif self.system_reg == 'cntvctss_el0': + self.op1 = 0b011 + self.CRn = 0b1110 + self.CRm = 0b0000 + self.op2 = 0b110 def generate(self): self.reg = [GeneralRegister().generate()] @@ -1607,6 +1612,8 @@ generate (Op, ["nop", "yield", "wfe", "sev", "sevl", "pacia1716", "paciasp", "paciaz", "pacib1716", "pacibsp", "pacibz", "eret", "drps", "isb", "sb",]) +generate (OneRegOp, ["wfet"]) + # Ensure the "i" is not stripped off the end of the instruction generate (PostfixExceptionOp, ["wfi", "xpaclri"]) @@ -1623,7 +1630,7 @@ generate (OneRegOp, ["br", "blr", for system_reg in ["fpsr", "nzcv"]: generate (SystemOneRegOp, [ ["msr", system_reg] ]) -for system_reg in ["fpsr", "nzcv", "dczid_el0", "ctr_el0"]: +for system_reg in ["fpsr", "nzcv", "dczid_el0", "ctr_el0", "cntvctss_el0"]: generate (OneRegSystemOp, [ ["mrs", system_reg] ]) # Ensure the "i" is not stripped off the end of the instruction @@ -2275,9 +2282,9 @@ outfile.write("forth:\n") outfile.close() -# compile for sve with armv9-a+sha3+sve2-bitperm because of SHA3 crypto extension and SVE2 bitperm instructions. +# compile for sve with armv9.2-a+sha3+sve2-bitperm because of SHA3 crypto extension and SVE2 bitperm instructions. # armv9-a enables sve and sve2 by default. -subprocess.check_call([AARCH64_AS, "-march=armv9-a+sha3+sve2-bitperm", "aarch64ops.s", "-o", "aarch64ops.o"]) +subprocess.check_call([AARCH64_AS, "-march=armv9.2-a+sha3+sve2-bitperm", "aarch64ops.s", "-o", "aarch64ops.o"]) print print "/*" diff --git a/test/hotspot/gtest/aarch64/asmtest.out.h b/test/hotspot/gtest/aarch64/asmtest.out.h index 22bb6c57784..cd9fd4cfe9a 100644 --- a/test/hotspot/gtest/aarch64/asmtest.out.h +++ b/test/hotspot/gtest/aarch64/asmtest.out.h @@ -189,756 +189,762 @@ __ isb(); // isb __ sb(); // sb +// OneRegOp + __ wfet(r26); // wfet x26 + // PostfixExceptionOp __ wfi(); // wfi __ xpaclri(); // xpaclri // SystemOp - __ dsb(Assembler::ST); // dsb ST - __ dmb(Assembler::OSHST); // dmb OSHST + __ dsb(Assembler::OSHST); // dsb OSHST + __ dmb(Assembler::ISHLD); // dmb ISHLD // OneRegOp - __ br(r16); // br x16 - __ blr(r20); // blr x20 - __ paciza(r10); // paciza x10 - __ pacizb(r27); // pacizb x27 - __ pacdza(r8); // pacdza x8 - __ pacdzb(r0); // pacdzb x0 - __ autiza(r1); // autiza x1 - __ autizb(r21); // autizb x21 - __ autdza(r17); // autdza x17 + __ br(r20); // br x20 + __ blr(r10); // blr x10 + __ paciza(r27); // paciza x27 + __ pacizb(r8); // pacizb x8 + __ pacdza(r0); // pacdza x0 + __ pacdzb(r1); // pacdzb x1 + __ autiza(r21); // autiza x21 + __ autizb(r17); // autizb x17 + __ autdza(r29); // autdza x29 __ autdzb(r29); // autdzb x29 - __ xpacd(r29); // xpacd x29 - __ braaz(r28); // braaz x28 - __ brabz(r1); // brabz x1 - __ blraaz(r23); // blraaz x23 - __ blrabz(r21); // blrabz x21 + __ xpacd(r28); // xpacd x28 + __ braaz(r1); // braaz x1 + __ brabz(r23); // brabz x23 + __ blraaz(r21); // blraaz x21 + __ blrabz(r20); // blrabz x20 // SystemOneRegOp - __ msr(3, 4, 4, 1, r20); // msr fpsr, x20 + __ msr(3, 4, 4, 1, r22); // msr fpsr, x22 // SystemOneRegOp - __ msr(3, 4, 2, 0, r22); // msr nzcv, x22 + __ msr(3, 4, 2, 0, r27); // msr nzcv, x27 // OneRegSystemOp - __ mrs(3, 4, 4, 1, r27); // mrs x27, fpsr + __ mrs(3, 4, 4, 1, r19); // mrs x19, fpsr // OneRegSystemOp - __ mrs(3, 4, 2, 0, r19); // mrs x19, nzcv + __ mrs(3, 4, 2, 0, r11); // mrs x11, nzcv // OneRegSystemOp - __ mrs(3, 0, 0, 7, r11); // mrs x11, dczid_el0 + __ mrs(3, 0, 0, 7, r16); // mrs x16, dczid_el0 // OneRegSystemOp - __ mrs(3, 0, 0, 1, r16); // mrs x16, ctr_el0 + __ mrs(3, 0, 0, 1, r6); // mrs x6, ctr_el0 + +// OneRegSystemOp + __ mrs(3, 14, 0, 6, r17); // mrs x17, cntvctss_el0 // PostfixExceptionOneRegOp - __ xpaci(r6); // xpaci x6 + __ xpaci(r0); // xpaci x0 // LoadStoreExclusiveOp - __ stxr(r17, r0, r4); // stxr w17, x0, [x4] - __ stlxr(r10, r24, r22); // stlxr w10, x24, [x22] - __ ldxr(r10, r19); // ldxr x10, [x19] - __ ldaxr(r1, r5); // ldaxr x1, [x5] - __ stlr(r30, r8); // stlr x30, [x8] - __ ldar(r12, r17); // ldar x12, [x17] + __ stxr(r4, r10, r24); // stxr w4, x10, [x24] + __ stlxr(r22, r10, r19); // stlxr w22, x10, [x19] + __ ldxr(r1, r5); // ldxr x1, [x5] + __ ldaxr(r30, r8); // ldaxr x30, [x8] + __ stlr(r12, r17); // stlr x12, [x17] + __ ldar(r9, r14); // ldar x9, [x14] // LoadStoreExclusiveOp - __ stxrw(r9, r14, r7); // stxr w9, w14, [x7] - __ stlxrw(r1, r5, r16); // stlxr w1, w5, [x16] - __ ldxrw(r2, r12); // ldxr w2, [x12] - __ ldaxrw(r10, r12); // ldaxr w10, [x12] - __ stlrw(r3, r28); // stlr w3, [x28] - __ ldarw(r14, r26); // ldar w14, [x26] + __ stxrw(r7, r1, r5); // stxr w7, w1, [x5] + __ stlxrw(r16, r2, r12); // stlxr w16, w2, [x12] + __ ldxrw(r10, r12); // ldxr w10, [x12] + __ ldaxrw(r3, r28); // ldaxr w3, [x28] + __ stlrw(r14, r26); // stlr w14, [x26] + __ ldarw(r30, r10); // ldar w30, [x10] // LoadStoreExclusiveOp - __ stxrh(r30, r10, r14); // stxrh w30, w10, [x14] - __ stlxrh(r21, r13, r9); // stlxrh w21, w13, [x9] - __ ldxrh(r22, r27); // ldxrh w22, [x27] - __ ldaxrh(r28, r19); // ldaxrh w28, [x19] - __ stlrh(r11, r30); // stlrh w11, [x30] - __ ldarh(r19, r2); // ldarh w19, [x2] + __ stxrh(r14, r21, r13); // stxrh w14, w21, [x13] + __ stlxrh(r9, r22, r27); // stlxrh w9, w22, [x27] + __ ldxrh(r28, r19); // ldxrh w28, [x19] + __ ldaxrh(r11, r30); // ldaxrh w11, [x30] + __ stlrh(r19, r2); // stlrh w19, [x2] + __ ldarh(r2, r23); // ldarh w2, [x23] // LoadStoreExclusiveOp - __ stxrb(r2, r23, r1); // stxrb w2, w23, [x1] - __ stlxrb(r0, r12, r16); // stlxrb w0, w12, [x16] - __ ldxrb(r13, r15); // ldxrb w13, [x15] - __ ldaxrb(r17, r21); // ldaxrb w17, [x21] - __ stlrb(r13, r11); // stlrb w13, [x11] - __ ldarb(r30, r8); // ldarb w30, [x8] + __ stxrb(r1, r0, r12); // stxrb w1, w0, [x12] + __ stlxrb(r16, r13, r15); // stlxrb w16, w13, [x15] + __ ldxrb(r17, r21); // ldxrb w17, [x21] + __ ldaxrb(r13, r11); // ldaxrb w13, [x11] + __ stlrb(r30, r8); // stlrb w30, [x8] + __ ldarb(r24, r13); // ldarb w24, [x13] // LoadStoreExclusiveOp - __ ldxp(r24, r13, r11); // ldxp x24, x13, [x11] - __ ldaxp(r1, r26, r21); // ldaxp x1, x26, [x21] - __ stxp(r27, r13, r20, r3); // stxp w27, x13, x20, [x3] - __ stlxp(r12, r6, r1, r29); // stlxp w12, x6, x1, [x29] + __ ldxp(r11, r1, r26); // ldxp x11, x1, [x26] + __ ldaxp(r21, r27, r13); // ldaxp x21, x27, [x13] + __ stxp(r20, r3, r12, r6); // stxp w20, x3, x12, [x6] + __ stlxp(r1, r29, r6, r4); // stlxp w1, x29, x6, [x4] // LoadStoreExclusiveOp - __ ldxpw(r6, r4, r11); // ldxp w6, w4, [x11] - __ ldaxpw(r16, r4, r30); // ldaxp w16, w4, [x30] - __ stxpw(r30, r4, r12, r21); // stxp w30, w4, w12, [x21] - __ stlxpw(r27, r15, r28, r9); // stlxp w27, w15, w28, [x9] + __ ldxpw(r6, r11, r16); // ldxp w6, w11, [x16] + __ ldaxpw(r4, r30, r12); // ldaxp w4, w30, [x12] + __ stxpw(r21, r27, r15, r28); // stxp w21, w27, w15, [x28] + __ stlxpw(r9, r15, r20, r6); // stlxp w9, w15, w20, [x6] // base_plus_unscaled_offset // LoadStoreOp - __ str(r25, Address(r15, 1)); // str x25, [x15, 1] - __ strw(r2, Address(r1, -79)); // str w2, [x1, -79] - __ strb(r20, Address(r26, -22)); // strb w20, [x26, -22] - __ strh(r23, Address(r30, 22)); // strh w23, [x30, 22] - __ ldr(r26, Address(r28, -49)); // ldr x26, [x28, -49] - __ ldrw(r9, Address(r24, -128)); // ldr w9, [x24, -128] - __ ldrb(r12, Address(r12, -30)); // ldrb w12, [x12, -30] - __ ldrh(r1, Address(r15, 5)); // ldrh w1, [x15, 5] - __ ldrsb(r24, Address(r14, -31)); // ldrsb x24, [x14, -31] - __ ldrsh(r24, Address(r15, -6)); // ldrsh x24, [x15, -6] - __ ldrshw(r5, Address(r3, 12)); // ldrsh w5, [x3, 12] - __ ldrsw(r27, Address(r24, 17)); // ldrsw x27, [x24, 17] - __ ldrd(v13, Address(r29, -35)); // ldr d13, [x29, -35] - __ ldrs(v23, Address(r9, -47)); // ldr s23, [x9, -47] - __ strd(v11, Address(r0, 9)); // str d11, [x0, 9] - __ strs(v21, Address(r0, -127)); // str s21, [x0, -127] + __ str(r24, Address(r17, -125)); // str x24, [x17, -125] + __ strw(r1, Address(r26, 10)); // str w1, [x26, 10] + __ strb(r15, Address(r0, -17)); // strb w15, [x0, -17] + __ strh(r17, Address(r17, 13)); // strh w17, [x17, 13] + __ ldr(r5, Address(r25, 49)); // ldr x5, [x25, 49] + __ ldrw(r19, Address(r15, -116)); // ldr w19, [x15, -116] + __ ldrb(r20, Address(r3, 7)); // ldrb w20, [x3, 7] + __ ldrh(r19, Address(r4, -25)); // ldrh w19, [x4, -25] + __ ldrsb(r14, Address(r19, -6)); // ldrsb x14, [x19, -6] + __ ldrsh(r28, Address(r19, -53)); // ldrsh x28, [x19, -53] + __ ldrshw(r14, Address(r27, 13)); // ldrsh w14, [x27, 13] + __ ldrsw(r6, Address(r24, -120)); // ldrsw x6, [x24, -120] + __ ldrd(v18, Address(r2, 87)); // ldr d18, [x2, 87] + __ ldrs(v0, Address(r28, -48)); // ldr s0, [x28, -48] + __ strd(v31, Address(r28, 23)); // str d31, [x28, 23] + __ strs(v11, Address(r25, 43)); // str s11, [x25, 43] // pre // LoadStoreOp - __ str(r29, Address(__ pre(r3, -114))); // str x29, [x3, -114]! - __ strw(r17, Address(__ pre(r4, -72))); // str w17, [x4, -72]! - __ strb(r0, Address(__ pre(r2, -17))); // strb w0, [x2, -17]! - __ strh(r29, Address(__ pre(r1, 7))); // strh w29, [x1, 7]! - __ ldr(r16, Address(__ pre(r21, -133))); // ldr x16, [x21, -133]! - __ ldrw(r20, Address(__ pre(r14, 19))); // ldr w20, [x14, 19]! - __ ldrb(r22, Address(__ pre(r14, -3))); // ldrb w22, [x14, -3]! - __ ldrh(r15, Address(__ pre(r17, 9))); // ldrh w15, [x17, 9]! - __ ldrsb(r10, Address(__ pre(r15, -19))); // ldrsb x10, [x15, -19]! - __ ldrsh(r20, Address(__ pre(r12, -25))); // ldrsh x20, [x12, -25]! - __ ldrshw(r21, Address(__ pre(r10, -29))); // ldrsh w21, [x10, -29]! - __ ldrsw(r19, Address(__ pre(r0, 5))); // ldrsw x19, [x0, 5]! - __ ldrd(v0, Address(__ pre(r14, -54))); // ldr d0, [x14, -54]! - __ ldrs(v3, Address(__ pre(r1, 40))); // ldr s3, [x1, 40]! - __ strd(v4, Address(__ pre(r14, -94))); // str d4, [x14, -94]! - __ strs(v18, Address(__ pre(r28, -54))); // str s18, [x28, -54]! + __ str(r14, Address(__ pre(r8, -185))); // str x14, [x8, -185]! + __ strw(r25, Address(__ pre(r9, -93))); // str w25, [x9, -93]! + __ strb(r16, Address(__ pre(r23, -12))); // strb w16, [x23, -12]! + __ strh(r22, Address(__ pre(r9, -56))); // strh w22, [x9, -56]! + __ ldr(r11, Address(__ pre(r24, 109))); // ldr x11, [x24, 109]! + __ ldrw(r21, Address(__ pre(r19, 52))); // ldr w21, [x19, 52]! + __ ldrb(r6, Address(__ pre(r23, -2))); // ldrb w6, [x23, -2]! + __ ldrh(r7, Address(__ pre(r8, 21))); // ldrh w7, [x8, 21]! + __ ldrsb(r4, Address(__ pre(r12, -31))); // ldrsb x4, [x12, -31]! + __ ldrsh(r8, Address(__ pre(r11, -4))); // ldrsh x8, [x11, -4]! + __ ldrshw(r14, Address(__ pre(r21, -28))); // ldrsh w14, [x21, -28]! + __ ldrsw(r0, Address(__ pre(r15, -71))); // ldrsw x0, [x15, -71]! + __ ldrd(v27, Address(__ pre(r2, 29))); // ldr d27, [x2, 29]! + __ ldrs(v13, Address(__ pre(r21, 16))); // ldr s13, [x21, 16]! + __ strd(v12, Address(__ pre(r27, 16))); // str d12, [x27, 16]! + __ strs(v2, Address(__ pre(r25, -91))); // str s2, [x25, -91]! // post // LoadStoreOp - __ str(r22, Address(__ post(r15, -185))); // str x22, [x15], -185 - __ strw(r17, Address(__ post(r14, -7))); // str w17, [x14], -7 - __ strb(r30, Address(__ post(r11, -25))); // strb w30, [x11], -25 - __ strh(r1, Address(__ post(r11, 20))); // strh w1, [x11], 20 - __ ldr(r22, Address(__ post(r1, 2))); // ldr x22, [x1], 2 - __ ldrw(r2, Address(__ post(r23, -119))); // ldr w2, [x23], -119 - __ ldrb(r3, Address(__ post(r27, -12))); // ldrb w3, [x27], -12 - __ ldrh(r16, Address(__ post(r7, -37))); // ldrh w16, [x7], -37 - __ ldrsb(r15, Address(__ post(r26, 3))); // ldrsb x15, [x26], 3 - __ ldrsh(r7, Address(__ post(r15, -30))); // ldrsh x7, [x15], -30 - __ ldrshw(r3, Address(__ post(r11, -48))); // ldrsh w3, [x11], -48 - __ ldrsw(r25, Address(__ post(r23, 22))); // ldrsw x25, [x23], 22 - __ ldrd(v0, Address(__ post(r10, -215))); // ldr d0, [x10], -215 - __ ldrs(v19, Address(__ post(r6, 55))); // ldr s19, [x6], 55 - __ strd(v14, Address(__ post(r21, -234))); // str d14, [x21], -234 - __ strs(v0, Address(__ post(r22, -70))); // str s0, [x22], -70 + __ str(r10, Address(__ post(r13, -21))); // str x10, [x13], -21 + __ strw(r7, Address(__ post(r1, 50))); // str w7, [x1], 50 + __ strb(r10, Address(__ post(r3, 5))); // strb w10, [x3], 5 + __ strh(r5, Address(__ post(r6, -33))); // strh w5, [x6], -33 + __ ldr(r13, Address(__ post(r22, -158))); // ldr x13, [x22], -158 + __ ldrw(r13, Address(__ post(r2, -106))); // ldr w13, [x2], -106 + __ ldrb(r13, Address(__ post(r16, -24))); // ldrb w13, [x16], -24 + __ ldrh(r24, Address(__ post(r2, -22))); // ldrh w24, [x2], -22 + __ ldrsb(r3, Address(__ post(r23, -1))); // ldrsb x3, [x23], -1 + __ ldrsh(r19, Address(__ post(r8, -43))); // ldrsh x19, [x8], -43 + __ ldrshw(r2, Address(__ post(r23, -8))); // ldrsh w2, [x23], -8 + __ ldrsw(r19, Address(__ post(r28, -87))); // ldrsw x19, [x28], -87 + __ ldrd(v15, Address(__ post(r3, -81))); // ldr d15, [x3], -81 + __ ldrs(v12, Address(__ post(r29, -79))); // ldr s12, [x29], -79 + __ strd(v21, Address(__ post(r1, -124))); // str d21, [x1], -124 + __ strs(v7, Address(__ post(r9, -99))); // str s7, [x9], -99 // base_plus_reg // LoadStoreOp - __ str(r27, Address(r19, r0, Address::sxtx(0))); // str x27, [x19, x0, sxtx #0] - __ strw(r8, Address(r6, r13, Address::lsl(0))); // str w8, [x6, x13, lsl #0] - __ strb(r4, Address(r16, r22, Address::lsl(0))); // strb w4, [x16, x22, lsl #0] - __ strh(r25, Address(r26, r15, Address::uxtw(0))); // strh w25, [x26, w15, uxtw #0] - __ ldr(r4, Address(r5, r24, Address::sxtw(0))); // ldr x4, [x5, w24, sxtw #0] - __ ldrw(r4, Address(r17, r7, Address::uxtw(0))); // ldr w4, [x17, w7, uxtw #0] - __ ldrb(r17, Address(r7, r11, Address::lsl(0))); // ldrb w17, [x7, x11, lsl #0] - __ ldrh(r0, Address(r30, r23, Address::lsl(0))); // ldrh w0, [x30, x23, lsl #0] - __ ldrsb(r10, Address(r22, r1, Address::uxtw(0))); // ldrsb x10, [x22, w1, uxtw #0] - __ ldrsh(r21, Address(r30, r30, Address::sxtw(1))); // ldrsh x21, [x30, w30, sxtw #1] - __ ldrshw(r11, Address(r10, r28, Address::sxtw(1))); // ldrsh w11, [x10, w28, sxtw #1] - __ ldrsw(r28, Address(r19, r10, Address::uxtw(0))); // ldrsw x28, [x19, w10, uxtw #0] - __ ldrd(v30, Address(r29, r14, Address::sxtw(0))); // ldr d30, [x29, w14, sxtw #0] - __ ldrs(v8, Address(r5, r5, Address::sxtw(2))); // ldr s8, [x5, w5, sxtw #2] - __ strd(v25, Address(r8, r13, Address::sxtx(0))); // str d25, [x8, x13, sxtx #0] - __ strs(v17, Address(r24, r26, Address::lsl(2))); // str s17, [x24, x26, lsl #2] + __ str(r5, Address(r20, r2, Address::lsl(0))); // str x5, [x20, x2, lsl #0] + __ strw(r14, Address(r10, r30, Address::sxtw(2))); // str w14, [x10, w30, sxtw #2] + __ strb(r4, Address(r1, r28, Address::sxtw(0))); // strb w4, [x1, w28, sxtw #0] + __ strh(r5, Address(r10, r26, Address::sxtx(1))); // strh w5, [x10, x26, sxtx #1] + __ ldr(r22, Address(r2, r28, Address::lsl(3))); // ldr x22, [x2, x28, lsl #3] + __ ldrw(r12, Address(r0, r28, Address::lsl(2))); // ldr w12, [x0, x28, lsl #2] + __ ldrb(r8, Address(r8, r15, Address::sxtx(0))); // ldrb w8, [x8, x15, sxtx #0] + __ ldrh(r17, Address(r21, r14, Address::uxtw(1))); // ldrh w17, [x21, w14, uxtw #1] + __ ldrsb(r17, Address(r24, r8, Address::sxtx(0))); // ldrsb x17, [x24, x8, sxtx #0] + __ ldrsh(r10, Address(r10, r30, Address::sxtx(1))); // ldrsh x10, [x10, x30, sxtx #1] + __ ldrshw(r17, Address(r23, r0, Address::lsl(1))); // ldrsh w17, [x23, x0, lsl #1] + __ ldrsw(r25, Address(r30, r0, Address::lsl(2))); // ldrsw x25, [x30, x0, lsl #2] + __ ldrd(v5, Address(r24, r23, Address::uxtw(3))); // ldr d5, [x24, w23, uxtw #3] + __ ldrs(v22, Address(r3, r15, Address::lsl(2))); // ldr s22, [x3, x15, lsl #2] + __ strd(v4, Address(r29, r16, Address::sxtx(3))); // str d4, [x29, x16, sxtx #3] + __ strs(v7, Address(r20, r28, Address::sxtw(2))); // str s7, [x20, w28, sxtw #2] // base_plus_scaled_offset // LoadStoreOp - __ str(r19, Address(r12, 15904)); // str x19, [x12, 15904] - __ strw(r23, Address(r15, 7892)); // str w23, [x15, 7892] - __ strb(r29, Address(r13, 1970)); // strb w29, [x13, 1970] - __ strh(r11, Address(r7, 3094)); // strh w11, [x7, 3094] - __ ldr(r10, Address(r24, 14992)); // ldr x10, [x24, 14992] - __ ldrw(r16, Address(r0, 6160)); // ldr w16, [x0, 6160] - __ ldrb(r20, Address(r1, 2032)); // ldrb w20, [x1, 2032] - __ ldrh(r1, Address(r17, 4056)); // ldrh w1, [x17, 4056] - __ ldrsb(r17, Address(r25, 1889)); // ldrsb x17, [x25, 1889] - __ ldrsh(r27, Address(r25, 3964)); // ldrsh x27, [x25, 3964] - __ ldrshw(r14, Address(r17, 3724)); // ldrsh w14, [x17, 3724] - __ ldrsw(r10, Address(r7, 6372)); // ldrsw x10, [x7, 6372] - __ ldrd(v3, Address(r25, 12392)); // ldr d3, [x25, 12392] - __ ldrs(v12, Address(r9, 7840)); // ldr s12, [x9, 7840] - __ strd(v24, Address(r1, 12728)); // str d24, [x1, 12728] - __ strs(v3, Address(r20, 6924)); // str s3, [x20, 6924] + __ str(r27, Address(r0, 16360)); // str x27, [x0, 16360] + __ strw(r21, Address(r8, 7984)); // str w21, [x8, 7984] + __ strb(r17, Address(r29, 1795)); // strb w17, [x29, 1795] + __ strh(r27, Address(r2, 3636)); // strh w27, [x2, 3636] + __ ldr(r1, Address(r1, 12480)); // ldr x1, [x1, 12480] + __ ldrw(r29, Address(r17, 6320)); // ldr w29, [x17, 6320] + __ ldrb(r1, Address(r9, 1634)); // ldrb w1, [x9, 1634] + __ ldrh(r23, Address(r3, 3736)); // ldrh w23, [x3, 3736] + __ ldrsb(r21, Address(r19, 1857)); // ldrsb x21, [x19, 1857] + __ ldrsh(r19, Address(r7, 3180)); // ldrsh x19, [x7, 3180] + __ ldrshw(r10, Address(r1, 3560)); // ldrsh w10, [x1, 3560] + __ ldrsw(r10, Address(r20, 7428)); // ldrsw x10, [x20, 7428] + __ ldrd(v0, Address(r13, 14880)); // ldr d0, [x13, 14880] + __ ldrs(v11, Address(r27, 6356)); // ldr s11, [x27, 6356] + __ strd(v13, Address(r25, 13704)); // str d13, [x25, 13704] + __ strs(v20, Address(r0, 7580)); // str s20, [x0, 7580] // pcrel // LoadStoreOp - __ ldr(r2, back); // ldr x2, back - __ ldrw(r29, __ pc()); // ldr w29, . + __ ldr(r26, __ pc()); // ldr x26, . + __ ldrw(r19, back); // ldr w19, back // LoadStoreOp - __ prfm(Address(r14, 93)); // prfm PLDL1KEEP, [x14, 93] + __ prfm(Address(r8, -111)); // prfm PLDL1KEEP, [x8, -111] // LoadStoreOp - __ prfm(back); // prfm PLDL1KEEP, back + __ prfm(forth); // prfm PLDL1KEEP, forth // LoadStoreOp - __ prfm(Address(r1, r7, Address::lsl(3))); // prfm PLDL1KEEP, [x1, x7, lsl #3] + __ prfm(Address(r7, r7, Address::uxtw(3))); // prfm PLDL1KEEP, [x7, w7, uxtw #3] // LoadStoreOp - __ prfm(Address(r17, 12288)); // prfm PLDL1KEEP, [x17, 12288] + __ prfm(Address(r12, 12600)); // prfm PLDL1KEEP, [x12, 12600] // AddSubCarryOp - __ adcw(r1, r24, r3); // adc w1, w24, w3 - __ adcsw(r17, r24, r20); // adcs w17, w24, w20 - __ sbcw(r11, r0, r13); // sbc w11, w0, w13 - __ sbcsw(r28, r10, r7); // sbcs w28, w10, w7 - __ adc(r4, r15, r16); // adc x4, x15, x16 - __ adcs(r2, r12, r20); // adcs x2, x12, x20 - __ sbc(r29, r13, r13); // sbc x29, x13, x13 - __ sbcs(r14, r6, r12); // sbcs x14, x6, x12 + __ adcw(r24, r20, r11); // adc w24, w20, w11 + __ adcsw(r0, r13, r28); // adcs w0, w13, w28 + __ sbcw(r10, r7, r4); // sbc w10, w7, w4 + __ sbcsw(r15, r16, r2); // sbcs w15, w16, w2 + __ adc(r12, r20, r29); // adc x12, x20, x29 + __ adcs(r13, r13, r14); // adcs x13, x13, x14 + __ sbc(r6, r12, r20); // sbc x6, x12, x20 + __ sbcs(r12, r17, r25); // sbcs x12, x17, x25 // AddSubExtendedOp - __ addw(r20, r12, r17, ext::sxtx, 4); // add w20, w12, w17, sxtx #4 - __ addsw(r27, r11, r0, ext::uxtx, 3); // adds w27, w11, w0, uxtx #3 - __ sub(r7, r1, r9, ext::sxtx, 4); // sub x7, x1, x9, sxtx #4 - __ subsw(r3, r27, r1, ext::uxtb, 3); // subs w3, w27, w1, uxtb #3 - __ add(r13, r26, r12, ext::sxth, 4); // add x13, x26, x12, sxth #4 - __ adds(r17, r5, r10, ext::sxtb, 2); // adds x17, x5, x10, sxtb #2 - __ sub(r30, r8, r15, ext::uxtw, 4); // sub x30, x8, x15, uxtw #4 - __ subs(r19, r23, r19, ext::uxth, 4); // subs x19, x23, x19, uxth #4 + __ addw(r30, r27, r11, ext::sxtb, 1); // add w30, w27, w11, sxtb #1 + __ addsw(r14, r7, r1, ext::sxtw, 2); // adds w14, w7, w1, sxtw #2 + __ sub(r29, r3, r27, ext::sxth, 1); // sub x29, x3, x27, sxth #1 + __ subsw(r0, r13, r26, ext::sxtx, 2); // subs w0, w13, w26, sxtx #2 + __ add(r22, r17, r5, ext::uxtx, 2); // add x22, x17, x5, uxtx #2 + __ adds(r17, r30, r8, ext::sxtx, 3); // adds x17, x30, x8, sxtx #3 + __ sub(r10, r19, r23, ext::sxtw, 3); // sub x10, x19, x23, sxtw #3 + __ subs(r6, r29, r5, ext::uxtw, 3); // subs x6, x29, x5, uxtw #3 // ConditionalCompareOp - __ ccmnw(r29, r5, 10u, Assembler::LO); // ccmn w29, w5, #10, LO - __ ccmpw(r9, r13, 11u, Assembler::LO); // ccmp w9, w13, #11, LO - __ ccmn(r10, r4, 6u, Assembler::HS); // ccmn x10, x4, #6, HS - __ ccmp(r12, r2, 12u, Assembler::HI); // ccmp x12, x2, #12, HI + __ ccmnw(r19, r9, 4u, Assembler::HI); // ccmn w19, w9, #4, HI + __ ccmpw(r22, r10, 2u, Assembler::VC); // ccmp w22, w10, #2, VC + __ ccmn(r13, r12, 10u, Assembler::LS); // ccmn x13, x12, #10, LS + __ ccmp(r24, r16, 3u, Assembler::HS); // ccmp x24, x16, #3, HS // ConditionalCompareImmedOp - __ ccmnw(r16, 6, 2, Assembler::VS); // ccmn w16, #6, #2, VS - __ ccmpw(r7, 11, 13, Assembler::VS); // ccmp w7, #11, #13, VS - __ ccmn(r27, 10, 11, Assembler::LS); // ccmn x27, #10, #11, LS - __ ccmp(r3, 13, 13, Assembler::LE); // ccmp x3, #13, #13, LE + __ ccmnw(r7, 11, 13, Assembler::VS); // ccmn w7, #11, #13, VS + __ ccmpw(r27, 10, 11, Assembler::LS); // ccmp w27, #10, #11, LS + __ ccmn(r3, 13, 13, Assembler::LE); // ccmn x3, #13, #13, LE + __ ccmp(r26, 16, 5, Assembler::GT); // ccmp x26, #16, #5, GT // ConditionalSelectOp - __ cselw(r26, r27, r10, Assembler::VS); // csel w26, w27, w10, VS - __ csincw(r10, r21, r28, Assembler::LE); // csinc w10, w21, w28, LE - __ csinvw(r23, r9, r27, Assembler::LE); // csinv w23, w9, w27, LE - __ csnegw(r10, r29, r15, Assembler::LE); // csneg w10, w29, w15, LE - __ csel(r30, r25, r21, Assembler::HS); // csel x30, x25, x21, HS - __ csinc(r0, r17, r21, Assembler::GT); // csinc x0, x17, x21, GT - __ csinv(r16, r21, r20, Assembler::CS); // csinv x16, x21, x20, CS - __ csneg(r19, r30, r3, Assembler::LS); // csneg x19, x30, x3, LS + __ cselw(r10, r21, r28, Assembler::LE); // csel w10, w21, w28, LE + __ csincw(r23, r9, r27, Assembler::LE); // csinc w23, w9, w27, LE + __ csinvw(r10, r29, r15, Assembler::LE); // csinv w10, w29, w15, LE + __ csnegw(r30, r25, r21, Assembler::HS); // csneg w30, w25, w21, HS + __ csel(r0, r17, r21, Assembler::GT); // csel x0, x17, x21, GT + __ csinc(r16, r21, r20, Assembler::CS); // csinc x16, x21, x20, CS + __ csinv(r19, r30, r3, Assembler::LS); // csinv x19, x30, x3, LS + __ csneg(r19, r11, r24, Assembler::EQ); // csneg x19, x11, x24, EQ // TwoRegOp - __ rbitw(r19, r11); // rbit w19, w11 - __ rev16w(r24, r0); // rev16 w24, w0 - __ revw(r27, r25); // rev w27, w25 - __ clzw(r14, r3); // clz w14, w3 - __ clsw(r14, r17); // cls w14, w17 - __ rbit(r7, r15); // rbit x7, x15 - __ rev16(r24, r28); // rev16 x24, x28 - __ rev32(r17, r25); // rev32 x17, x25 - __ rev(r2, r26); // rev x2, x26 - __ clz(r28, r5); // clz x28, x5 - __ cls(r25, r26); // cls x25, x26 - __ pacia(r27, r16); // pacia x27, x16 - __ pacib(r17, r6); // pacib x17, x6 - __ pacda(r21, r12); // pacda x21, x12 - __ pacdb(r0, r4); // pacdb x0, x4 - __ autia(r12, r27); // autia x12, x27 - __ autib(r17, r28); // autib x17, x28 - __ autda(r28, r2); // autda x28, x2 - __ autdb(r17, r10); // autdb x17, x10 - __ braa(r15, r14); // braa x15, x14 - __ brab(r14, r3); // brab x14, x3 - __ blraa(r25, r15); // blraa x25, x15 - __ blrab(r19, r14); // blrab x19, x14 + __ rbitw(r27, r25); // rbit w27, w25 + __ rev16w(r14, r3); // rev16 w14, w3 + __ revw(r14, r17); // rev w14, w17 + __ clzw(r7, r15); // clz w7, w15 + __ clsw(r24, r28); // cls w24, w28 + __ rbit(r17, r25); // rbit x17, x25 + __ rev16(r2, r26); // rev16 x2, x26 + __ rev32(r28, r5); // rev32 x28, x5 + __ rev(r25, r26); // rev x25, x26 + __ clz(r27, r16); // clz x27, x16 + __ cls(r17, r6); // cls x17, x6 + __ pacia(r21, r12); // pacia x21, x12 + __ pacib(r0, r4); // pacib x0, x4 + __ pacda(r12, r27); // pacda x12, x27 + __ pacdb(r17, r28); // pacdb x17, x28 + __ autia(r28, r2); // autia x28, x2 + __ autib(r17, r10); // autib x17, x10 + __ autda(r15, r14); // autda x15, x14 + __ autdb(r14, r3); // autdb x14, x3 + __ braa(r25, r15); // braa x25, x15 + __ brab(r19, r14); // brab x19, x14 + __ blraa(r5, r16); // blraa x5, x16 + __ blrab(r4, r26); // blrab x4, x26 // ThreeRegOp - __ udivw(r5, r16, r4); // udiv w5, w16, w4 - __ sdivw(r26, r25, r4); // sdiv w26, w25, w4 - __ lslvw(r2, r2, r12); // lslv w2, w2, w12 - __ lsrvw(r29, r17, r8); // lsrv w29, w17, w8 - __ asrvw(r7, r3, r4); // asrv w7, w3, w4 - __ rorvw(r25, r4, r26); // rorv w25, w4, w26 - __ udiv(r25, r4, r17); // udiv x25, x4, x17 - __ sdiv(r0, r26, r17); // sdiv x0, x26, x17 - __ lslv(r23, r15, r21); // lslv x23, x15, x21 - __ lsrv(r28, r17, r27); // lsrv x28, x17, x27 - __ asrv(r10, r3, r0); // asrv x10, x3, x0 - __ rorv(r7, r25, r9); // rorv x7, x25, x9 - __ umulh(r6, r15, r29); // umulh x6, x15, x29 - __ smulh(r15, r10, r2); // smulh x15, x10, x2 + __ udivw(r25, r4, r2); // udiv w25, w4, w2 + __ sdivw(r2, r12, r29); // sdiv w2, w12, w29 + __ lslvw(r17, r8, r7); // lslv w17, w8, w7 + __ lsrvw(r3, r4, r25); // lsrv w3, w4, w25 + __ asrvw(r4, r26, r25); // asrv w4, w26, w25 + __ rorvw(r4, r17, r0); // rorv w4, w17, w0 + __ udiv(r26, r17, r23); // udiv x26, x17, x23 + __ sdiv(r15, r21, r28); // sdiv x15, x21, x28 + __ lslv(r17, r27, r10); // lslv x17, x27, x10 + __ lsrv(r3, r0, r7); // lsrv x3, x0, x7 + __ asrv(r25, r9, r6); // asrv x25, x9, x6 + __ rorv(r15, r29, r15); // rorv x15, x29, x15 + __ umulh(r10, r2, r17); // umulh x10, x2, x17 + __ smulh(r7, r11, r11); // smulh x7, x11, x11 // FourRegMulOp - __ maddw(r17, r7, r11, r11); // madd w17, w7, w11, w11 - __ msubw(r23, r7, r29, r23); // msub w23, w7, w29, w23 - __ madd(r14, r27, r11, r11); // madd x14, x27, x11, x11 - __ msub(r4, r24, r12, r15); // msub x4, x24, x12, x15 - __ smaddl(r14, r20, r11, r28); // smaddl x14, w20, w11, x28 - __ smsubl(r13, r11, r12, r23); // smsubl x13, w11, w12, x23 - __ umaddl(r30, r26, r14, r9); // umaddl x30, w26, w14, x9 - __ umsubl(r13, r10, r7, r5); // umsubl x13, w10, w7, x5 + __ maddw(r23, r7, r29, r23); // madd w23, w7, w29, w23 + __ msubw(r14, r27, r11, r11); // msub w14, w27, w11, w11 + __ madd(r4, r24, r12, r15); // madd x4, x24, x12, x15 + __ msub(r14, r20, r11, r28); // msub x14, x20, x11, x28 + __ smaddl(r13, r11, r12, r23); // smaddl x13, w11, w12, x23 + __ smsubl(r30, r26, r14, r9); // smsubl x30, w26, w14, x9 + __ umaddl(r13, r10, r7, r5); // umaddl x13, w10, w7, x5 + __ umsubl(r29, r15, r3, r11); // umsubl x29, w15, w3, x11 // ThreeRegFloatOp - __ fabdh(v30, v15, v3); // fabd h30, h15, h3 - __ fmulh(v12, v12, v16); // fmul h12, h12, h16 - __ fdivh(v31, v31, v18); // fdiv h31, h31, h18 - __ faddh(v19, v21, v16); // fadd h19, h21, h16 - __ fsubh(v15, v10, v21); // fsub h15, h10, h21 - __ fmaxh(v2, v10, v28); // fmax h2, h10, h28 - __ fminh(v7, v30, v31); // fmin h7, h30, h31 - __ fnmulh(v18, v1, v2); // fnmul h18, h1, h2 - __ fabds(v6, v10, v3); // fabd s6, s10, s3 - __ fmuls(v25, v11, v7); // fmul s25, s11, s7 - __ fdivs(v1, v12, v0); // fdiv s1, s12, s0 - __ fadds(v3, v19, v29); // fadd s3, s19, s29 - __ fsubs(v6, v23, v6); // fsub s6, s23, s6 - __ fmaxs(v0, v28, v27); // fmax s0, s28, s27 - __ fmins(v2, v5, v7); // fmin s2, s5, s7 - __ fnmuls(v29, v12, v25); // fnmul s29, s12, s25 - __ fabdd(v13, v12, v24); // fabd d13, d12, d24 - __ fmuld(v19, v8, v18); // fmul d19, d8, d18 - __ fdivd(v22, v26, v21); // fdiv d22, d26, d21 - __ faddd(v20, v19, v2); // fadd d20, d19, d2 - __ fsubd(v30, v22, v8); // fsub d30, d22, d8 - __ fmaxd(v22, v19, v21); // fmax d22, d19, d21 - __ fmind(v12, v18, v21); // fmin d12, d18, d21 - __ fnmuld(v6, v16, v3); // fnmul d6, d16, d3 + __ fabdh(v12, v16, v31); // fabd h12, h16, h31 + __ fmulh(v31, v18, v19); // fmul h31, h18, h19 + __ fdivh(v21, v16, v15); // fdiv h21, h16, h15 + __ faddh(v10, v21, v2); // fadd h10, h21, h2 + __ fsubh(v10, v28, v7); // fsub h10, h28, h7 + __ fmaxh(v30, v31, v18); // fmax h30, h31, h18 + __ fminh(v1, v2, v6); // fmin h1, h2, h6 + __ fnmulh(v10, v3, v25); // fnmul h10, h3, h25 + __ fabds(v11, v7, v1); // fabd s11, s7, s1 + __ fmuls(v12, v0, v3); // fmul s12, s0, s3 + __ fdivs(v19, v29, v6); // fdiv s19, s29, s6 + __ fadds(v23, v6, v0); // fadd s23, s6, s0 + __ fsubs(v28, v27, v2); // fsub s28, s27, s2 + __ fmaxs(v5, v7, v29); // fmax s5, s7, s29 + __ fmins(v12, v25, v13); // fmin s12, s25, s13 + __ fnmuls(v12, v24, v19); // fnmul s12, s24, s19 + __ fabdd(v8, v18, v22); // fabd d8, d18, d22 + __ fmuld(v26, v21, v20); // fmul d26, d21, d20 + __ fdivd(v19, v2, v30); // fdiv d19, d2, d30 + __ faddd(v22, v8, v22); // fadd d22, d8, d22 + __ fsubd(v19, v21, v12); // fsub d19, d21, d12 + __ fmaxd(v18, v21, v6); // fmax d18, d21, d6 + __ fmind(v16, v3, v3); // fmin d16, d3, d3 + __ fnmuld(v29, v3, v28); // fnmul d29, d3, d28 // FourRegFloatOp - __ fmaddh(v3, v29, v3, v28); // fmadd h3, h29, h3, h28 - __ fmadds(v15, v14, v10, v13); // fmadd s15, s14, s10, s13 - __ fmsubs(v12, v18, v10, v26); // fmsub s12, s18, s10, s26 - __ fnmadds(v7, v7, v15, v29); // fnmadd s7, s7, s15, s29 + __ fmaddh(v15, v14, v10, v13); // fmadd h15, h14, h10, h13 + __ fmadds(v12, v18, v10, v26); // fmadd s12, s18, s10, s26 + __ fmsubs(v7, v7, v15, v29); // fmsub s7, s7, s15, s29 __ fnmadds(v0, v23, v0, v12); // fnmadd s0, s23, s0, s12 - __ fmaddd(v24, v14, v13, v8); // fmadd d24, d14, d13, d8 - __ fmsubd(v15, v7, v9, v20); // fmsub d15, d7, d9, d20 - __ fnmaddd(v19, v29, v31, v16); // fnmadd d19, d29, d31, d16 + __ fnmadds(v24, v14, v13, v8); // fnmadd s24, s14, s13, s8 + __ fmaddd(v15, v7, v9, v20); // fmadd d15, d7, d9, d20 + __ fmsubd(v19, v29, v31, v16); // fmsub d19, d29, d31, d16 __ fnmaddd(v2, v9, v16, v21); // fnmadd d2, d9, d16, d21 + __ fnmaddd(v30, v4, v1, v27); // fnmadd d30, d4, d1, d27 // TwoRegFloatOp - __ fmovs(v30, v4); // fmov s30, s4 - __ fabss(v1, v27); // fabs s1, s27 - __ fnegs(v25, v24); // fneg s25, s24 - __ fsqrts(v14, v21); // fsqrt s14, s21 - __ fcvts(v13, v6); // fcvt d13, s6 - __ fcvtsh(v12, v25); // fcvt h12, s25 - __ fcvths(v25, v30); // fcvt s25, h30 - __ fmovd(v28, v21); // fmov d28, d21 - __ fabsd(v16, v23); // fabs d16, d23 - __ fnegd(v5, v29); // fneg d5, d29 - __ fsqrtd(v22, v19); // fsqrt d22, d19 - __ fcvtd(v13, v20); // fcvt s13, d20 - __ fsqrth(v19, v28); // fsqrt h19, h28 + __ fmovs(v25, v24); // fmov s25, s24 + __ fabss(v14, v21); // fabs s14, s21 + __ fnegs(v13, v6); // fneg s13, s6 + __ fsqrts(v12, v25); // fsqrt s12, s25 + __ fcvts(v25, v30); // fcvt d25, s30 + __ fcvtsh(v28, v21); // fcvt h28, s21 + __ fcvths(v16, v23); // fcvt s16, h23 + __ fmovd(v5, v29); // fmov d5, d29 + __ fabsd(v22, v19); // fabs d22, d19 + __ fnegd(v13, v20); // fneg d13, d20 + __ fsqrtd(v19, v28); // fsqrt d19, d28 + __ fcvtd(v18, v6); // fcvt s18, d6 + __ fsqrth(v14, v7); // fsqrt h14, h7 // FloatConvertOp - __ fcvtzsw(r17, v6); // fcvtzs w17, s6 - __ fcvtzs(r13, v7); // fcvtzs x13, s7 - __ fcvtzdw(r28, v26); // fcvtzs w28, d26 - __ fcvtzd(r17, v6); // fcvtzs x17, d6 - __ scvtfws(v1, r4); // scvtf s1, w4 - __ scvtfs(v14, r20); // scvtf s14, x20 - __ scvtfwd(v7, r21); // scvtf d7, w21 - __ scvtfd(v27, r23); // scvtf d27, x23 - __ fcvtassw(r13, v20); // fcvtas w13, s20 - __ fcvtasd(r30, v28); // fcvtas x30, d28 - __ fcvtmssw(r10, v21); // fcvtms w10, s21 - __ fcvtmsd(r5, v17); // fcvtms x5, d17 - __ fmovs(r11, v14); // fmov w11, s14 - __ fmovd(r13, v21); // fmov x13, d21 - __ fmovs(v27, r14); // fmov s27, w14 - __ fmovd(v4, r23); // fmov d4, x23 + __ fcvtzsw(r28, v26); // fcvtzs w28, s26 + __ fcvtzs(r17, v6); // fcvtzs x17, s6 + __ fcvtzdw(r1, v4); // fcvtzs w1, d4 + __ fcvtzd(r13, v21); // fcvtzs x13, d21 + __ scvtfws(v7, r21); // scvtf s7, w21 + __ scvtfs(v27, r23); // scvtf s27, x23 + __ scvtfwd(v13, r20); // scvtf d13, w20 + __ scvtfd(v31, r27); // scvtf d31, x27 + __ fcvtassw(r10, v21); // fcvtas w10, s21 + __ fcvtasd(r5, v17); // fcvtas x5, d17 + __ fcvtmssw(r11, v14); // fcvtms w11, s14 + __ fcvtmsd(r13, v21); // fcvtms x13, d21 + __ fmovs(r26, v14); // fmov w26, s14 + __ fmovd(r4, v24); // fmov x4, d24 + __ fmovs(v24, r29); // fmov s24, w29 + __ fmovd(v12, r14); // fmov d12, x14 // TwoRegFloatOp - __ fcmps(v24, v30); // fcmp s24, s30 - __ fcmpd(v12, v14); // fcmp d12, d14 - __ fcmps(v17, 0.0); // fcmp s17, #0.0 - __ fcmpd(v28, 0.0); // fcmp d28, #0.0 + __ fcmps(v17, v28); // fcmp s17, s28 + __ fcmpd(v22, v0); // fcmp d22, d0 + __ fcmps(v6, 0.0); // fcmp s6, #0.0 + __ fcmpd(v27, 0.0); // fcmp d27, #0.0 // LoadStorePairOp - __ stpw(r0, r6, Address(r26, 16)); // stp w0, w6, [x26, #16] - __ ldpw(r0, r30, Address(r6, -32)); // ldp w0, w30, [x6, #-32] - __ ldpsw(r16, r2, Address(r11, -208)); // ldpsw x16, x2, [x11, #-208] - __ stp(r15, r0, Address(r12, 128)); // stp x15, x0, [x12, #128] - __ ldp(r7, r30, Address(r23, 32)); // ldp x7, x30, [x23, #32] + __ stpw(r27, r12, Address(r6, -32)); // stp w27, w12, [x6, #-32] + __ ldpw(r14, r11, Address(r19, -256)); // ldp w14, w11, [x19, #-256] + __ ldpsw(r0, r12, Address(r15, -48)); // ldpsw x0, x12, [x15, #-48] + __ stp(r9, r23, Address(r23, 32)); // stp x9, x23, [x23, #32] + __ ldp(r15, r4, Address(r26, -176)); // ldp x15, x4, [x26, #-176] // LoadStorePairOp - __ stpw(r26, r15, Address(__ pre(r7, -256))); // stp w26, w15, [x7, #-256]! - __ ldpw(r11, r15, Address(__ pre(r10, -32))); // ldp w11, w15, [x10, #-32]! - __ ldpsw(r19, r16, Address(__ pre(r1, 64))); // ldpsw x19, x16, [x1, #64]! - __ stp(r14, r9, Address(__ pre(r0, 128))); // stp x14, x9, [x0, #128]! - __ ldp(r27, r3, Address(__ pre(r12, -96))); // ldp x27, x3, [x12, #-96]! + __ stpw(r17, r8, Address(__ pre(r6, -160))); // stp w17, w8, [x6, #-160]! + __ ldpw(r7, r2, Address(__ pre(r4, -112))); // ldp w7, w2, [x4, #-112]! + __ ldpsw(r14, r9, Address(__ pre(r22, -16))); // ldpsw x14, x9, [x22, #-16]! + __ stp(r13, r20, Address(__ pre(r24, -256))); // stp x13, x20, [x24, #-256]! + __ ldp(r8, r11, Address(__ pre(r10, 96))); // ldp x8, x11, [x10, #96]! // LoadStorePairOp - __ stpw(r8, r11, Address(__ post(r12, -256))); // stp w8, w11, [x12], #-256 - __ ldpw(r10, r16, Address(__ post(r4, 64))); // ldp w10, w16, [x4], #64 - __ ldpsw(r10, r30, Address(__ post(r19, -64))); // ldpsw x10, x30, [x19], #-64 - __ stp(r24, r2, Address(__ post(r15, -96))); // stp x24, x2, [x15], #-96 - __ ldp(r24, r10, Address(__ post(r16, 80))); // ldp x24, x10, [x16], #80 + __ stpw(r24, r5, Address(__ post(r16, -112))); // stp w24, w5, [x16], #-112 + __ ldpw(r0, r26, Address(__ post(r9, -128))); // ldp w0, w26, [x9], #-128 + __ ldpsw(r24, r2, Address(__ post(r17, -128))); // ldpsw x24, x2, [x17], #-128 + __ stp(r26, r17, Address(__ post(r14, -48))); // stp x26, x17, [x14], #-48 + __ ldp(r30, r21, Address(__ post(r29, 48))); // ldp x30, x21, [x29], #48 // LoadStorePairOp - __ stnpw(r30, r21, Address(r29, 16)); // stnp w30, w21, [x29, #16] - __ ldnpw(r8, r30, Address(r10, -112)); // ldnp w8, w30, [x10, #-112] - __ stnp(r30, r26, Address(r6, -128)); // stnp x30, x26, [x6, #-128] - __ ldnp(r24, r2, Address(r20, 64)); // ldnp x24, x2, [x20, #64] + __ stnpw(r17, r23, Address(r10, -112)); // stnp w17, w23, [x10, #-112] + __ ldnpw(r26, r6, Address(r30, -160)); // ldnp w26, w6, [x30, #-160] + __ stnp(r30, r8, Address(r20, 64)); // stnp x30, x8, [x20, #64] + __ ldnp(r22, r29, Address(r9, 48)); // ldnp x22, x29, [x9, #48] // LdStNEONOp - __ ld1(v31, __ T8B, Address(r25)); // ld1 {v31.8B}, [x25] - __ ld1(v5, v6, __ T16B, Address(__ post(r15, 32))); // ld1 {v5.16B, v6.16B}, [x15], 32 - __ ld1(v10, v11, v12, __ T1D, Address(__ post(r7, r13))); // ld1 {v10.1D, v11.1D, v12.1D}, [x7], x13 - __ ld1(v13, v14, v15, v16, __ T8H, Address(__ post(r16, 64))); // ld1 {v13.8H, v14.8H, v15.8H, v16.8H}, [x16], 64 - __ ld1r(v7, __ T8B, Address(r17)); // ld1r {v7.8B}, [x17] - __ ld1r(v16, __ T4S, Address(__ post(r25, 4))); // ld1r {v16.4S}, [x25], 4 - __ ld1r(v11, __ T1D, Address(__ post(r3, r7))); // ld1r {v11.1D}, [x3], x7 - __ ld2(v13, v14, __ T2D, Address(r7)); // ld2 {v13.2D, v14.2D}, [x7] - __ ld2(v9, v10, __ T4H, Address(__ post(r27, 16))); // ld2 {v9.4H, v10.4H}, [x27], 16 - __ ld2r(v6, v7, __ T16B, Address(r26)); // ld2r {v6.16B, v7.16B}, [x26] - __ ld2r(v23, v24, __ T2S, Address(__ post(r16, 8))); // ld2r {v23.2S, v24.2S}, [x16], 8 - __ ld2r(v6, v7, __ T2D, Address(__ post(r13, r8))); // ld2r {v6.2D, v7.2D}, [x13], x8 - __ ld3(v20, v21, v22, __ T4S, Address(__ post(r1, r26))); // ld3 {v20.4S, v21.4S, v22.4S}, [x1], x26 - __ ld3(v15, v16, v17, __ T2S, Address(r15)); // ld3 {v15.2S, v16.2S, v17.2S}, [x15] - __ ld3r(v29, v30, v31, __ T8H, Address(r22)); // ld3r {v29.8H, v30.8H, v31.8H}, [x22] - __ ld3r(v6, v7, v8, __ T4S, Address(__ post(r10, 12))); // ld3r {v6.4S, v7.4S, v8.4S}, [x10], 12 - __ ld3r(v15, v16, v17, __ T1D, Address(__ post(r6, r15))); // ld3r {v15.1D, v16.1D, v17.1D}, [x6], x15 - __ ld4(v6, v7, v8, v9, __ T8H, Address(__ post(r10, 64))); // ld4 {v6.8H, v7.8H, v8.8H, v9.8H}, [x10], 64 - __ ld4(v11, v12, v13, v14, __ T8B, Address(__ post(r3, r7))); // ld4 {v11.8B, v12.8B, v13.8B, v14.8B}, [x3], x7 - __ ld4r(v12, v13, v14, v15, __ T8B, Address(r25)); // ld4r {v12.8B, v13.8B, v14.8B, v15.8B}, [x25] - __ ld4r(v11, v12, v13, v14, __ T4H, Address(__ post(r15, 8))); // ld4r {v11.4H, v12.4H, v13.4H, v14.4H}, [x15], 8 - __ ld4r(v30, v31, v0, v1, __ T2S, Address(__ post(r6, r28))); // ld4r {v30.2S, v31.2S, v0.2S, v1.2S}, [x6], x28 + __ ld1(v13, __ T8B, Address(r1)); // ld1 {v13.8B}, [x1] + __ ld1(v1, v2, __ T16B, Address(__ post(r16, 32))); // ld1 {v1.16B, v2.16B}, [x16], 32 + __ ld1(v22, v23, v24, __ T1D, Address(__ post(r25, r19))); // ld1 {v22.1D, v23.1D, v24.1D}, [x25], x19 + __ ld1(v25, v26, v27, v28, __ T8H, Address(__ post(r26, 64))); // ld1 {v25.8H, v26.8H, v27.8H, v28.8H}, [x26], 64 + __ ld1r(v9, __ T8B, Address(r15)); // ld1r {v9.8B}, [x15] + __ ld1r(v12, __ T4S, Address(__ post(r25, 4))); // ld1r {v12.4S}, [x25], 4 + __ ld1r(v4, __ T1D, Address(__ post(r14, r29))); // ld1r {v4.1D}, [x14], x29 + __ ld2(v17, v18, __ T2D, Address(r17)); // ld2 {v17.2D, v18.2D}, [x17] + __ ld2(v23, v24, __ T4H, Address(__ post(r27, 16))); // ld2 {v23.4H, v24.4H}, [x27], 16 + __ ld2r(v2, v3, __ T16B, Address(r24)); // ld2r {v2.16B, v3.16B}, [x24] + __ ld2r(v11, v12, __ T2S, Address(__ post(r0, 8))); // ld2r {v11.2S, v12.2S}, [x0], 8 + __ ld2r(v2, v3, __ T2D, Address(__ post(r12, r22))); // ld2r {v2.2D, v3.2D}, [x12], x22 + __ ld3(v21, v22, v23, __ T4S, Address(__ post(r13, r13))); // ld3 {v21.4S, v22.4S, v23.4S}, [x13], x13 + __ ld3(v12, v13, v14, __ T2S, Address(r11)); // ld3 {v12.2S, v13.2S, v14.2S}, [x11] + __ ld3r(v18, v19, v20, __ T8H, Address(r14)); // ld3r {v18.8H, v19.8H, v20.8H}, [x14] + __ ld3r(v25, v26, v27, __ T4S, Address(__ post(r21, 12))); // ld3r {v25.4S, v26.4S, v27.4S}, [x21], 12 + __ ld3r(v20, v21, v22, __ T1D, Address(__ post(r16, r27))); // ld3r {v20.1D, v21.1D, v22.1D}, [x16], x27 + __ ld4(v0, v1, v2, v3, __ T8H, Address(__ post(r1, 64))); // ld4 {v0.8H, v1.8H, v2.8H, v3.8H}, [x1], 64 + __ ld4(v0, v1, v2, v3, __ T8B, Address(__ post(r27, r29))); // ld4 {v0.8B, v1.8B, v2.8B, v3.8B}, [x27], x29 + __ ld4r(v18, v19, v20, v21, __ T8B, Address(r17)); // ld4r {v18.8B, v19.8B, v20.8B, v21.8B}, [x17] + __ ld4r(v5, v6, v7, v8, __ T4H, Address(__ post(r24, 8))); // ld4r {v5.4H, v6.4H, v7.4H, v8.4H}, [x24], 8 + __ ld4r(v28, v29, v30, v31, __ T2S, Address(__ post(r5, r20))); // ld4r {v28.2S, v29.2S, v30.2S, v31.2S}, [x5], x20 // NEONReduceInstruction - __ addv(v27, __ T8B, v28); // addv b27, v28.8B - __ addv(v28, __ T16B, v29); // addv b28, v29.16B - __ addv(v1, __ T4H, v2); // addv h1, v2.4H - __ addv(v28, __ T8H, v29); // addv h28, v29.8H - __ addv(v1, __ T4S, v2); // addv s1, v2.4S - __ smaxv(v20, __ T8B, v21); // smaxv b20, v21.8B + __ addv(v1, __ T8B, v2); // addv b1, v2.8B + __ addv(v20, __ T16B, v21); // addv b20, v21.16B + __ addv(v29, __ T4H, v30); // addv h29, v30.4H + __ addv(v16, __ T8H, v17); // addv h16, v17.8H + __ addv(v13, __ T4S, v14); // addv s13, v14.4S + __ smaxv(v10, __ T8B, v11); // smaxv b10, v11.8B __ smaxv(v29, __ T16B, v30); // smaxv b29, v30.16B - __ smaxv(v16, __ T4H, v17); // smaxv h16, v17.4H - __ smaxv(v13, __ T8H, v14); // smaxv h13, v14.8H - __ smaxv(v10, __ T4S, v11); // smaxv s10, v11.4S - __ fmaxv(v29, __ T4S, v30); // fmaxv s29, v30.4S - __ sminv(v29, __ T8B, v30); // sminv b29, v30.8B - __ uminv(v19, __ T8B, v20); // uminv b19, v20.8B - __ sminv(v22, __ T16B, v23); // sminv b22, v23.16B - __ uminv(v10, __ T16B, v11); // uminv b10, v11.16B - __ sminv(v4, __ T4H, v5); // sminv h4, v5.4H - __ uminv(v31, __ T4H, v0); // uminv h31, v0.4H - __ sminv(v21, __ T8H, v22); // sminv h21, v22.8H - __ uminv(v8, __ T8H, v9); // uminv h8, v9.8H - __ sminv(v31, __ T4S, v0); // sminv s31, v0.4S - __ uminv(v19, __ T4S, v20); // uminv s19, v20.4S - __ fminv(v10, __ T4S, v11); // fminv s10, v11.4S - __ fmaxp(v28, v29, __ S); // fmaxp s28, v29.2S - __ fmaxp(v2, v3, __ D); // fmaxp d2, v3.2D - __ fminp(v25, v26, __ S); // fminp s25, v26.2S - __ fminp(v5, v6, __ D); // fminp d5, v6.2D + __ smaxv(v29, __ T4H, v30); // smaxv h29, v30.4H + __ smaxv(v19, __ T8H, v20); // smaxv h19, v20.8H + __ smaxv(v22, __ T4S, v23); // smaxv s22, v23.4S + __ fmaxv(v10, __ T4S, v11); // fmaxv s10, v11.4S + __ sminv(v4, __ T8B, v5); // sminv b4, v5.8B + __ uminv(v31, __ T8B, v0); // uminv b31, v0.8B + __ sminv(v21, __ T16B, v22); // sminv b21, v22.16B + __ uminv(v8, __ T16B, v9); // uminv b8, v9.16B + __ sminv(v31, __ T4H, v0); // sminv h31, v0.4H + __ uminv(v19, __ T4H, v20); // uminv h19, v20.4H + __ sminv(v10, __ T8H, v11); // sminv h10, v11.8H + __ uminv(v28, __ T8H, v29); // uminv h28, v29.8H + __ sminv(v2, __ T4S, v3); // sminv s2, v3.4S + __ uminv(v25, __ T4S, v26); // uminv s25, v26.4S + __ fminv(v5, __ T4S, v6); // fminv s5, v6.4S + __ fmaxp(v3, v4, __ S); // fmaxp s3, v4.2S + __ fmaxp(v8, v9, __ D); // fmaxp d8, v9.2D + __ fminp(v22, v23, __ S); // fminp s22, v23.2S + __ fminp(v19, v20, __ D); // fminp d19, v20.2D // NEONFloatCompareWithZero - __ fcm(Assembler::GT, v3, __ T2S, v4); // fcmgt v3.2S, v4.2S, #0.0 - __ fcm(Assembler::GT, v8, __ T4S, v9); // fcmgt v8.4S, v9.4S, #0.0 - __ fcm(Assembler::GT, v22, __ T2D, v23); // fcmgt v22.2D, v23.2D, #0.0 - __ fcm(Assembler::GE, v19, __ T2S, v20); // fcmge v19.2S, v20.2S, #0.0 - __ fcm(Assembler::GE, v13, __ T4S, v14); // fcmge v13.4S, v14.4S, #0.0 - __ fcm(Assembler::GE, v5, __ T2D, v6); // fcmge v5.2D, v6.2D, #0.0 - __ fcm(Assembler::EQ, v29, __ T2S, v30); // fcmeq v29.2S, v30.2S, #0.0 - __ fcm(Assembler::EQ, v24, __ T4S, v25); // fcmeq v24.4S, v25.4S, #0.0 - __ fcm(Assembler::EQ, v21, __ T2D, v22); // fcmeq v21.2D, v22.2D, #0.0 + __ fcm(Assembler::GT, v13, __ T2S, v14); // fcmgt v13.2S, v14.2S, #0.0 + __ fcm(Assembler::GT, v5, __ T4S, v6); // fcmgt v5.4S, v6.4S, #0.0 + __ fcm(Assembler::GT, v29, __ T2D, v30); // fcmgt v29.2D, v30.2D, #0.0 + __ fcm(Assembler::GE, v24, __ T2S, v25); // fcmge v24.2S, v25.2S, #0.0 + __ fcm(Assembler::GE, v21, __ T4S, v22); // fcmge v21.4S, v22.4S, #0.0 + __ fcm(Assembler::GE, v26, __ T2D, v27); // fcmge v26.2D, v27.2D, #0.0 + __ fcm(Assembler::EQ, v24, __ T2S, v25); // fcmeq v24.2S, v25.2S, #0.0 + __ fcm(Assembler::EQ, v3, __ T4S, v4); // fcmeq v3.4S, v4.4S, #0.0 + __ fcm(Assembler::EQ, v24, __ T2D, v25); // fcmeq v24.2D, v25.2D, #0.0 __ fcm(Assembler::LT, v26, __ T2S, v27); // fcmlt v26.2S, v27.2S, #0.0 - __ fcm(Assembler::LT, v24, __ T4S, v25); // fcmlt v24.4S, v25.4S, #0.0 - __ fcm(Assembler::LT, v3, __ T2D, v4); // fcmlt v3.2D, v4.2D, #0.0 - __ fcm(Assembler::LE, v24, __ T2S, v25); // fcmle v24.2S, v25.2S, #0.0 - __ fcm(Assembler::LE, v26, __ T4S, v27); // fcmle v26.4S, v27.4S, #0.0 - __ fcm(Assembler::LE, v23, __ T2D, v24); // fcmle v23.2D, v24.2D, #0.0 + __ fcm(Assembler::LT, v23, __ T4S, v24); // fcmlt v23.4S, v24.4S, #0.0 + __ fcm(Assembler::LT, v15, __ T2D, v16); // fcmlt v15.2D, v16.2D, #0.0 + __ fcm(Assembler::LE, v21, __ T2S, v22); // fcmle v21.2S, v22.2S, #0.0 + __ fcm(Assembler::LE, v3, __ T4S, v4); // fcmle v3.4S, v4.4S, #0.0 + __ fcm(Assembler::LE, v24, __ T2D, v25); // fcmle v24.2D, v25.2D, #0.0 // TwoRegNEONOp - __ absr(v15, __ T8B, v16); // abs v15.8B, v16.8B - __ absr(v21, __ T16B, v22); // abs v21.16B, v22.16B - __ absr(v3, __ T4H, v4); // abs v3.4H, v4.4H - __ absr(v24, __ T8H, v25); // abs v24.8H, v25.8H - __ absr(v8, __ T2S, v9); // abs v8.2S, v9.2S - __ absr(v25, __ T4S, v26); // abs v25.4S, v26.4S - __ absr(v20, __ T2D, v21); // abs v20.2D, v21.2D - __ fabs(v16, __ T2S, v17); // fabs v16.2S, v17.2S - __ fabs(v17, __ T4S, v18); // fabs v17.4S, v18.4S - __ fabs(v2, __ T2D, v3); // fabs v2.2D, v3.2D - __ fabs(v1, __ T4H, v2); // fabs v1.4H, v2.4H - __ fabs(v0, __ T8H, v1); // fabs v0.8H, v1.8H - __ fneg(v24, __ T2S, v25); // fneg v24.2S, v25.2S - __ fneg(v4, __ T4S, v5); // fneg v4.4S, v5.4S - __ fneg(v3, __ T2D, v4); // fneg v3.2D, v4.2D - __ fneg(v12, __ T4H, v13); // fneg v12.4H, v13.4H - __ fneg(v31, __ T8H, v0); // fneg v31.8H, v0.8H - __ fsqrt(v28, __ T2S, v29); // fsqrt v28.2S, v29.2S - __ fsqrt(v10, __ T4S, v11); // fsqrt v10.4S, v11.4S - __ fsqrt(v26, __ T2D, v27); // fsqrt v26.2D, v27.2D - __ fsqrt(v2, __ T4H, v3); // fsqrt v2.4H, v3.4H - __ fsqrt(v12, __ T8H, v13); // fsqrt v12.8H, v13.8H - __ notr(v18, __ T8B, v19); // not v18.8B, v19.8B - __ notr(v31, __ T16B, v0); // not v31.16B, v0.16B + __ absr(v8, __ T8B, v9); // abs v8.8B, v9.8B + __ absr(v25, __ T16B, v26); // abs v25.16B, v26.16B + __ absr(v20, __ T4H, v21); // abs v20.4H, v21.4H + __ absr(v16, __ T8H, v17); // abs v16.8H, v17.8H + __ absr(v17, __ T2S, v18); // abs v17.2S, v18.2S + __ absr(v2, __ T4S, v3); // abs v2.4S, v3.4S + __ absr(v1, __ T2D, v2); // abs v1.2D, v2.2D + __ fabs(v0, __ T2S, v1); // fabs v0.2S, v1.2S + __ fabs(v24, __ T4S, v25); // fabs v24.4S, v25.4S + __ fabs(v4, __ T2D, v5); // fabs v4.2D, v5.2D + __ fabs(v3, __ T4H, v4); // fabs v3.4H, v4.4H + __ fabs(v12, __ T8H, v13); // fabs v12.8H, v13.8H + __ fneg(v31, __ T2S, v0); // fneg v31.2S, v0.2S + __ fneg(v28, __ T4S, v29); // fneg v28.4S, v29.4S + __ fneg(v10, __ T2D, v11); // fneg v10.2D, v11.2D + __ fneg(v26, __ T4H, v27); // fneg v26.4H, v27.4H + __ fneg(v2, __ T8H, v3); // fneg v2.8H, v3.8H + __ fsqrt(v12, __ T2S, v13); // fsqrt v12.2S, v13.2S + __ fsqrt(v18, __ T4S, v19); // fsqrt v18.4S, v19.4S + __ fsqrt(v31, __ T2D, v0); // fsqrt v31.2D, v0.2D + __ fsqrt(v1, __ T4H, v2); // fsqrt v1.4H, v2.4H + __ fsqrt(v13, __ T8H, v14); // fsqrt v13.8H, v14.8H + __ notr(v29, __ T8B, v30); // not v29.8B, v30.8B + __ notr(v0, __ T16B, v1); // not v0.16B, v1.16B // ThreeRegNEONOp - __ andr(v1, __ T8B, v2, v3); // and v1.8B, v2.8B, v3.8B - __ andr(v13, __ T16B, v14, v15); // and v13.16B, v14.16B, v15.16B - __ orr(v29, __ T8B, v30, v31); // orr v29.8B, v30.8B, v31.8B - __ orr(v0, __ T16B, v1, v2); // orr v0.16B, v1.16B, v2.16B - __ eor(v19, __ T8B, v20, v21); // eor v19.8B, v20.8B, v21.8B - __ eor(v12, __ T16B, v13, v14); // eor v12.16B, v13.16B, v14.16B - __ addv(v17, __ T8B, v18, v19); // add v17.8B, v18.8B, v19.8B - __ addv(v22, __ T16B, v23, v24); // add v22.16B, v23.16B, v24.16B - __ addv(v13, __ T4H, v14, v15); // add v13.4H, v14.4H, v15.4H - __ addv(v28, __ T8H, v29, v30); // add v28.8H, v29.8H, v30.8H - __ addv(v30, __ T2S, v31, v0); // add v30.2S, v31.2S, v0.2S - __ addv(v31, __ T4S, v0, v1); // add v31.4S, v0.4S, v1.4S - __ addv(v1, __ T2D, v2, v3); // add v1.2D, v2.2D, v3.2D - __ sqaddv(v26, __ T8B, v27, v28); // sqadd v26.8B, v27.8B, v28.8B - __ sqaddv(v28, __ T16B, v29, v30); // sqadd v28.16B, v29.16B, v30.16B - __ sqaddv(v4, __ T4H, v5, v6); // sqadd v4.4H, v5.4H, v6.4H - __ sqaddv(v30, __ T8H, v31, v0); // sqadd v30.8H, v31.8H, v0.8H - __ sqaddv(v4, __ T2S, v5, v6); // sqadd v4.2S, v5.2S, v6.2S - __ sqaddv(v6, __ T4S, v7, v8); // sqadd v6.4S, v7.4S, v8.4S - __ sqaddv(v30, __ T2D, v31, v0); // sqadd v30.2D, v31.2D, v0.2D - __ uqaddv(v26, __ T8B, v27, v28); // uqadd v26.8B, v27.8B, v28.8B - __ uqaddv(v18, __ T16B, v19, v20); // uqadd v18.16B, v19.16B, v20.16B - __ uqaddv(v9, __ T4H, v10, v11); // uqadd v9.4H, v10.4H, v11.4H - __ uqaddv(v8, __ T8H, v9, v10); // uqadd v8.8H, v9.8H, v10.8H - __ uqaddv(v12, __ T2S, v13, v14); // uqadd v12.2S, v13.2S, v14.2S - __ uqaddv(v0, __ T4S, v1, v2); // uqadd v0.4S, v1.4S, v2.4S - __ uqaddv(v20, __ T2D, v21, v22); // uqadd v20.2D, v21.2D, v22.2D - __ fadd(v1, __ T2S, v2, v3); // fadd v1.2S, v2.2S, v3.2S + __ andr(v19, __ T8B, v20, v21); // and v19.8B, v20.8B, v21.8B + __ andr(v12, __ T16B, v13, v14); // and v12.16B, v13.16B, v14.16B + __ orr(v17, __ T8B, v18, v19); // orr v17.8B, v18.8B, v19.8B + __ orr(v22, __ T16B, v23, v24); // orr v22.16B, v23.16B, v24.16B + __ eor(v13, __ T8B, v14, v15); // eor v13.8B, v14.8B, v15.8B + __ eor(v28, __ T16B, v29, v30); // eor v28.16B, v29.16B, v30.16B + __ addv(v30, __ T8B, v31, v0); // add v30.8B, v31.8B, v0.8B + __ addv(v31, __ T16B, v0, v1); // add v31.16B, v0.16B, v1.16B + __ addv(v1, __ T4H, v2, v3); // add v1.4H, v2.4H, v3.4H + __ addv(v26, __ T8H, v27, v28); // add v26.8H, v27.8H, v28.8H + __ addv(v28, __ T2S, v29, v30); // add v28.2S, v29.2S, v30.2S + __ addv(v4, __ T4S, v5, v6); // add v4.4S, v5.4S, v6.4S + __ addv(v30, __ T2D, v31, v0); // add v30.2D, v31.2D, v0.2D + __ sqaddv(v4, __ T8B, v5, v6); // sqadd v4.8B, v5.8B, v6.8B + __ sqaddv(v6, __ T16B, v7, v8); // sqadd v6.16B, v7.16B, v8.16B + __ sqaddv(v30, __ T4H, v31, v0); // sqadd v30.4H, v31.4H, v0.4H + __ sqaddv(v26, __ T8H, v27, v28); // sqadd v26.8H, v27.8H, v28.8H + __ sqaddv(v18, __ T2S, v19, v20); // sqadd v18.2S, v19.2S, v20.2S + __ sqaddv(v9, __ T4S, v10, v11); // sqadd v9.4S, v10.4S, v11.4S + __ sqaddv(v8, __ T2D, v9, v10); // sqadd v8.2D, v9.2D, v10.2D + __ uqaddv(v12, __ T8B, v13, v14); // uqadd v12.8B, v13.8B, v14.8B + __ uqaddv(v0, __ T16B, v1, v2); // uqadd v0.16B, v1.16B, v2.16B + __ uqaddv(v20, __ T4H, v21, v22); // uqadd v20.4H, v21.4H, v22.4H + __ uqaddv(v1, __ T8H, v2, v3); // uqadd v1.8H, v2.8H, v3.8H + __ uqaddv(v24, __ T2S, v25, v26); // uqadd v24.2S, v25.2S, v26.2S + __ uqaddv(v2, __ T4S, v3, v4); // uqadd v2.4S, v3.4S, v4.4S + __ uqaddv(v0, __ T2D, v1, v2); // uqadd v0.2D, v1.2D, v2.2D + __ fadd(v9, __ T2S, v10, v11); // fadd v9.2S, v10.2S, v11.2S __ fadd(v24, __ T4S, v25, v26); // fadd v24.4S, v25.4S, v26.4S - __ fadd(v2, __ T2D, v3, v4); // fadd v2.2D, v3.2D, v4.2D - __ fadd(v0, __ T4H, v1, v2); // fadd v0.4H, v1.4H, v2.4H - __ fadd(v9, __ T8H, v10, v11); // fadd v9.8H, v10.8H, v11.8H - __ subv(v24, __ T8B, v25, v26); // sub v24.8B, v25.8B, v26.8B - __ subv(v26, __ T16B, v27, v28); // sub v26.16B, v27.16B, v28.16B - __ subv(v16, __ T4H, v17, v18); // sub v16.4H, v17.4H, v18.4H - __ subv(v30, __ T8H, v31, v0); // sub v30.8H, v31.8H, v0.8H - __ subv(v3, __ T2S, v4, v5); // sub v3.2S, v4.2S, v5.2S - __ subv(v10, __ T4S, v11, v12); // sub v10.4S, v11.4S, v12.4S - __ subv(v23, __ T2D, v24, v25); // sub v23.2D, v24.2D, v25.2D - __ sqsubv(v10, __ T8B, v11, v12); // sqsub v10.8B, v11.8B, v12.8B - __ sqsubv(v4, __ T16B, v5, v6); // sqsub v4.16B, v5.16B, v6.16B - __ sqsubv(v18, __ T4H, v19, v20); // sqsub v18.4H, v19.4H, v20.4H - __ sqsubv(v2, __ T8H, v3, v4); // sqsub v2.8H, v3.8H, v4.8H - __ sqsubv(v11, __ T2S, v12, v13); // sqsub v11.2S, v12.2S, v13.2S - __ sqsubv(v8, __ T4S, v9, v10); // sqsub v8.4S, v9.4S, v10.4S + __ fadd(v26, __ T2D, v27, v28); // fadd v26.2D, v27.2D, v28.2D + __ fadd(v16, __ T4H, v17, v18); // fadd v16.4H, v17.4H, v18.4H + __ fadd(v30, __ T8H, v31, v0); // fadd v30.8H, v31.8H, v0.8H + __ subv(v3, __ T8B, v4, v5); // sub v3.8B, v4.8B, v5.8B + __ subv(v10, __ T16B, v11, v12); // sub v10.16B, v11.16B, v12.16B + __ subv(v23, __ T4H, v24, v25); // sub v23.4H, v24.4H, v25.4H + __ subv(v10, __ T8H, v11, v12); // sub v10.8H, v11.8H, v12.8H + __ subv(v4, __ T2S, v5, v6); // sub v4.2S, v5.2S, v6.2S + __ subv(v18, __ T4S, v19, v20); // sub v18.4S, v19.4S, v20.4S + __ subv(v2, __ T2D, v3, v4); // sub v2.2D, v3.2D, v4.2D + __ sqsubv(v11, __ T8B, v12, v13); // sqsub v11.8B, v12.8B, v13.8B + __ sqsubv(v8, __ T16B, v9, v10); // sqsub v8.16B, v9.16B, v10.16B + __ sqsubv(v10, __ T4H, v11, v12); // sqsub v10.4H, v11.4H, v12.4H + __ sqsubv(v15, __ T8H, v16, v17); // sqsub v15.8H, v16.8H, v17.8H + __ sqsubv(v17, __ T2S, v18, v19); // sqsub v17.2S, v18.2S, v19.2S + __ sqsubv(v2, __ T4S, v3, v4); // sqsub v2.4S, v3.4S, v4.4S __ sqsubv(v10, __ T2D, v11, v12); // sqsub v10.2D, v11.2D, v12.2D - __ uqsubv(v15, __ T8B, v16, v17); // uqsub v15.8B, v16.8B, v17.8B - __ uqsubv(v17, __ T16B, v18, v19); // uqsub v17.16B, v18.16B, v19.16B - __ uqsubv(v2, __ T4H, v3, v4); // uqsub v2.4H, v3.4H, v4.4H - __ uqsubv(v10, __ T8H, v11, v12); // uqsub v10.8H, v11.8H, v12.8H - __ uqsubv(v12, __ T2S, v13, v14); // uqsub v12.2S, v13.2S, v14.2S - __ uqsubv(v12, __ T4S, v13, v14); // uqsub v12.4S, v13.4S, v14.4S - __ uqsubv(v15, __ T2D, v16, v17); // uqsub v15.2D, v16.2D, v17.2D - __ fsub(v13, __ T2S, v14, v15); // fsub v13.2S, v14.2S, v15.2S - __ fsub(v2, __ T4S, v3, v4); // fsub v2.4S, v3.4S, v4.4S - __ fsub(v7, __ T2D, v8, v9); // fsub v7.2D, v8.2D, v9.2D - __ fsub(v20, __ T4H, v21, v22); // fsub v20.4H, v21.4H, v22.4H - __ fsub(v26, __ T8H, v27, v28); // fsub v26.8H, v27.8H, v28.8H - __ mulv(v16, __ T8B, v17, v18); // mul v16.8B, v17.8B, v18.8B - __ mulv(v4, __ T16B, v5, v6); // mul v4.16B, v5.16B, v6.16B - __ mulv(v2, __ T4H, v3, v4); // mul v2.4H, v3.4H, v4.4H - __ mulv(v4, __ T8H, v5, v6); // mul v4.8H, v5.8H, v6.8H - __ mulv(v12, __ T2S, v13, v14); // mul v12.2S, v13.2S, v14.2S - __ mulv(v18, __ T4S, v19, v20); // mul v18.4S, v19.4S, v20.4S + __ uqsubv(v12, __ T8B, v13, v14); // uqsub v12.8B, v13.8B, v14.8B + __ uqsubv(v12, __ T16B, v13, v14); // uqsub v12.16B, v13.16B, v14.16B + __ uqsubv(v15, __ T4H, v16, v17); // uqsub v15.4H, v16.4H, v17.4H + __ uqsubv(v13, __ T8H, v14, v15); // uqsub v13.8H, v14.8H, v15.8H + __ uqsubv(v2, __ T2S, v3, v4); // uqsub v2.2S, v3.2S, v4.2S + __ uqsubv(v7, __ T4S, v8, v9); // uqsub v7.4S, v8.4S, v9.4S + __ uqsubv(v20, __ T2D, v21, v22); // uqsub v20.2D, v21.2D, v22.2D + __ fsub(v26, __ T2S, v27, v28); // fsub v26.2S, v27.2S, v28.2S + __ fsub(v16, __ T4S, v17, v18); // fsub v16.4S, v17.4S, v18.4S + __ fsub(v4, __ T2D, v5, v6); // fsub v4.2D, v5.2D, v6.2D + __ fsub(v2, __ T4H, v3, v4); // fsub v2.4H, v3.4H, v4.4H + __ fsub(v4, __ T8H, v5, v6); // fsub v4.8H, v5.8H, v6.8H + __ mulv(v12, __ T8B, v13, v14); // mul v12.8B, v13.8B, v14.8B + __ mulv(v18, __ T16B, v19, v20); // mul v18.16B, v19.16B, v20.16B + __ mulv(v21, __ T4H, v22, v23); // mul v21.4H, v22.4H, v23.4H + __ mulv(v16, __ T8H, v17, v18); // mul v16.8H, v17.8H, v18.8H + __ mulv(v18, __ T2S, v19, v20); // mul v18.2S, v19.2S, v20.2S + __ mulv(v11, __ T4S, v12, v13); // mul v11.4S, v12.4S, v13.4S __ fabd(v21, __ T2S, v22, v23); // fabd v21.2S, v22.2S, v23.2S - __ fabd(v16, __ T4S, v17, v18); // fabd v16.4S, v17.4S, v18.4S - __ fabd(v18, __ T2D, v19, v20); // fabd v18.2D, v19.2D, v20.2D - __ fabd(v11, __ T4H, v12, v13); // fabd v11.4H, v12.4H, v13.4H - __ fabd(v21, __ T8H, v22, v23); // fabd v21.8H, v22.8H, v23.8H - __ faddp(v23, __ T2S, v24, v25); // faddp v23.2S, v24.2S, v25.2S - __ faddp(v12, __ T4S, v13, v14); // faddp v12.4S, v13.4S, v14.4S - __ faddp(v26, __ T2D, v27, v28); // faddp v26.2D, v27.2D, v28.2D - __ faddp(v23, __ T4H, v24, v25); // faddp v23.4H, v24.4H, v25.4H - __ faddp(v28, __ T8H, v29, v30); // faddp v28.8H, v29.8H, v30.8H - __ fmul(v14, __ T2S, v15, v16); // fmul v14.2S, v15.2S, v16.2S - __ fmul(v11, __ T4S, v12, v13); // fmul v11.4S, v12.4S, v13.4S - __ fmul(v24, __ T2D, v25, v26); // fmul v24.2D, v25.2D, v26.2D - __ fmul(v1, __ T4H, v2, v3); // fmul v1.4H, v2.4H, v3.4H - __ fmul(v12, __ T8H, v13, v14); // fmul v12.8H, v13.8H, v14.8H - __ mlav(v31, __ T4H, v0, v1); // mla v31.4H, v0.4H, v1.4H - __ mlav(v10, __ T8H, v11, v12); // mla v10.8H, v11.8H, v12.8H - __ mlav(v16, __ T2S, v17, v18); // mla v16.2S, v17.2S, v18.2S - __ mlav(v7, __ T4S, v8, v9); // mla v7.4S, v8.4S, v9.4S - __ fmla(v2, __ T2S, v3, v4); // fmla v2.2S, v3.2S, v4.2S - __ fmla(v3, __ T4S, v4, v5); // fmla v3.4S, v4.4S, v5.4S - __ fmla(v13, __ T2D, v14, v15); // fmla v13.2D, v14.2D, v15.2D - __ fmla(v19, __ T4H, v20, v21); // fmla v19.4H, v20.4H, v21.4H - __ fmla(v17, __ T8H, v18, v19); // fmla v17.8H, v18.8H, v19.8H - __ mlsv(v16, __ T4H, v17, v18); // mls v16.4H, v17.4H, v18.4H - __ mlsv(v3, __ T8H, v4, v5); // mls v3.8H, v4.8H, v5.8H - __ mlsv(v1, __ T2S, v2, v3); // mls v1.2S, v2.2S, v3.2S - __ mlsv(v11, __ T4S, v12, v13); // mls v11.4S, v12.4S, v13.4S - __ fmls(v30, __ T2S, v31, v0); // fmls v30.2S, v31.2S, v0.2S - __ fmls(v5, __ T4S, v6, v7); // fmls v5.4S, v6.4S, v7.4S - __ fmls(v8, __ T2D, v9, v10); // fmls v8.2D, v9.2D, v10.2D - __ fmls(v15, __ T4H, v16, v17); // fmls v15.4H, v16.4H, v17.4H - __ fmls(v29, __ T8H, v30, v31); // fmls v29.8H, v30.8H, v31.8H - __ fdiv(v30, __ T2S, v31, v0); // fdiv v30.2S, v31.2S, v0.2S - __ fdiv(v0, __ T4S, v1, v2); // fdiv v0.4S, v1.4S, v2.4S - __ fdiv(v20, __ T2D, v21, v22); // fdiv v20.2D, v21.2D, v22.2D - __ fdiv(v7, __ T4H, v8, v9); // fdiv v7.4H, v8.4H, v9.4H - __ fdiv(v20, __ T8H, v21, v22); // fdiv v20.8H, v21.8H, v22.8H - __ maxv(v23, __ T8B, v24, v25); // smax v23.8B, v24.8B, v25.8B - __ maxv(v28, __ T16B, v29, v30); // smax v28.16B, v29.16B, v30.16B - __ maxv(v21, __ T4H, v22, v23); // smax v21.4H, v22.4H, v23.4H - __ maxv(v27, __ T8H, v28, v29); // smax v27.8H, v28.8H, v29.8H - __ maxv(v25, __ T2S, v26, v27); // smax v25.2S, v26.2S, v27.2S - __ maxv(v5, __ T4S, v6, v7); // smax v5.4S, v6.4S, v7.4S - __ umaxv(v1, __ T8B, v2, v3); // umax v1.8B, v2.8B, v3.8B - __ umaxv(v23, __ T16B, v24, v25); // umax v23.16B, v24.16B, v25.16B - __ umaxv(v16, __ T4H, v17, v18); // umax v16.4H, v17.4H, v18.4H - __ umaxv(v31, __ T8H, v0, v1); // umax v31.8H, v0.8H, v1.8H - __ umaxv(v5, __ T2S, v6, v7); // umax v5.2S, v6.2S, v7.2S - __ umaxv(v12, __ T4S, v13, v14); // umax v12.4S, v13.4S, v14.4S - __ smaxp(v9, __ T8B, v10, v11); // smaxp v9.8B, v10.8B, v11.8B - __ smaxp(v28, __ T16B, v29, v30); // smaxp v28.16B, v29.16B, v30.16B - __ smaxp(v15, __ T4H, v16, v17); // smaxp v15.4H, v16.4H, v17.4H - __ smaxp(v29, __ T8H, v30, v31); // smaxp v29.8H, v30.8H, v31.8H - __ smaxp(v22, __ T2S, v23, v24); // smaxp v22.2S, v23.2S, v24.2S - __ smaxp(v31, __ T4S, v0, v1); // smaxp v31.4S, v0.4S, v1.4S - __ fmax(v19, __ T2S, v20, v21); // fmax v19.2S, v20.2S, v21.2S + __ fabd(v23, __ T4S, v24, v25); // fabd v23.4S, v24.4S, v25.4S + __ fabd(v12, __ T2D, v13, v14); // fabd v12.2D, v13.2D, v14.2D + __ fabd(v26, __ T4H, v27, v28); // fabd v26.4H, v27.4H, v28.4H + __ fabd(v23, __ T8H, v24, v25); // fabd v23.8H, v24.8H, v25.8H + __ faddp(v28, __ T2S, v29, v30); // faddp v28.2S, v29.2S, v30.2S + __ faddp(v14, __ T4S, v15, v16); // faddp v14.4S, v15.4S, v16.4S + __ faddp(v11, __ T2D, v12, v13); // faddp v11.2D, v12.2D, v13.2D + __ faddp(v24, __ T4H, v25, v26); // faddp v24.4H, v25.4H, v26.4H + __ faddp(v1, __ T8H, v2, v3); // faddp v1.8H, v2.8H, v3.8H + __ fmul(v12, __ T2S, v13, v14); // fmul v12.2S, v13.2S, v14.2S + __ fmul(v31, __ T4S, v0, v1); // fmul v31.4S, v0.4S, v1.4S + __ fmul(v10, __ T2D, v11, v12); // fmul v10.2D, v11.2D, v12.2D + __ fmul(v16, __ T4H, v17, v18); // fmul v16.4H, v17.4H, v18.4H + __ fmul(v7, __ T8H, v8, v9); // fmul v7.8H, v8.8H, v9.8H + __ mlav(v2, __ T4H, v3, v4); // mla v2.4H, v3.4H, v4.4H + __ mlav(v3, __ T8H, v4, v5); // mla v3.8H, v4.8H, v5.8H + __ mlav(v13, __ T2S, v14, v15); // mla v13.2S, v14.2S, v15.2S + __ mlav(v19, __ T4S, v20, v21); // mla v19.4S, v20.4S, v21.4S + __ fmla(v17, __ T2S, v18, v19); // fmla v17.2S, v18.2S, v19.2S + __ fmla(v16, __ T4S, v17, v18); // fmla v16.4S, v17.4S, v18.4S + __ fmla(v3, __ T2D, v4, v5); // fmla v3.2D, v4.2D, v5.2D + __ fmla(v1, __ T4H, v2, v3); // fmla v1.4H, v2.4H, v3.4H + __ fmla(v11, __ T8H, v12, v13); // fmla v11.8H, v12.8H, v13.8H + __ mlsv(v30, __ T4H, v31, v0); // mls v30.4H, v31.4H, v0.4H + __ mlsv(v5, __ T8H, v6, v7); // mls v5.8H, v6.8H, v7.8H + __ mlsv(v8, __ T2S, v9, v10); // mls v8.2S, v9.2S, v10.2S + __ mlsv(v15, __ T4S, v16, v17); // mls v15.4S, v16.4S, v17.4S + __ fmls(v29, __ T2S, v30, v31); // fmls v29.2S, v30.2S, v31.2S + __ fmls(v30, __ T4S, v31, v0); // fmls v30.4S, v31.4S, v0.4S + __ fmls(v0, __ T2D, v1, v2); // fmls v0.2D, v1.2D, v2.2D + __ fmls(v20, __ T4H, v21, v22); // fmls v20.4H, v21.4H, v22.4H + __ fmls(v7, __ T8H, v8, v9); // fmls v7.8H, v8.8H, v9.8H + __ fdiv(v20, __ T2S, v21, v22); // fdiv v20.2S, v21.2S, v22.2S + __ fdiv(v23, __ T4S, v24, v25); // fdiv v23.4S, v24.4S, v25.4S + __ fdiv(v28, __ T2D, v29, v30); // fdiv v28.2D, v29.2D, v30.2D + __ fdiv(v21, __ T4H, v22, v23); // fdiv v21.4H, v22.4H, v23.4H + __ fdiv(v27, __ T8H, v28, v29); // fdiv v27.8H, v28.8H, v29.8H + __ maxv(v25, __ T8B, v26, v27); // smax v25.8B, v26.8B, v27.8B + __ maxv(v5, __ T16B, v6, v7); // smax v5.16B, v6.16B, v7.16B + __ maxv(v1, __ T4H, v2, v3); // smax v1.4H, v2.4H, v3.4H + __ maxv(v23, __ T8H, v24, v25); // smax v23.8H, v24.8H, v25.8H + __ maxv(v16, __ T2S, v17, v18); // smax v16.2S, v17.2S, v18.2S + __ maxv(v31, __ T4S, v0, v1); // smax v31.4S, v0.4S, v1.4S + __ umaxv(v5, __ T8B, v6, v7); // umax v5.8B, v6.8B, v7.8B + __ umaxv(v12, __ T16B, v13, v14); // umax v12.16B, v13.16B, v14.16B + __ umaxv(v9, __ T4H, v10, v11); // umax v9.4H, v10.4H, v11.4H + __ umaxv(v28, __ T8H, v29, v30); // umax v28.8H, v29.8H, v30.8H + __ umaxv(v15, __ T2S, v16, v17); // umax v15.2S, v16.2S, v17.2S + __ umaxv(v29, __ T4S, v30, v31); // umax v29.4S, v30.4S, v31.4S + __ smaxp(v22, __ T8B, v23, v24); // smaxp v22.8B, v23.8B, v24.8B + __ smaxp(v31, __ T16B, v0, v1); // smaxp v31.16B, v0.16B, v1.16B + __ smaxp(v19, __ T4H, v20, v21); // smaxp v19.4H, v20.4H, v21.4H + __ smaxp(v31, __ T8H, v0, v1); // smaxp v31.8H, v0.8H, v1.8H + __ smaxp(v5, __ T2S, v6, v7); // smaxp v5.2S, v6.2S, v7.2S + __ smaxp(v14, __ T4S, v15, v16); // smaxp v14.4S, v15.4S, v16.4S + __ fmax(v18, __ T2S, v19, v20); // fmax v18.2S, v19.2S, v20.2S __ fmax(v31, __ T4S, v0, v1); // fmax v31.4S, v0.4S, v1.4S - __ fmax(v5, __ T2D, v6, v7); // fmax v5.2D, v6.2D, v7.2D - __ fmax(v14, __ T4H, v15, v16); // fmax v14.4H, v15.4H, v16.4H - __ fmax(v18, __ T8H, v19, v20); // fmax v18.8H, v19.8H, v20.8H - __ minv(v31, __ T8B, v0, v1); // smin v31.8B, v0.8B, v1.8B - __ minv(v18, __ T16B, v19, v20); // smin v18.16B, v19.16B, v20.16B - __ minv(v27, __ T4H, v28, v29); // smin v27.4H, v28.4H, v29.4H - __ minv(v20, __ T8H, v21, v22); // smin v20.8H, v21.8H, v22.8H - __ minv(v16, __ T2S, v17, v18); // smin v16.2S, v17.2S, v18.2S - __ minv(v12, __ T4S, v13, v14); // smin v12.4S, v13.4S, v14.4S - __ uminv(v11, __ T8B, v12, v13); // umin v11.8B, v12.8B, v13.8B - __ uminv(v9, __ T16B, v10, v11); // umin v9.16B, v10.16B, v11.16B - __ uminv(v6, __ T4H, v7, v8); // umin v6.4H, v7.4H, v8.4H + __ fmax(v18, __ T2D, v19, v20); // fmax v18.2D, v19.2D, v20.2D + __ fmax(v27, __ T4H, v28, v29); // fmax v27.4H, v28.4H, v29.4H + __ fmax(v20, __ T8H, v21, v22); // fmax v20.8H, v21.8H, v22.8H + __ minv(v16, __ T8B, v17, v18); // smin v16.8B, v17.8B, v18.8B + __ minv(v12, __ T16B, v13, v14); // smin v12.16B, v13.16B, v14.16B + __ minv(v11, __ T4H, v12, v13); // smin v11.4H, v12.4H, v13.4H + __ minv(v9, __ T8H, v10, v11); // smin v9.8H, v10.8H, v11.8H + __ minv(v6, __ T2S, v7, v8); // smin v6.2S, v7.2S, v8.2S + __ minv(v30, __ T4S, v31, v0); // smin v30.4S, v31.4S, v0.4S + __ uminv(v17, __ T8B, v18, v19); // umin v17.8B, v18.8B, v19.8B + __ uminv(v27, __ T16B, v28, v29); // umin v27.16B, v28.16B, v29.16B + __ uminv(v28, __ T4H, v29, v30); // umin v28.4H, v29.4H, v30.4H __ uminv(v30, __ T8H, v31, v0); // umin v30.8H, v31.8H, v0.8H - __ uminv(v17, __ T2S, v18, v19); // umin v17.2S, v18.2S, v19.2S - __ uminv(v27, __ T4S, v28, v29); // umin v27.4S, v28.4S, v29.4S - __ sminp(v28, __ T8B, v29, v30); // sminp v28.8B, v29.8B, v30.8B - __ sminp(v30, __ T16B, v31, v0); // sminp v30.16B, v31.16B, v0.16B - __ sminp(v7, __ T4H, v8, v9); // sminp v7.4H, v8.4H, v9.4H - __ sminp(v10, __ T8H, v11, v12); // sminp v10.8H, v11.8H, v12.8H - __ sminp(v20, __ T2S, v21, v22); // sminp v20.2S, v21.2S, v22.2S - __ sminp(v10, __ T4S, v11, v12); // sminp v10.4S, v11.4S, v12.4S - __ uminp(v4, __ T8B, v5, v6); // uminp v4.8B, v5.8B, v6.8B - __ uminp(v24, __ T16B, v25, v26); // uminp v24.16B, v25.16B, v26.16B - __ uminp(v17, __ T4H, v18, v19); // uminp v17.4H, v18.4H, v19.4H - __ uminp(v17, __ T8H, v18, v19); // uminp v17.8H, v18.8H, v19.8H + __ uminv(v7, __ T2S, v8, v9); // umin v7.2S, v8.2S, v9.2S + __ uminv(v10, __ T4S, v11, v12); // umin v10.4S, v11.4S, v12.4S + __ sminp(v20, __ T8B, v21, v22); // sminp v20.8B, v21.8B, v22.8B + __ sminp(v10, __ T16B, v11, v12); // sminp v10.16B, v11.16B, v12.16B + __ sminp(v4, __ T4H, v5, v6); // sminp v4.4H, v5.4H, v6.4H + __ sminp(v24, __ T8H, v25, v26); // sminp v24.8H, v25.8H, v26.8H + __ sminp(v17, __ T2S, v18, v19); // sminp v17.2S, v18.2S, v19.2S + __ sminp(v17, __ T4S, v18, v19); // sminp v17.4S, v18.4S, v19.4S + __ uminp(v22, __ T8B, v23, v24); // uminp v22.8B, v23.8B, v24.8B + __ uminp(v3, __ T16B, v4, v5); // uminp v3.16B, v4.16B, v5.16B + __ uminp(v29, __ T4H, v30, v31); // uminp v29.4H, v30.4H, v31.4H + __ uminp(v15, __ T8H, v16, v17); // uminp v15.8H, v16.8H, v17.8H __ uminp(v22, __ T2S, v23, v24); // uminp v22.2S, v23.2S, v24.2S - __ uminp(v3, __ T4S, v4, v5); // uminp v3.4S, v4.4S, v5.4S - __ umaxp(v29, __ T8B, v30, v31); // umaxp v29.8B, v30.8B, v31.8B - __ umaxp(v15, __ T16B, v16, v17); // umaxp v15.16B, v16.16B, v17.16B - __ umaxp(v22, __ T4H, v23, v24); // umaxp v22.4H, v23.4H, v24.4H - __ umaxp(v19, __ T8H, v20, v21); // umaxp v19.8H, v20.8H, v21.8H - __ umaxp(v19, __ T2S, v20, v21); // umaxp v19.2S, v20.2S, v21.2S - __ umaxp(v22, __ T4S, v23, v24); // umaxp v22.4S, v23.4S, v24.4S - __ sqdmulh(v2, __ T4H, v3, v4); // sqdmulh v2.4H, v3.4H, v4.4H - __ sqdmulh(v15, __ T8H, v16, v17); // sqdmulh v15.8H, v16.8H, v17.8H - __ sqdmulh(v6, __ T2S, v7, v8); // sqdmulh v6.2S, v7.2S, v8.2S - __ sqdmulh(v12, __ T4S, v13, v14); // sqdmulh v12.4S, v13.4S, v14.4S - __ shsubv(v16, __ T8B, v17, v18); // shsub v16.8B, v17.8B, v18.8B - __ shsubv(v11, __ T16B, v12, v13); // shsub v11.16B, v12.16B, v13.16B - __ shsubv(v13, __ T4H, v14, v15); // shsub v13.4H, v14.4H, v15.4H - __ shsubv(v23, __ T8H, v24, v25); // shsub v23.8H, v24.8H, v25.8H - __ shsubv(v1, __ T2S, v2, v3); // shsub v1.2S, v2.2S, v3.2S - __ shsubv(v30, __ T4S, v31, v0); // shsub v30.4S, v31.4S, v0.4S - __ fmin(v19, __ T2S, v20, v21); // fmin v19.2S, v20.2S, v21.2S - __ fmin(v5, __ T4S, v6, v7); // fmin v5.4S, v6.4S, v7.4S - __ fmin(v17, __ T2D, v18, v19); // fmin v17.2D, v18.2D, v19.2D - __ fmin(v2, __ T4H, v3, v4); // fmin v2.4H, v3.4H, v4.4H - __ fmin(v16, __ T8H, v17, v18); // fmin v16.8H, v17.8H, v18.8H - __ facgt(v22, __ T2S, v23, v24); // facgt v22.2S, v23.2S, v24.2S - __ facgt(v13, __ T4S, v14, v15); // facgt v13.4S, v14.4S, v15.4S - __ facgt(v10, __ T2D, v11, v12); // facgt v10.2D, v11.2D, v12.2D - __ facgt(v21, __ T4H, v22, v23); // facgt v21.4H, v22.4H, v23.4H - __ facgt(v29, __ T8H, v30, v31); // facgt v29.8H, v30.8H, v31.8H + __ uminp(v19, __ T4S, v20, v21); // uminp v19.4S, v20.4S, v21.4S + __ umaxp(v19, __ T8B, v20, v21); // umaxp v19.8B, v20.8B, v21.8B + __ umaxp(v22, __ T16B, v23, v24); // umaxp v22.16B, v23.16B, v24.16B + __ umaxp(v2, __ T4H, v3, v4); // umaxp v2.4H, v3.4H, v4.4H + __ umaxp(v15, __ T8H, v16, v17); // umaxp v15.8H, v16.8H, v17.8H + __ umaxp(v6, __ T2S, v7, v8); // umaxp v6.2S, v7.2S, v8.2S + __ umaxp(v12, __ T4S, v13, v14); // umaxp v12.4S, v13.4S, v14.4S + __ sqdmulh(v16, __ T4H, v17, v18); // sqdmulh v16.4H, v17.4H, v18.4H + __ sqdmulh(v11, __ T8H, v12, v13); // sqdmulh v11.8H, v12.8H, v13.8H + __ sqdmulh(v13, __ T2S, v14, v15); // sqdmulh v13.2S, v14.2S, v15.2S + __ sqdmulh(v23, __ T4S, v24, v25); // sqdmulh v23.4S, v24.4S, v25.4S + __ shsubv(v1, __ T8B, v2, v3); // shsub v1.8B, v2.8B, v3.8B + __ shsubv(v30, __ T16B, v31, v0); // shsub v30.16B, v31.16B, v0.16B + __ shsubv(v19, __ T4H, v20, v21); // shsub v19.4H, v20.4H, v21.4H + __ shsubv(v5, __ T8H, v6, v7); // shsub v5.8H, v6.8H, v7.8H + __ shsubv(v17, __ T2S, v18, v19); // shsub v17.2S, v18.2S, v19.2S + __ shsubv(v2, __ T4S, v3, v4); // shsub v2.4S, v3.4S, v4.4S + __ fmin(v16, __ T2S, v17, v18); // fmin v16.2S, v17.2S, v18.2S + __ fmin(v22, __ T4S, v23, v24); // fmin v22.4S, v23.4S, v24.4S + __ fmin(v13, __ T2D, v14, v15); // fmin v13.2D, v14.2D, v15.2D + __ fmin(v10, __ T4H, v11, v12); // fmin v10.4H, v11.4H, v12.4H + __ fmin(v21, __ T8H, v22, v23); // fmin v21.8H, v22.8H, v23.8H + __ facgt(v29, __ T2S, v30, v31); // facgt v29.2S, v30.2S, v31.2S + __ facgt(v27, __ T4S, v28, v29); // facgt v27.4S, v28.4S, v29.4S + __ facgt(v12, __ T2D, v13, v14); // facgt v12.2D, v13.2D, v14.2D + __ facgt(v27, __ T4H, v28, v29); // facgt v27.4H, v28.4H, v29.4H + __ facgt(v3, __ T8H, v4, v5); // facgt v3.8H, v4.8H, v5.8H // VectorScalarNEONInstruction - __ fmlavs(v6, __ T2S, v7, v8, 1); // fmla v6.2S, v7.2S, v8.S[1] - __ mulvs(v1, __ T4S, v2, v3, 3); // mul v1.4S, v2.4S, v3.S[3] - __ fmlavs(v15, __ T2D, v0, v1, 0); // fmla v15.2D, v0.2D, v1.D[0] - __ fmlsvs(v9, __ T2S, v10, v11, 1); // fmls v9.2S, v10.2S, v11.S[1] - __ mulvs(v4, __ T4S, v5, v6, 2); // mul v4.4S, v5.4S, v6.S[2] - __ fmlsvs(v13, __ T2D, v14, v15, 1); // fmls v13.2D, v14.2D, v15.D[1] - __ fmulxvs(v3, __ T2S, v4, v5, 0); // fmulx v3.2S, v4.2S, v5.S[0] - __ mulvs(v11, __ T4S, v12, v13, 2); // mul v11.4S, v12.4S, v13.S[2] - __ fmulxvs(v12, __ T2D, v13, v14, 1); // fmulx v12.2D, v13.2D, v14.D[1] - __ mulvs(v15, __ T4H, v0, v1, 0); // mul v15.4H, v0.4H, v1.H[0] - __ mulvs(v9, __ T8H, v10, v11, 6); // mul v9.8H, v10.8H, v11.H[6] - __ mulvs(v11, __ T2S, v12, v13, 0); // mul v11.2S, v12.2S, v13.S[0] - __ mulvs(v1, __ T4S, v2, v3, 2); // mul v1.4S, v2.4S, v3.S[2] + __ fmlavs(v15, __ T2S, v0, v1, 0); // fmla v15.2S, v0.2S, v1.S[0] + __ mulvs(v9, __ T4S, v10, v11, 3); // mul v9.4S, v10.4S, v11.S[3] + __ fmlavs(v4, __ T2D, v5, v6, 1); // fmla v4.2D, v5.2D, v6.D[1] + __ fmlsvs(v13, __ T2S, v14, v15, 1); // fmls v13.2S, v14.2S, v15.S[1] + __ mulvs(v3, __ T4S, v4, v5, 1); // mul v3.4S, v4.4S, v5.S[1] + __ fmlsvs(v11, __ T2D, v12, v13, 1); // fmls v11.2D, v12.2D, v13.D[1] + __ fmulxvs(v12, __ T2S, v13, v14, 1); // fmulx v12.2S, v13.2S, v14.S[1] + __ mulvs(v15, __ T4S, v0, v1, 0); // mul v15.4S, v0.4S, v1.S[0] + __ fmulxvs(v9, __ T2D, v10, v11, 1); // fmulx v9.2D, v10.2D, v11.D[1] + __ mulvs(v11, __ T4H, v12, v13, 1); // mul v11.4H, v12.4H, v13.H[1] + __ mulvs(v1, __ T8H, v2, v3, 4); // mul v1.8H, v2.8H, v3.H[4] + __ mulvs(v0, __ T2S, v1, v2, 1); // mul v0.2S, v1.2S, v2.S[1] + __ mulvs(v13, __ T4S, v14, v15, 3); // mul v13.4S, v14.4S, v15.S[3] // NEONVectorCompare - __ cm(Assembler::GT, v18, __ T8B, v19, v20); // cmgt v18.8B, v19.8B, v20.8B - __ cm(Assembler::GT, v0, __ T16B, v1, v2); // cmgt v0.16B, v1.16B, v2.16B - __ cm(Assembler::GT, v25, __ T4H, v26, v27); // cmgt v25.4H, v26.4H, v27.4H - __ cm(Assembler::GT, v26, __ T8H, v27, v28); // cmgt v26.8H, v27.8H, v28.8H - __ cm(Assembler::GT, v23, __ T2S, v24, v25); // cmgt v23.2S, v24.2S, v25.2S - __ cm(Assembler::GT, v2, __ T4S, v3, v4); // cmgt v2.4S, v3.4S, v4.4S - __ cm(Assembler::GT, v18, __ T2D, v19, v20); // cmgt v18.2D, v19.2D, v20.2D - __ cm(Assembler::GE, v12, __ T8B, v13, v14); // cmge v12.8B, v13.8B, v14.8B - __ cm(Assembler::GE, v4, __ T16B, v5, v6); // cmge v4.16B, v5.16B, v6.16B - __ cm(Assembler::GE, v28, __ T4H, v29, v30); // cmge v28.4H, v29.4H, v30.4H - __ cm(Assembler::GE, v30, __ T8H, v31, v0); // cmge v30.8H, v31.8H, v0.8H - __ cm(Assembler::GE, v29, __ T2S, v30, v31); // cmge v29.2S, v30.2S, v31.2S - __ cm(Assembler::GE, v16, __ T4S, v17, v18); // cmge v16.4S, v17.4S, v18.4S - __ cm(Assembler::GE, v27, __ T2D, v28, v29); // cmge v27.2D, v28.2D, v29.2D - __ cm(Assembler::EQ, v6, __ T8B, v7, v8); // cmeq v6.8B, v7.8B, v8.8B - __ cm(Assembler::EQ, v9, __ T16B, v10, v11); // cmeq v9.16B, v10.16B, v11.16B - __ cm(Assembler::EQ, v29, __ T4H, v30, v31); // cmeq v29.4H, v30.4H, v31.4H - __ cm(Assembler::EQ, v18, __ T8H, v19, v20); // cmeq v18.8H, v19.8H, v20.8H - __ cm(Assembler::EQ, v7, __ T2S, v8, v9); // cmeq v7.2S, v8.2S, v9.2S - __ cm(Assembler::EQ, v4, __ T4S, v5, v6); // cmeq v4.4S, v5.4S, v6.4S - __ cm(Assembler::EQ, v7, __ T2D, v8, v9); // cmeq v7.2D, v8.2D, v9.2D - __ cm(Assembler::HI, v15, __ T8B, v16, v17); // cmhi v15.8B, v16.8B, v17.8B - __ cm(Assembler::HI, v9, __ T16B, v10, v11); // cmhi v9.16B, v10.16B, v11.16B - __ cm(Assembler::HI, v23, __ T4H, v24, v25); // cmhi v23.4H, v24.4H, v25.4H - __ cm(Assembler::HI, v8, __ T8H, v9, v10); // cmhi v8.8H, v9.8H, v10.8H - __ cm(Assembler::HI, v2, __ T2S, v3, v4); // cmhi v2.2S, v3.2S, v4.2S - __ cm(Assembler::HI, v28, __ T4S, v29, v30); // cmhi v28.4S, v29.4S, v30.4S - __ cm(Assembler::HI, v21, __ T2D, v22, v23); // cmhi v21.2D, v22.2D, v23.2D - __ cm(Assembler::HS, v31, __ T8B, v0, v1); // cmhs v31.8B, v0.8B, v1.8B - __ cm(Assembler::HS, v5, __ T16B, v6, v7); // cmhs v5.16B, v6.16B, v7.16B - __ cm(Assembler::HS, v27, __ T4H, v28, v29); // cmhs v27.4H, v28.4H, v29.4H - __ cm(Assembler::HS, v0, __ T8H, v1, v2); // cmhs v0.8H, v1.8H, v2.8H - __ cm(Assembler::HS, v17, __ T2S, v18, v19); // cmhs v17.2S, v18.2S, v19.2S - __ cm(Assembler::HS, v15, __ T4S, v16, v17); // cmhs v15.4S, v16.4S, v17.4S - __ cm(Assembler::HS, v4, __ T2D, v5, v6); // cmhs v4.2D, v5.2D, v6.2D - __ fcm(Assembler::EQ, v26, __ T2S, v27, v28); // fcmeq v26.2S, v27.2S, v28.2S - __ fcm(Assembler::EQ, v8, __ T4S, v9, v10); // fcmeq v8.4S, v9.4S, v10.4S - __ fcm(Assembler::EQ, v28, __ T2D, v29, v30); // fcmeq v28.2D, v29.2D, v30.2D - __ fcm(Assembler::GT, v22, __ T2S, v23, v24); // fcmgt v22.2S, v23.2S, v24.2S - __ fcm(Assembler::GT, v27, __ T4S, v28, v29); // fcmgt v27.4S, v28.4S, v29.4S - __ fcm(Assembler::GT, v27, __ T2D, v28, v29); // fcmgt v27.2D, v28.2D, v29.2D - __ fcm(Assembler::GE, v25, __ T2S, v26, v27); // fcmge v25.2S, v26.2S, v27.2S - __ fcm(Assembler::GE, v23, __ T4S, v24, v25); // fcmge v23.4S, v24.4S, v25.4S + __ cm(Assembler::GT, v23, __ T8B, v24, v25); // cmgt v23.8B, v24.8B, v25.8B + __ cm(Assembler::GT, v2, __ T16B, v3, v4); // cmgt v2.16B, v3.16B, v4.16B + __ cm(Assembler::GT, v18, __ T4H, v19, v20); // cmgt v18.4H, v19.4H, v20.4H + __ cm(Assembler::GT, v12, __ T8H, v13, v14); // cmgt v12.8H, v13.8H, v14.8H + __ cm(Assembler::GT, v4, __ T2S, v5, v6); // cmgt v4.2S, v5.2S, v6.2S + __ cm(Assembler::GT, v28, __ T4S, v29, v30); // cmgt v28.4S, v29.4S, v30.4S + __ cm(Assembler::GT, v30, __ T2D, v31, v0); // cmgt v30.2D, v31.2D, v0.2D + __ cm(Assembler::GE, v29, __ T8B, v30, v31); // cmge v29.8B, v30.8B, v31.8B + __ cm(Assembler::GE, v16, __ T16B, v17, v18); // cmge v16.16B, v17.16B, v18.16B + __ cm(Assembler::GE, v27, __ T4H, v28, v29); // cmge v27.4H, v28.4H, v29.4H + __ cm(Assembler::GE, v6, __ T8H, v7, v8); // cmge v6.8H, v7.8H, v8.8H + __ cm(Assembler::GE, v9, __ T2S, v10, v11); // cmge v9.2S, v10.2S, v11.2S + __ cm(Assembler::GE, v29, __ T4S, v30, v31); // cmge v29.4S, v30.4S, v31.4S + __ cm(Assembler::GE, v18, __ T2D, v19, v20); // cmge v18.2D, v19.2D, v20.2D + __ cm(Assembler::EQ, v7, __ T8B, v8, v9); // cmeq v7.8B, v8.8B, v9.8B + __ cm(Assembler::EQ, v4, __ T16B, v5, v6); // cmeq v4.16B, v5.16B, v6.16B + __ cm(Assembler::EQ, v7, __ T4H, v8, v9); // cmeq v7.4H, v8.4H, v9.4H + __ cm(Assembler::EQ, v15, __ T8H, v16, v17); // cmeq v15.8H, v16.8H, v17.8H + __ cm(Assembler::EQ, v9, __ T2S, v10, v11); // cmeq v9.2S, v10.2S, v11.2S + __ cm(Assembler::EQ, v23, __ T4S, v24, v25); // cmeq v23.4S, v24.4S, v25.4S + __ cm(Assembler::EQ, v8, __ T2D, v9, v10); // cmeq v8.2D, v9.2D, v10.2D + __ cm(Assembler::HI, v2, __ T8B, v3, v4); // cmhi v2.8B, v3.8B, v4.8B + __ cm(Assembler::HI, v28, __ T16B, v29, v30); // cmhi v28.16B, v29.16B, v30.16B + __ cm(Assembler::HI, v21, __ T4H, v22, v23); // cmhi v21.4H, v22.4H, v23.4H + __ cm(Assembler::HI, v31, __ T8H, v0, v1); // cmhi v31.8H, v0.8H, v1.8H + __ cm(Assembler::HI, v5, __ T2S, v6, v7); // cmhi v5.2S, v6.2S, v7.2S + __ cm(Assembler::HI, v27, __ T4S, v28, v29); // cmhi v27.4S, v28.4S, v29.4S + __ cm(Assembler::HI, v0, __ T2D, v1, v2); // cmhi v0.2D, v1.2D, v2.2D + __ cm(Assembler::HS, v17, __ T8B, v18, v19); // cmhs v17.8B, v18.8B, v19.8B + __ cm(Assembler::HS, v15, __ T16B, v16, v17); // cmhs v15.16B, v16.16B, v17.16B + __ cm(Assembler::HS, v4, __ T4H, v5, v6); // cmhs v4.4H, v5.4H, v6.4H + __ cm(Assembler::HS, v26, __ T8H, v27, v28); // cmhs v26.8H, v27.8H, v28.8H + __ cm(Assembler::HS, v8, __ T2S, v9, v10); // cmhs v8.2S, v9.2S, v10.2S + __ cm(Assembler::HS, v28, __ T4S, v29, v30); // cmhs v28.4S, v29.4S, v30.4S + __ cm(Assembler::HS, v22, __ T2D, v23, v24); // cmhs v22.2D, v23.2D, v24.2D + __ fcm(Assembler::EQ, v27, __ T2S, v28, v29); // fcmeq v27.2S, v28.2S, v29.2S + __ fcm(Assembler::EQ, v27, __ T4S, v28, v29); // fcmeq v27.4S, v28.4S, v29.4S + __ fcm(Assembler::EQ, v25, __ T2D, v26, v27); // fcmeq v25.2D, v26.2D, v27.2D + __ fcm(Assembler::GT, v23, __ T2S, v24, v25); // fcmgt v23.2S, v24.2S, v25.2S + __ fcm(Assembler::GT, v0, __ T4S, v1, v2); // fcmgt v0.4S, v1.4S, v2.4S + __ fcm(Assembler::GT, v4, __ T2D, v5, v6); // fcmgt v4.2D, v5.2D, v6.2D + __ fcm(Assembler::GE, v6, __ T2S, v7, v8); // fcmge v6.2S, v7.2S, v8.2S + __ fcm(Assembler::GE, v18, __ T4S, v19, v20); // fcmge v18.4S, v19.4S, v20.4S __ fcm(Assembler::GE, v0, __ T2D, v1, v2); // fcmge v0.2D, v1.2D, v2.2D // SVEComparisonWithZero - __ sve_fcm(Assembler::EQ, p2, __ D, p0, z6, 0.0); // fcmeq p2.d, p0/z, z6.d, #0.0 - __ sve_fcm(Assembler::GT, p2, __ S, p2, z15, 0.0); // fcmgt p2.s, p2/z, z15.s, #0.0 - __ sve_fcm(Assembler::GE, p3, __ S, p7, z5, 0.0); // fcmge p3.s, p7/z, z5.s, #0.0 - __ sve_fcm(Assembler::LT, p3, __ D, p5, z20, 0.0); // fcmlt p3.d, p5/z, z20.d, #0.0 - __ sve_fcm(Assembler::LE, p3, __ S, p4, z11, 0.0); // fcmle p3.s, p4/z, z11.s, #0.0 - __ sve_fcm(Assembler::NE, p15, __ D, p0, z6, 0.0); // fcmne p15.d, p0/z, z6.d, #0.0 + __ sve_fcm(Assembler::EQ, p2, __ S, p2, z15, 0.0); // fcmeq p2.s, p2/z, z15.s, #0.0 + __ sve_fcm(Assembler::GT, p3, __ S, p7, z5, 0.0); // fcmgt p3.s, p7/z, z5.s, #0.0 + __ sve_fcm(Assembler::GE, p3, __ D, p5, z20, 0.0); // fcmge p3.d, p5/z, z20.d, #0.0 + __ sve_fcm(Assembler::LT, p3, __ S, p4, z11, 0.0); // fcmlt p3.s, p4/z, z11.s, #0.0 + __ sve_fcm(Assembler::LE, p15, __ D, p0, z6, 0.0); // fcmle p15.d, p0/z, z6.d, #0.0 + __ sve_fcm(Assembler::NE, p6, __ D, p0, z30, 0.0); // fcmne p6.d, p0/z, z30.d, #0.0 // SVEComparisonWithImm - __ sve_cmp(Assembler::EQ, p6, __ D, p0, z30, 11); // cmpeq p6.d, p0/z, z30.d, #11 - __ sve_cmp(Assembler::GT, p11, __ H, p3, z29, 12); // cmpgt p11.h, p3/z, z29.h, #12 - __ sve_cmp(Assembler::GE, p8, __ B, p0, z24, -2); // cmpge p8.b, p0/z, z24.b, #-2 - __ sve_cmp(Assembler::LT, p5, __ H, p6, z16, 7); // cmplt p5.h, p6/z, z16.h, #7 - __ sve_cmp(Assembler::LE, p6, __ S, p4, z4, -12); // cmple p6.s, p4/z, z4.s, #-12 - __ sve_cmp(Assembler::NE, p0, __ S, p4, z19, -3); // cmpne p0.s, p4/z, z19.s, #-3 - __ sve_cmp(Assembler::HS, p7, __ B, p4, z12, 15); // cmphs p7.b, p4/z, z12.b, #15 - __ sve_cmp(Assembler::HI, p10, __ B, p1, z23, 30); // cmphi p10.b, p1/z, z23.b, #30 - __ sve_cmp(Assembler::LS, p9, __ D, p4, z13, 67); // cmpls p9.d, p4/z, z13.d, #67 - __ sve_cmp(Assembler::LO, p3, __ D, p0, z2, 16); // cmplo p3.d, p0/z, z2.d, #16 + __ sve_cmp(Assembler::EQ, p13, __ D, p3, z22, -3); // cmpeq p13.d, p3/z, z22.d, #-3 + __ sve_cmp(Assembler::GT, p14, __ D, p1, z17, -14); // cmpgt p14.d, p1/z, z17.d, #-14 + __ sve_cmp(Assembler::GE, p7, __ S, p2, z10, 11); // cmpge p7.s, p2/z, z10.s, #11 + __ sve_cmp(Assembler::LT, p11, __ B, p5, z12, 1); // cmplt p11.b, p5/z, z12.b, #1 + __ sve_cmp(Assembler::LE, p2, __ S, p4, z1, 2); // cmple p2.s, p4/z, z1.s, #2 + __ sve_cmp(Assembler::NE, p6, __ H, p0, z14, 1); // cmpne p6.h, p0/z, z14.h, #1 + __ sve_cmp(Assembler::HS, p1, __ S, p1, z21, 25); // cmphs p1.s, p1/z, z21.s, #25 + __ sve_cmp(Assembler::HI, p3, __ H, p7, z19, 70); // cmphi p3.h, p7/z, z19.h, #70 + __ sve_cmp(Assembler::LS, p8, __ B, p7, z6, 12); // cmpls p8.b, p7/z, z6.b, #12 + __ sve_cmp(Assembler::LO, p2, __ S, p5, z6, 55); // cmplo p2.s, p5/z, z6.s, #55 // SpecialCases __ ccmn(zr, zr, 3u, Assembler::LE); // ccmn xzr, xzr, #3, LE @@ -1210,241 +1216,241 @@ __ fmovd(v0, -1.0625); // fmov d0, #-1.0625 // LSEOp - __ swp(Assembler::xword, r6, r16, r20); // swp x6, x16, [x20] - __ ldadd(Assembler::xword, r13, r12, r20); // ldadd x13, x12, [x20] - __ ldbic(Assembler::xword, r8, r25, r20); // ldclr x8, x25, [x20] - __ ldeor(Assembler::xword, r19, r0, r11); // ldeor x19, x0, [x11] - __ ldorr(Assembler::xword, r24, r6, r20); // ldset x24, x6, [x20] - __ ldsmin(Assembler::xword, zr, r14, r16); // ldsmin xzr, x14, [x16] - __ ldsmax(Assembler::xword, r6, r0, r7); // ldsmax x6, x0, [x7] - __ ldumin(Assembler::xword, r15, r19, r26); // ldumin x15, x19, [x26] - __ ldumax(Assembler::xword, r9, r10, r23); // ldumax x9, x10, [x23] + __ swp(Assembler::xword, r12, r20, r8); // swp x12, x20, [x8] + __ ldadd(Assembler::xword, r25, r20, r19); // ldadd x25, x20, [x19] + __ ldbic(Assembler::xword, r0, r11, r24); // ldclr x0, x11, [x24] + __ ldeor(Assembler::xword, r6, r20, sp); // ldeor x6, x20, [sp] + __ ldorr(Assembler::xword, r14, r16, r6); // ldset x14, x16, [x6] + __ ldsmin(Assembler::xword, r0, r7, r15); // ldsmin x0, x7, [x15] + __ ldsmax(Assembler::xword, r19, r26, r9); // ldsmax x19, x26, [x9] + __ ldumin(Assembler::xword, r10, r23, r21); // ldumin x10, x23, [x21] + __ ldumax(Assembler::xword, r22, r28, r2); // ldumax x22, x28, [x2] // LSEOp - __ swpa(Assembler::xword, r21, r22, r28); // swpa x21, x22, [x28] - __ ldadda(Assembler::xword, r2, r3, r15); // ldadda x2, x3, [x15] - __ ldbica(Assembler::xword, r19, r20, r7); // ldclra x19, x20, [x7] - __ ldeora(Assembler::xword, r4, r29, r7); // ldeora x4, x29, [x7] - __ ldorra(Assembler::xword, r0, r9, r16); // ldseta x0, x9, [x16] - __ ldsmina(Assembler::xword, r20, r23, r4); // ldsmina x20, x23, [x4] - __ ldsmaxa(Assembler::xword, r16, r10, r23); // ldsmaxa x16, x10, [x23] - __ ldumina(Assembler::xword, r11, r25, r6); // ldumina x11, x25, [x6] - __ ldumaxa(Assembler::xword, zr, r16, r13); // ldumaxa xzr, x16, [x13] + __ swpa(Assembler::xword, r3, r15, r19); // swpa x3, x15, [x19] + __ ldadda(Assembler::xword, r20, r7, r4); // ldadda x20, x7, [x4] + __ ldbica(Assembler::xword, r29, r7, r0); // ldclra x29, x7, [x0] + __ ldeora(Assembler::xword, r9, r16, r20); // ldeora x9, x16, [x20] + __ ldorra(Assembler::xword, r23, r4, r16); // ldseta x23, x4, [x16] + __ ldsmina(Assembler::xword, r10, r23, r11); // ldsmina x10, x23, [x11] + __ ldsmaxa(Assembler::xword, r25, r6, sp); // ldsmaxa x25, x6, [sp] + __ ldumina(Assembler::xword, r16, r13, r23); // ldumina x16, x13, [x23] + __ ldumaxa(Assembler::xword, r12, r1, r14); // ldumaxa x12, x1, [x14] // LSEOp - __ swpal(Assembler::xword, r23, r12, r1); // swpal x23, x12, [x1] - __ ldaddal(Assembler::xword, r14, r9, r21); // ldaddal x14, x9, [x21] - __ ldbical(Assembler::xword, r16, r26, r15); // ldclral x16, x26, [x15] - __ ldeoral(Assembler::xword, r4, r4, r15); // ldeoral x4, x4, [x15] - __ ldorral(Assembler::xword, r8, r6, r30); // ldsetal x8, x6, [x30] - __ ldsminal(Assembler::xword, r4, r29, r17); // ldsminal x4, x29, [x17] - __ ldsmaxal(Assembler::xword, r29, r26, r9); // ldsmaxal x29, x26, [x9] - __ lduminal(Assembler::xword, r15, r2, r11); // lduminal x15, x2, [x11] - __ ldumaxal(Assembler::xword, r29, r3, r7); // ldumaxal x29, x3, [x7] + __ swpal(Assembler::xword, r9, r21, r16); // swpal x9, x21, [x16] + __ ldaddal(Assembler::xword, r26, r15, r4); // ldaddal x26, x15, [x4] + __ ldbical(Assembler::xword, r4, r16, r8); // ldclral x4, x16, [x8] + __ ldeoral(Assembler::xword, r6, r30, r4); // ldeoral x6, x30, [x4] + __ ldorral(Assembler::xword, r29, r17, r29); // ldsetal x29, x17, [x29] + __ ldsminal(Assembler::xword, r26, r9, r15); // ldsminal x26, x9, [x15] + __ ldsmaxal(Assembler::xword, r2, r11, r29); // ldsmaxal x2, x11, [x29] + __ lduminal(Assembler::xword, r3, r7, r1); // lduminal x3, x7, [x1] + __ ldumaxal(Assembler::xword, r27, r21, r15); // ldumaxal x27, x21, [x15] // LSEOp - __ swpl(Assembler::xword, r1, r27, r21); // swpl x1, x27, [x21] - __ ldaddl(Assembler::xword, r16, r14, r8); // ldaddl x16, x14, [x8] - __ ldbicl(Assembler::xword, r16, r22, r25); // ldclrl x16, x22, [x25] - __ ldeorl(Assembler::xword, r5, r20, r21); // ldeorl x5, x20, [x21] - __ ldorrl(Assembler::xword, r16, r23, r16); // ldsetl x16, x23, [x16] - __ ldsminl(Assembler::xword, r30, r20, r20); // ldsminl x30, x20, [x20] - __ ldsmaxl(Assembler::xword, r0, r4, r19); // ldsmaxl x0, x4, [x19] - __ lduminl(Assembler::xword, r24, r4, r20); // lduminl x24, x4, [x20] - __ ldumaxl(Assembler::xword, r4, r24, r26); // ldumaxl x4, x24, [x26] + __ swpl(Assembler::xword, r14, r8, r15); // swpl x14, x8, [x15] + __ ldaddl(Assembler::xword, r22, r25, r5); // ldaddl x22, x25, [x5] + __ ldbicl(Assembler::xword, r20, r21, r15); // ldclrl x20, x21, [x15] + __ ldeorl(Assembler::xword, r23, r16, r30); // ldeorl x23, x16, [x30] + __ ldorrl(Assembler::xword, r20, r20, r0); // ldsetl x20, x20, [x0] + __ ldsminl(Assembler::xword, r4, r19, r24); // ldsminl x4, x19, [x24] + __ ldsmaxl(Assembler::xword, r4, r20, r4); // ldsmaxl x4, x20, [x4] + __ lduminl(Assembler::xword, r24, r26, r19); // lduminl x24, x26, [x19] + __ ldumaxl(Assembler::xword, r2, r8, r8); // ldumaxl x2, x8, [x8] // LSEOp - __ swp(Assembler::word, r19, r2, r8); // swp w19, w2, [x8] - __ ldadd(Assembler::word, r8, r14, r24); // ldadd w8, w14, [x24] - __ ldbic(Assembler::word, r16, zr, r22); // ldclr w16, wzr, [x22] - __ ldeor(Assembler::word, r4, zr, r1); // ldeor w4, wzr, [x1] - __ ldorr(Assembler::word, r10, r20, r12); // ldset w10, w20, [x12] - __ ldsmin(Assembler::word, r0, r9, r7); // ldsmin w0, w9, [x7] - __ ldsmax(Assembler::word, r24, r16, r4); // ldsmax w24, w16, [x4] - __ ldumin(Assembler::word, r27, r6, r10); // ldumin w27, w6, [x10] - __ ldumax(Assembler::word, r27, r24, r13); // ldumax w27, w24, [x13] + __ swp(Assembler::word, r14, r24, r15); // swp w14, w24, [x15] + __ ldadd(Assembler::word, zr, r22, r4); // ldadd wzr, w22, [x4] + __ ldbic(Assembler::word, zr, r1, r10); // ldclr wzr, w1, [x10] + __ ldeor(Assembler::word, r20, r12, r0); // ldeor w20, w12, [x0] + __ ldorr(Assembler::word, r9, r7, r24); // ldset w9, w7, [x24] + __ ldsmin(Assembler::word, r16, r4, r27); // ldsmin w16, w4, [x27] + __ ldsmax(Assembler::word, r6, r10, r27); // ldsmax w6, w10, [x27] + __ ldumin(Assembler::word, r24, r13, r16); // ldumin w24, w13, [x16] + __ ldumax(Assembler::word, zr, r22, r22); // ldumax wzr, w22, [x22] // LSEOp - __ swpa(Assembler::word, r16, zr, r22); // swpa w16, wzr, [x22] - __ ldadda(Assembler::word, r22, r20, sp); // ldadda w22, w20, [sp] - __ ldbica(Assembler::word, r29, r9, r14); // ldclra w29, w9, [x14] - __ ldeora(Assembler::word, r20, r7, r20); // ldeora w20, w7, [x20] - __ ldorra(Assembler::word, r28, r9, r11); // ldseta w28, w9, [x11] - __ ldsmina(Assembler::word, r14, r12, r20); // ldsmina w14, w12, [x20] - __ ldsmaxa(Assembler::word, r1, r24, r9); // ldsmaxa w1, w24, [x9] - __ ldumina(Assembler::word, r19, r13, r19); // ldumina w19, w13, [x19] - __ ldumaxa(Assembler::word, r16, r16, r5); // ldumaxa w16, w16, [x5] + __ swpa(Assembler::word, r20, zr, r29); // swpa w20, wzr, [x29] + __ ldadda(Assembler::word, r9, r14, r20); // ldadda w9, w14, [x20] + __ ldbica(Assembler::word, r7, r20, r28); // ldclra w7, w20, [x28] + __ ldeora(Assembler::word, r9, r11, r14); // ldeora w9, w11, [x14] + __ ldorra(Assembler::word, r12, r20, r1); // ldseta w12, w20, [x1] + __ ldsmina(Assembler::word, r24, r9, r19); // ldsmina w24, w9, [x19] + __ ldsmaxa(Assembler::word, r13, r19, r15); // ldsmaxa w13, w19, [x15] + __ ldumina(Assembler::word, r16, r5, r0); // ldumina w16, w5, [x0] + __ ldumaxa(Assembler::word, r3, r12, r8); // ldumaxa w3, w12, [x8] // LSEOp - __ swpal(Assembler::word, r0, r3, r12); // swpal w0, w3, [x12] - __ ldaddal(Assembler::word, r8, r15, r15); // ldaddal w8, w15, [x15] - __ ldbical(Assembler::word, r16, r4, r15); // ldclral w16, w4, [x15] - __ ldeoral(Assembler::word, r30, r5, r0); // ldeoral w30, w5, [x0] - __ ldorral(Assembler::word, r10, r22, r27); // ldsetal w10, w22, [x27] - __ ldsminal(Assembler::word, r3, r0, r9); // ldsminal w3, w0, [x9] - __ ldsmaxal(Assembler::word, r19, r29, r10); // ldsmaxal w19, w29, [x10] - __ lduminal(Assembler::word, r24, r4, r20); // lduminal w24, w4, [x20] - __ ldumaxal(Assembler::word, r7, r24, r29); // ldumaxal w7, w24, [x29] + __ swpal(Assembler::word, r15, r15, r16); // swpal w15, w15, [x16] + __ ldaddal(Assembler::word, r4, r15, r30); // ldaddal w4, w15, [x30] + __ ldbical(Assembler::word, r5, r0, r10); // ldclral w5, w0, [x10] + __ ldeoral(Assembler::word, r22, r27, r3); // ldeoral w22, w27, [x3] + __ ldorral(Assembler::word, r0, r9, r19); // ldsetal w0, w9, [x19] + __ ldsminal(Assembler::word, r29, r10, r24); // ldsminal w29, w10, [x24] + __ ldsmaxal(Assembler::word, r4, r20, r7); // ldsmaxal w4, w20, [x7] + __ lduminal(Assembler::word, r24, r29, r14); // lduminal w24, w29, [x14] + __ ldumaxal(Assembler::word, r21, r11, r27); // ldumaxal w21, w11, [x27] // LSEOp - __ swpl(Assembler::word, r14, r21, r11); // swpl w14, w21, [x11] - __ ldaddl(Assembler::word, r27, r13, r15); // ldaddl w27, w13, [x15] - __ ldbicl(Assembler::word, zr, r17, r14); // ldclrl wzr, w17, [x14] - __ ldeorl(Assembler::word, r3, r30, r16); // ldeorl w3, w30, [x16] - __ ldorrl(Assembler::word, r22, r20, r7); // ldsetl w22, w20, [x7] - __ ldsminl(Assembler::word, r20, r3, r1); // ldsminl w20, w3, [x1] - __ ldsmaxl(Assembler::word, r26, r19, r9); // ldsmaxl w26, w19, [x9] - __ lduminl(Assembler::word, r16, r17, r21); // lduminl w16, w17, [x21] - __ ldumaxl(Assembler::word, r0, r4, r2); // ldumaxl w0, w4, [x2] + __ swpl(Assembler::word, r13, r16, sp); // swpl w13, w16, [sp] + __ ldaddl(Assembler::word, r17, r14, r3); // ldaddl w17, w14, [x3] + __ ldbicl(Assembler::word, r30, r16, r22); // ldclrl w30, w16, [x22] + __ ldeorl(Assembler::word, r20, r7, r20); // ldeorl w20, w7, [x20] + __ ldorrl(Assembler::word, r3, r1, r26); // ldsetl w3, w1, [x26] + __ ldsminl(Assembler::word, r19, r9, r16); // ldsminl w19, w9, [x16] + __ ldsmaxl(Assembler::word, r17, r21, r0); // ldsmaxl w17, w21, [x0] + __ lduminl(Assembler::word, r4, r2, r24); // lduminl w4, w2, [x24] + __ ldumaxl(Assembler::word, r14, r6, r11); // ldumaxl w14, w6, [x11] // SHA3SIMDOp - __ bcax(v24, __ T16B, v14, v6, v11); // bcax v24.16B, v14.16B, v6.16B, v11.16B - __ eor3(v21, __ T16B, v14, v17, v30); // eor3 v21.16B, v14.16B, v17.16B, v30.16B - __ rax1(v12, __ T2D, v3, v3); // rax1 v12.2D, v3.2D, v3.2D - __ xar(v23, __ T2D, v9, v3, 49); // xar v23.2D, v9.2D, v3.2D, #49 + __ bcax(v21, __ T16B, v14, v17, v30); // bcax v21.16B, v14.16B, v17.16B, v30.16B + __ eor3(v12, __ T16B, v3, v3, v23); // eor3 v12.16B, v3.16B, v3.16B, v23.16B + __ rax1(v9, __ T2D, v3, v24); // rax1 v9.2D, v3.2D, v24.2D + __ xar(v28, __ T2D, v3, v19, 47); // xar v28.2D, v3.2D, v19.2D, #47 // SHA512SIMDOp - __ sha512h(v28, __ T2D, v3, v19); // sha512h q28, q3, v19.2D - __ sha512h2(v23, __ T2D, v7, v26); // sha512h2 q23, q7, v26.2D - __ sha512su0(v21, __ T2D, v14); // sha512su0 v21.2D, v14.2D - __ sha512su1(v5, __ T2D, v8, v26); // sha512su1 v5.2D, v8.2D, v26.2D + __ sha512h(v7, __ T2D, v26, v21); // sha512h q7, q26, v21.2D + __ sha512h2(v14, __ T2D, v5, v8); // sha512h2 q14, q5, v8.2D + __ sha512su0(v26, __ T2D, v5); // sha512su0 v26.2D, v5.2D + __ sha512su1(v22, __ T2D, v18, v17); // sha512su1 v22.2D, v18.2D, v17.2D // SVEBinaryImmOp - __ sve_add(z5, __ S, 146u); // add z5.s, z5.s, #0x92 - __ sve_sub(z17, __ B, 31u); // sub z17.b, z17.b, #0x1f - __ sve_and(z9, __ S, 16744448u); // and z9.s, z9.s, #0xff8000 - __ sve_eor(z12, __ H, 33279u); // eor z12.h, z12.h, #0x81ff - __ sve_orr(z11, __ H, 49663u); // orr z11.h, z11.h, #0xc1ff + __ sve_add(z0, __ B, 79u); // add z0.b, z0.b, #0x4f + __ sve_sub(z20, __ H, 65u); // sub z20.h, z20.h, #0x41 + __ sve_and(z12, __ H, 33279u); // and z12.h, z12.h, #0x81ff + __ sve_eor(z11, __ H, 49663u); // eor z11.h, z11.h, #0xc1ff + __ sve_orr(z31, __ S, 2147484159u); // orr z31.s, z31.s, #0x800001ff // SVEBinaryImmOp - __ sve_add(z31, __ S, 72u); // add z31.s, z31.s, #0x48 - __ sve_sub(z16, __ H, 218u); // sub z16.h, z16.h, #0xda - __ sve_and(z23, __ D, 562675075514368u); // and z23.d, z23.d, #0x1ffc000000000 - __ sve_eor(z8, __ B, 243u); // eor z8.b, z8.b, #0xf3 - __ sve_orr(z10, __ B, 239u); // orr z10.b, z10.b, #0xef + __ sve_add(z15, __ D, 188u); // add z15.d, z15.d, #0xbc + __ sve_sub(z28, __ S, 64u); // sub z28.s, z28.s, #0x40 + __ sve_and(z8, __ B, 243u); // and z8.b, z8.b, #0xf3 + __ sve_eor(z10, __ B, 239u); // eor z10.b, z10.b, #0xef + __ sve_orr(z22, __ S, 32768u); // orr z22.s, z22.s, #0x8000 // SVEBinaryImmOp - __ sve_add(z22, __ S, 5u); // add z22.s, z22.s, #0x5 - __ sve_sub(z3, __ S, 209u); // sub z3.s, z3.s, #0xd1 - __ sve_and(z5, __ D, 17870287719452639231u); // and z5.d, z5.d, #0xf80003ffffffffff - __ sve_eor(z17, __ B, 128u); // eor z17.b, z17.b, #0x80 - __ sve_orr(z30, __ H, 49663u); // orr z30.h, z30.h, #0xc1ff + __ sve_add(z23, __ D, 46u); // add z23.d, z23.d, #0x2e + __ sve_sub(z26, __ D, 154u); // sub z26.d, z26.d, #0x9a + __ sve_and(z17, __ B, 128u); // and z17.b, z17.b, #0x80 + __ sve_eor(z30, __ H, 49663u); // eor z30.h, z30.h, #0xc1ff + __ sve_orr(z2, __ D, 18444492273897963519u); // orr z2.d, z2.d, #0xfff80000001fffff // SVEBinaryImmOp - __ sve_add(z2, __ D, 168u); // add z2.d, z2.d, #0xa8 - __ sve_sub(z23, __ S, 240u); // sub z23.s, z23.s, #0xf0 - __ sve_and(z12, __ H, 1u); // and z12.h, z12.h, #0x1 - __ sve_eor(z15, __ S, 1u); // eor z15.s, z15.s, #0x1 - __ sve_orr(z19, __ D, 18446532967477018623u); // orr z19.d, z19.d, #0xffff3fffffffffff + __ sve_add(z22, __ D, 103u); // add z22.d, z22.d, #0x67 + __ sve_sub(z8, __ B, 5u); // sub z8.b, z8.b, #0x5 + __ sve_and(z15, __ S, 1u); // and z15.s, z15.s, #0x1 + __ sve_eor(z19, __ D, 18446532967477018623u); // eor z19.d, z19.d, #0xffff3fffffffffff + __ sve_orr(z13, __ S, 7168u); // orr z13.s, z13.s, #0x1c00 // SVEBinaryImmOp - __ sve_add(z13, __ S, 179u); // add z13.s, z13.s, #0xb3 - __ sve_sub(z2, __ B, 88u); // sub z2.b, z2.b, #0x58 - __ sve_and(z20, __ H, 57855u); // and z20.h, z20.h, #0xe1ff - __ sve_eor(z24, __ H, 33279u); // eor z24.h, z24.h, #0x81ff - __ sve_orr(z20, __ S, 917504u); // orr z20.s, z20.s, #0xe0000 + __ sve_add(z1, __ H, 164u); // add z1.h, z1.h, #0xa4 + __ sve_sub(z12, __ S, 194u); // sub z12.s, z12.s, #0xc2 + __ sve_and(z24, __ H, 33279u); // and z24.h, z24.h, #0x81ff + __ sve_eor(z20, __ S, 917504u); // eor z20.s, z20.s, #0xe0000 + __ sve_orr(z21, __ H, 57343u); // orr z21.h, z21.h, #0xdfff // SVEBinaryImmOp - __ sve_add(z21, __ H, 247u); // add z21.h, z21.h, #0xf7 - __ sve_sub(z22, __ D, 253u); // sub z22.d, z22.d, #0xfd - __ sve_and(z26, __ S, 1610637312u); // and z26.s, z26.s, #0x60006000 - __ sve_eor(z11, __ H, 51199u); // eor z11.h, z11.h, #0xc7ff - __ sve_orr(z5, __ B, 128u); // orr z5.b, z5.b, #0x80 + __ sve_add(z31, __ D, 213u); // add z31.d, z31.d, #0xd5 + __ sve_sub(z18, __ S, 120u); // sub z18.s, z18.s, #0x78 + __ sve_and(z11, __ H, 51199u); // and z11.h, z11.h, #0xc7ff + __ sve_eor(z5, __ B, 128u); // eor z5.b, z5.b, #0x80 + __ sve_orr(z2, __ B, 124u); // orr z2.b, z2.b, #0x7c // SVEVectorOp - __ sve_add(z2, __ H, z7, z10); // add z2.h, z7.h, z10.h - __ sve_sub(z19, __ H, z4, z26); // sub z19.h, z4.h, z26.h - __ sve_fadd(z2, __ S, z3, z30); // fadd z2.s, z3.s, z30.s - __ sve_fmul(z20, __ D, z5, z20); // fmul z20.d, z5.d, z20.d - __ sve_fsub(z29, __ S, z13, z13); // fsub z29.s, z13.s, z13.s - __ sve_sqadd(z14, __ H, z30, z1); // sqadd z14.h, z30.h, z1.h - __ sve_sqsub(z28, __ D, z3, z3); // sqsub z28.d, z3.d, z3.d - __ sve_uqadd(z9, __ B, z25, z9); // uqadd z9.b, z25.b, z9.b - __ sve_uqsub(z26, __ B, z10, z14); // uqsub z26.b, z10.b, z14.b - __ sve_abs(z20, __ D, p6, z7); // abs z20.d, p6/m, z7.d - __ sve_add(z20, __ D, p4, z6); // add z20.d, p4/m, z20.d, z6.d - __ sve_and(z13, __ H, p0, z29); // and z13.h, p0/m, z13.h, z29.h - __ sve_asr(z9, __ B, p0, z1); // asr z9.b, p0/m, z9.b, z1.b - __ sve_bic(z27, __ B, p6, z15); // bic z27.b, p6/m, z27.b, z15.b - __ sve_clz(z4, __ D, p7, z17); // clz z4.d, p7/m, z17.d - __ sve_cnt(z2, __ B, p0, z24); // cnt z2.b, p0/m, z24.b - __ sve_eor(z26, __ B, p7, z13); // eor z26.b, p7/m, z26.b, z13.b - __ sve_lsl(z22, __ D, p3, z16); // lsl z22.d, p3/m, z22.d, z16.d - __ sve_lsr(z17, __ D, p1, z11); // lsr z17.d, p1/m, z17.d, z11.d - __ sve_mul(z16, __ B, p0, z16); // mul z16.b, p0/m, z16.b, z16.b - __ sve_neg(z28, __ D, p1, z23); // neg z28.d, p1/m, z23.d - __ sve_not(z28, __ S, p4, z10); // not z28.s, p4/m, z10.s - __ sve_orr(z17, __ S, p7, z7); // orr z17.s, p7/m, z17.s, z7.s - __ sve_rbit(z4, __ H, p3, z24); // rbit z4.h, p3/m, z24.h - __ sve_revb(z9, __ H, p2, z11); // revb z9.h, p2/m, z11.h - __ sve_smax(z4, __ S, p5, z22); // smax z4.s, p5/m, z4.s, z22.s - __ sve_smin(z4, __ H, p0, z15); // smin z4.h, p0/m, z4.h, z15.h - __ sve_umax(z4, __ D, p7, z26); // umax z4.d, p7/m, z4.d, z26.d - __ sve_umin(z5, __ H, p5, z26); // umin z5.h, p5/m, z5.h, z26.h - __ sve_sub(z31, __ B, p0, z25); // sub z31.b, p0/m, z31.b, z25.b - __ sve_fabs(z8, __ D, p1, z3); // fabs z8.d, p1/m, z3.d - __ sve_fadd(z7, __ D, p6, z24); // fadd z7.d, p6/m, z7.d, z24.d - __ sve_fdiv(z24, __ S, p7, z17); // fdiv z24.s, p7/m, z24.s, z17.s - __ sve_fmax(z10, __ S, p3, z30); // fmax z10.s, p3/m, z10.s, z30.s - __ sve_fmin(z8, __ S, p6, z29); // fmin z8.s, p6/m, z8.s, z29.s - __ sve_fmul(z31, __ D, p5, z31); // fmul z31.d, p5/m, z31.d, z31.d - __ sve_fneg(z0, __ D, p5, z7); // fneg z0.d, p5/m, z7.d - __ sve_frintm(z29, __ S, p6, z22); // frintm z29.s, p6/m, z22.s - __ sve_frintn(z29, __ S, p6, z20); // frintn z29.s, p6/m, z20.s - __ sve_frintp(z6, __ S, p4, z18); // frintp z6.s, p4/m, z18.s - __ sve_fsqrt(z26, __ S, p5, z8); // fsqrt z26.s, p5/m, z8.s - __ sve_fsub(z19, __ S, p2, z28); // fsub z19.s, p2/m, z19.s, z28.s - __ sve_fmad(z17, __ D, p1, z30, z20); // fmad z17.d, p1/m, z30.d, z20.d - __ sve_fmla(z28, __ D, p3, z17, z14); // fmla z28.d, p3/m, z17.d, z14.d - __ sve_fmls(z10, __ S, p6, z11, z24); // fmls z10.s, p6/m, z11.s, z24.s - __ sve_fmsb(z11, __ D, p3, z28, z23); // fmsb z11.d, p3/m, z28.d, z23.d - __ sve_fnmad(z20, __ D, p7, z23, z20); // fnmad z20.d, p7/m, z23.d, z20.d - __ sve_fnmsb(z24, __ D, p0, z27, z6); // fnmsb z24.d, p0/m, z27.d, z6.d - __ sve_fnmla(z13, __ D, p3, z4, z13); // fnmla z13.d, p3/m, z4.d, z13.d - __ sve_fnmls(z26, __ S, p5, z20, z6); // fnmls z26.s, p5/m, z20.s, z6.s - __ sve_mla(z29, __ S, p7, z0, z29); // mla z29.s, p7/m, z0.s, z29.s - __ sve_mls(z3, __ D, p1, z5, z8); // mls z3.d, p1/m, z5.d, z8.d - __ sve_and(z13, z17, z13); // and z13.d, z17.d, z13.d - __ sve_eor(z8, z10, z8); // eor z8.d, z10.d, z8.d - __ sve_orr(z19, z0, z29); // orr z19.d, z0.d, z29.d - __ sve_bic(z16, z13, z23); // bic z16.d, z13.d, z23.d - __ sve_uzp1(z23, __ B, z30, z13); // uzp1 z23.b, z30.b, z13.b - __ sve_uzp2(z25, __ H, z22, z0); // uzp2 z25.h, z22.h, z0.h - __ sve_fabd(z25, __ S, p7, z11); // fabd z25.s, p7/m, z25.s, z11.s - __ sve_bext(z14, __ H, z23, z22); // bext z14.h, z23.h, z22.h - __ sve_bdep(z5, __ H, z18, z0); // bdep z5.h, z18.h, z0.h - __ sve_eor3(z9, z2, z3); // eor3 z9.d, z9.d, z2.d, z3.d - __ sve_sqadd(z14, __ H, p1, z29); // sqadd z14.h, p1/m, z14.h, z29.h - __ sve_sqsub(z14, __ D, p5, z4); // sqsub z14.d, p5/m, z14.d, z4.d - __ sve_uqadd(z27, __ S, p3, z22); // uqadd z27.s, p3/m, z27.s, z22.s - __ sve_uqsub(z31, __ S, p6, z11); // uqsub z31.s, p6/m, z31.s, z11.s + __ sve_add(z19, __ H, z4, z26); // add z19.h, z4.h, z26.h + __ sve_sub(z2, __ B, z3, z30); // sub z2.b, z3.b, z30.b + __ sve_fadd(z20, __ D, z5, z20); // fadd z20.d, z5.d, z20.d + __ sve_fmul(z29, __ S, z13, z13); // fmul z29.s, z13.s, z13.s + __ sve_fsub(z14, __ S, z30, z1); // fsub z14.s, z30.s, z1.s + __ sve_sqadd(z28, __ D, z3, z3); // sqadd z28.d, z3.d, z3.d + __ sve_sqsub(z9, __ B, z25, z9); // sqsub z9.b, z25.b, z9.b + __ sve_uqadd(z26, __ B, z10, z14); // uqadd z26.b, z10.b, z14.b + __ sve_uqsub(z20, __ D, z26, z7); // uqsub z20.d, z26.d, z7.d + __ sve_abs(z20, __ D, p4, z6); // abs z20.d, p4/m, z6.d + __ sve_add(z13, __ H, p0, z29); // add z13.h, p0/m, z13.h, z29.h + __ sve_and(z9, __ B, p0, z1); // and z9.b, p0/m, z9.b, z1.b + __ sve_asr(z27, __ B, p6, z15); // asr z27.b, p6/m, z27.b, z15.b + __ sve_bic(z4, __ D, p7, z17); // bic z4.d, p7/m, z4.d, z17.d + __ sve_clz(z2, __ B, p0, z24); // clz z2.b, p0/m, z24.b + __ sve_cnt(z26, __ B, p7, z13); // cnt z26.b, p7/m, z13.b + __ sve_eor(z22, __ D, p3, z16); // eor z22.d, p3/m, z22.d, z16.d + __ sve_lsl(z17, __ D, p1, z11); // lsl z17.d, p1/m, z17.d, z11.d + __ sve_lsr(z16, __ B, p0, z16); // lsr z16.b, p0/m, z16.b, z16.b + __ sve_mul(z28, __ D, p1, z23); // mul z28.d, p1/m, z28.d, z23.d + __ sve_neg(z28, __ S, p4, z10); // neg z28.s, p4/m, z10.s + __ sve_not(z17, __ S, p7, z7); // not z17.s, p7/m, z7.s + __ sve_orr(z4, __ H, p3, z24); // orr z4.h, p3/m, z4.h, z24.h + __ sve_rbit(z9, __ B, p2, z11); // rbit z9.b, p2/m, z11.b + __ sve_revb(z4, __ S, p5, z22); // revb z4.s, p5/m, z22.s + __ sve_smax(z4, __ H, p0, z15); // smax z4.h, p0/m, z4.h, z15.h + __ sve_smin(z4, __ D, p7, z26); // smin z4.d, p7/m, z4.d, z26.d + __ sve_umax(z5, __ H, p5, z26); // umax z5.h, p5/m, z5.h, z26.h + __ sve_umin(z31, __ B, p0, z25); // umin z31.b, p0/m, z31.b, z25.b + __ sve_sub(z8, __ S, p1, z3); // sub z8.s, p1/m, z8.s, z3.s + __ sve_fabs(z7, __ D, p6, z24); // fabs z7.d, p6/m, z24.d + __ sve_fadd(z24, __ S, p7, z17); // fadd z24.s, p7/m, z24.s, z17.s + __ sve_fdiv(z10, __ S, p3, z30); // fdiv z10.s, p3/m, z10.s, z30.s + __ sve_fmax(z8, __ S, p6, z29); // fmax z8.s, p6/m, z8.s, z29.s + __ sve_fmin(z31, __ D, p5, z31); // fmin z31.d, p5/m, z31.d, z31.d + __ sve_fmul(z0, __ D, p5, z7); // fmul z0.d, p5/m, z0.d, z7.d + __ sve_fneg(z29, __ S, p6, z22); // fneg z29.s, p6/m, z22.s + __ sve_frintm(z29, __ S, p6, z20); // frintm z29.s, p6/m, z20.s + __ sve_frintn(z6, __ S, p4, z18); // frintn z6.s, p4/m, z18.s + __ sve_frintp(z26, __ S, p5, z8); // frintp z26.s, p5/m, z8.s + __ sve_fsqrt(z19, __ S, p2, z28); // fsqrt z19.s, p2/m, z28.s + __ sve_fsub(z17, __ D, p1, z30); // fsub z17.d, p1/m, z17.d, z30.d + __ sve_fmad(z24, __ S, p7, z14, z17); // fmad z24.s, p7/m, z14.s, z17.s + __ sve_fmla(z19, __ D, p2, z26, z11); // fmla z19.d, p2/m, z26.d, z11.d + __ sve_fmls(z0, __ D, p2, z15, z28); // fmls z0.d, p2/m, z15.d, z28.d + __ sve_fmsb(z23, __ D, p5, z28, z23); // fmsb z23.d, p5/m, z28.d, z23.d + __ sve_fnmad(z29, __ S, p6, z0, z27); // fnmad z29.s, p6/m, z0.s, z27.s + __ sve_fnmsb(z23, __ S, p3, z12, z4); // fnmsb z23.s, p3/m, z12.s, z4.s + __ sve_fnmla(z31, __ S, p6, z23, z20); // fnmla z31.s, p6/m, z23.s, z20.s + __ sve_fnmls(z2, __ D, p7, z29, z0); // fnmls z2.d, p7/m, z29.d, z0.d + __ sve_mla(z23, __ H, p0, z4, z5); // mla z23.h, p0/m, z4.h, z5.h + __ sve_mls(z28, __ H, p3, z17, z13); // mls z28.h, p3/m, z17.h, z13.h + __ sve_and(z8, z10, z8); // and z8.d, z10.d, z8.d + __ sve_eor(z19, z0, z29); // eor z19.d, z0.d, z29.d + __ sve_orr(z16, z13, z23); // orr z16.d, z13.d, z23.d + __ sve_bic(z23, z30, z13); // bic z23.d, z30.d, z13.d + __ sve_uzp1(z25, __ H, z22, z0); // uzp1 z25.h, z22.h, z0.h + __ sve_uzp2(z25, __ H, z30, z11); // uzp2 z25.h, z30.h, z11.h + __ sve_fabd(z14, __ S, p5, z22); // fabd z14.s, p5/m, z14.s, z22.s + __ sve_bext(z5, __ H, z18, z0); // bext z5.h, z18.h, z0.h + __ sve_bdep(z9, __ D, z2, z3); // bdep z9.d, z2.d, z3.d + __ sve_eor3(z14, z4, z29); // eor3 z14.d, z14.d, z4.d, z29.d + __ sve_sqadd(z14, __ D, p5, z4); // sqadd z14.d, p5/m, z14.d, z4.d + __ sve_sqsub(z27, __ S, p3, z22); // sqsub z27.s, p3/m, z27.s, z22.s + __ sve_uqadd(z31, __ S, p6, z11); // uqadd z31.s, p6/m, z31.s, z11.s + __ sve_uqsub(z12, __ B, p4, z28); // uqsub z12.b, p4/m, z12.b, z28.b // SVEReductionOp - __ sve_andv(v12, __ B, p4, z28); // andv b12, p4, z28.b - __ sve_orv(v28, __ D, p4, z4); // orv d28, p4, z4.d - __ sve_eorv(v6, __ S, p0, z15); // eorv s6, p0, z15.s - __ sve_smaxv(v1, __ S, p5, z18); // smaxv s1, p5, z18.s - __ sve_sminv(v2, __ H, p2, z4); // sminv h2, p2, z4.h - __ sve_umaxv(v11, __ S, p2, z28); // umaxv s11, p2, z28.s - __ sve_uminv(v3, __ H, p5, z31); // uminv h3, p5, z31.h - __ sve_fminv(v24, __ S, p5, z15); // fminv s24, p5, z15.s - __ sve_fmaxv(v6, __ S, p3, z8); // fmaxv s6, p3, z8.s - __ sve_fadda(v21, __ D, p7, z4); // fadda d21, p7, d21, z4.d - __ sve_uaddv(v24, __ B, p5, z6); // uaddv d24, p5, z6.b + __ sve_andv(v28, __ D, p4, z4); // andv d28, p4, z4.d + __ sve_orv(v6, __ S, p0, z15); // orv s6, p0, z15.s + __ sve_eorv(v1, __ S, p5, z18); // eorv s1, p5, z18.s + __ sve_smaxv(v2, __ H, p2, z4); // smaxv h2, p2, z4.h + __ sve_sminv(v11, __ S, p2, z28); // sminv s11, p2, z28.s + __ sve_umaxv(v3, __ H, p5, z31); // umaxv h3, p5, z31.h + __ sve_uminv(v24, __ H, p5, z15); // uminv h24, p5, z15.h + __ sve_fminv(v6, __ S, p3, z8); // fminv s6, p3, z8.s + __ sve_fmaxv(v21, __ D, p7, z4); // fmaxv d21, p7, z4.d + __ sve_fadda(v24, __ S, p5, z6); // fadda s24, p5, s24, z6.s + __ sve_uaddv(v4, __ D, p2, z9); // uaddv d4, p2, z9.d // AddWideNEONOp - __ saddwv(v4, v5, __ T8H, v6, __ T8B); // saddw v4.8H, v5.8H, v6.8B - __ saddwv2(v10, v11, __ T8H, v12, __ T16B); // saddw2 v10.8H, v11.8H, v12.16B - __ saddwv(v9, v10, __ T4S, v11, __ T4H); // saddw v9.4S, v10.4S, v11.4H - __ saddwv2(v25, v26, __ T4S, v27, __ T8H); // saddw2 v25.4S, v26.4S, v27.8H - __ saddwv(v10, v11, __ T2D, v12, __ T2S); // saddw v10.2D, v11.2D, v12.2S - __ saddwv2(v5, v6, __ T2D, v7, __ T4S); // saddw2 v5.2D, v6.2D, v7.4S - __ uaddwv(v31, v0, __ T8H, v1, __ T8B); // uaddw v31.8H, v0.8H, v1.8B - __ uaddwv2(v22, v23, __ T8H, v24, __ T16B); // uaddw2 v22.8H, v23.8H, v24.16B - __ uaddwv(v25, v26, __ T4S, v27, __ T4H); // uaddw v25.4S, v26.4S, v27.4H - __ uaddwv2(v15, v16, __ T4S, v17, __ T8H); // uaddw2 v15.4S, v16.4S, v17.8H - __ uaddwv(v3, v4, __ T2D, v5, __ T2S); // uaddw v3.2D, v4.2D, v5.2S - __ uaddwv2(v18, v19, __ T2D, v20, __ T4S); // uaddw2 v18.2D, v19.2D, v20.4S + __ saddwv(v10, v11, __ T8H, v12, __ T8B); // saddw v10.8H, v11.8H, v12.8B + __ saddwv2(v5, v6, __ T8H, v7, __ T16B); // saddw2 v5.8H, v6.8H, v7.16B + __ saddwv(v31, v0, __ T4S, v1, __ T4H); // saddw v31.4S, v0.4S, v1.4H + __ saddwv2(v22, v23, __ T4S, v24, __ T8H); // saddw2 v22.4S, v23.4S, v24.8H + __ saddwv(v25, v26, __ T2D, v27, __ T2S); // saddw v25.2D, v26.2D, v27.2S + __ saddwv2(v15, v16, __ T2D, v17, __ T4S); // saddw2 v15.2D, v16.2D, v17.4S + __ uaddwv(v3, v4, __ T8H, v5, __ T8B); // uaddw v3.8H, v4.8H, v5.8B + __ uaddwv2(v18, v19, __ T8H, v20, __ T16B); // uaddw2 v18.8H, v19.8H, v20.16B + __ uaddwv(v14, v15, __ T4S, v16, __ T4H); // uaddw v14.4S, v15.4S, v16.4H + __ uaddwv2(v10, v11, __ T4S, v12, __ T8H); // uaddw2 v10.4S, v11.4S, v12.8H + __ uaddwv(v2, v3, __ T2D, v4, __ T2S); // uaddw v2.2D, v3.2D, v4.2S + __ uaddwv2(v10, v11, __ T2D, v12, __ T4S); // uaddw2 v10.2D, v11.2D, v12.4S __ bind(forth); @@ -1463,312 +1469,313 @@ 0x9101a1a0, 0xb10a5cc8, 0xd10810aa, 0xf10fd061, 0x120cb166, 0x321764bc, 0x52174681, 0x720c0227, 0x9241018e, 0xb25a2969, 0xd278b411, 0xf26aad01, - 0x14000000, 0x17ffffd7, 0x140004c9, 0x94000000, - 0x97ffffd4, 0x940004c6, 0x3400000a, 0x34fffa2a, - 0x3400986a, 0x35000008, 0x35fff9c8, 0x35009808, - 0xb400000b, 0xb4fff96b, 0xb40097ab, 0xb500001d, - 0xb5fff91d, 0xb500975d, 0x10000013, 0x10fff8b3, - 0x100096f3, 0x90000013, 0x36300016, 0x3637f836, - 0x36309676, 0x3758000c, 0x375ff7cc, 0x3758960c, + 0x14000000, 0x17ffffd7, 0x140004cb, 0x94000000, + 0x97ffffd4, 0x940004c8, 0x3400000a, 0x34fffa2a, + 0x340098aa, 0x35000008, 0x35fff9c8, 0x35009848, + 0xb400000b, 0xb4fff96b, 0xb40097eb, 0xb500001d, + 0xb5fff91d, 0xb500979d, 0x10000013, 0x10fff8b3, + 0x10009733, 0x90000013, 0x36300016, 0x3637f836, + 0x363096b6, 0x3758000c, 0x375ff7cc, 0x3758964c, 0x128313a0, 0x528a32c7, 0x7289173b, 0x92ab3acc, 0xd2a0bf94, 0xf2c285e8, 0x9358722f, 0x330e652f, 0x53067f3b, 0x93577c53, 0xb34a1aac, 0xd35a4016, 0x13946c63, 0x93c3dbc8, 0x54000000, 0x54fff5a0, - 0x540093e0, 0x54000001, 0x54fff541, 0x54009381, - 0x54000002, 0x54fff4e2, 0x54009322, 0x54000002, - 0x54fff482, 0x540092c2, 0x54000003, 0x54fff423, - 0x54009263, 0x54000003, 0x54fff3c3, 0x54009203, - 0x54000004, 0x54fff364, 0x540091a4, 0x54000005, - 0x54fff305, 0x54009145, 0x54000006, 0x54fff2a6, - 0x540090e6, 0x54000007, 0x54fff247, 0x54009087, - 0x54000008, 0x54fff1e8, 0x54009028, 0x54000009, - 0x54fff189, 0x54008fc9, 0x5400000a, 0x54fff12a, - 0x54008f6a, 0x5400000b, 0x54fff0cb, 0x54008f0b, - 0x5400000c, 0x54fff06c, 0x54008eac, 0x5400000d, - 0x54fff00d, 0x54008e4d, 0x5400000e, 0x54ffefae, - 0x54008dee, 0x5400000f, 0x54ffef4f, 0x54008d8f, + 0x54009420, 0x54000001, 0x54fff541, 0x540093c1, + 0x54000002, 0x54fff4e2, 0x54009362, 0x54000002, + 0x54fff482, 0x54009302, 0x54000003, 0x54fff423, + 0x540092a3, 0x54000003, 0x54fff3c3, 0x54009243, + 0x54000004, 0x54fff364, 0x540091e4, 0x54000005, + 0x54fff305, 0x54009185, 0x54000006, 0x54fff2a6, + 0x54009126, 0x54000007, 0x54fff247, 0x540090c7, + 0x54000008, 0x54fff1e8, 0x54009068, 0x54000009, + 0x54fff189, 0x54009009, 0x5400000a, 0x54fff12a, + 0x54008faa, 0x5400000b, 0x54fff0cb, 0x54008f4b, + 0x5400000c, 0x54fff06c, 0x54008eec, 0x5400000d, + 0x54fff00d, 0x54008e8d, 0x5400000e, 0x54ffefae, + 0x54008e2e, 0x5400000f, 0x54ffef4f, 0x54008dcf, 0xd40658e1, 0xd4014d22, 0xd4046543, 0xd4273f60, 0xd44cad80, 0xd503201f, 0xd503203f, 0xd503205f, 0xd503209f, 0xd50320bf, 0xd503219f, 0xd50323bf, 0xd503239f, 0xd50321df, 0xd50323ff, 0xd50323df, 0xd503211f, 0xd503233f, 0xd503231f, 0xd503215f, 0xd503237f, 0xd503235f, 0xd69f03e0, 0xd6bf03e0, - 0xd5033fdf, 0xd50330ff, 0xd503207f, 0xd50320ff, - 0xd5033e9f, 0xd50332bf, 0xd61f0200, 0xd63f0280, - 0xdac123ea, 0xdac127fb, 0xdac12be8, 0xdac12fe0, - 0xdac133e1, 0xdac137f5, 0xdac13bf1, 0xdac13ffd, - 0xdac147fd, 0xd61f0b9f, 0xd61f0c3f, 0xd63f0aff, - 0xd63f0ebf, 0xd51b4434, 0xd51b4216, 0xd53b443b, - 0xd53b4213, 0xd53b00eb, 0xd53b0030, 0xdac143e6, - 0xc8117c80, 0xc80afed8, 0xc85f7e6a, 0xc85ffca1, - 0xc89ffd1e, 0xc8dffe2c, 0x88097cee, 0x8801fe05, - 0x885f7d82, 0x885ffd8a, 0x889fff83, 0x88dfff4e, - 0x481e7dca, 0x4815fd2d, 0x485f7f76, 0x485ffe7c, - 0x489fffcb, 0x48dffc53, 0x08027c37, 0x0800fe0c, - 0x085f7ded, 0x085ffeb1, 0x089ffd6d, 0x08dffd1e, - 0xc87f3578, 0xc87feaa1, 0xc83b506d, 0xc82c87a6, - 0x887f1166, 0x887f93d0, 0x883e32a4, 0x883bf12f, - 0xf80011f9, 0xb81b1022, 0x381ea354, 0x79002fd7, - 0xf85cf39a, 0xb8580309, 0x385e218c, 0x784051e1, - 0x389e11d8, 0x789fa1f8, 0x79c01865, 0xb881131b, - 0xfc5dd3ad, 0xbc5d1137, 0xfc00900b, 0xbc181015, - 0xf818ec7d, 0xb81b8c91, 0x381efc40, 0x78007c3d, - 0xf857beb0, 0xb8413dd4, 0x385fddd6, 0x78409e2f, - 0x389eddea, 0x789e7d94, 0x78de3d55, 0xb8805c13, - 0xfc5cadc0, 0xbc428c23, 0xfc1a2dc4, 0xbc1caf92, - 0xf81475f6, 0xb81f95d1, 0x381e757e, 0x78014561, - 0xf8402436, 0xb85896e2, 0x385f4763, 0x785db4f0, - 0x3880374f, 0x789e25e7, 0x78dd0563, 0xb88166f9, - 0xfc529540, 0xbc4374d3, 0xfc1166ae, 0xbc1ba6c0, - 0xf820ea7b, 0xb82d68c8, 0x38367a04, 0x782f4b59, - 0xf878c8a4, 0xb8674a24, 0x386b78f1, 0x78776bc0, - 0x38a15aca, 0x78bedbd5, 0x78fcd94b, 0xb8aa4a7c, - 0xfc6ecbbe, 0xbc65d8a8, 0xfc2de919, 0xbc3a7b11, - 0xf91f1193, 0xb91ed5f7, 0x391ec9bd, 0x79182ceb, - 0xf95d4b0a, 0xb9581010, 0x395fc034, 0x795fb221, - 0x399d8731, 0x799efb3b, 0x79dd1a2e, 0xb998e4ea, - 0xfd583723, 0xbd5ea12c, 0xfd18dc38, 0xbd1b0e83, - 0x58ffda82, 0x1800001d, 0xf885d1c0, 0xd8ffda20, - 0xf8a77820, 0xf9980220, 0x1a030301, 0x3a140311, - 0x5a0d000b, 0x7a07015c, 0x9a1001e4, 0xba140182, - 0xda0d01bd, 0xfa0c00ce, 0x0b31f194, 0x2b206d7b, - 0xcb29f027, 0x6b210f63, 0x8b2cb34d, 0xab2a88b1, - 0xcb2f511e, 0xeb3332f3, 0x3a4533aa, 0x7a4d312b, - 0xba442146, 0xfa42818c, 0x3a466a02, 0x7a4b68ed, - 0xba4a9b6b, 0xfa4dd86d, 0x1a8a637a, 0x1a9cd6aa, - 0x5a9bd137, 0x5a8fd7aa, 0x9a95233e, 0x9a95c620, - 0xda9422b0, 0xda8397d3, 0x5ac00173, 0x5ac00418, - 0x5ac00b3b, 0x5ac0106e, 0x5ac0162e, 0xdac001e7, - 0xdac00798, 0xdac00b31, 0xdac00f42, 0xdac010bc, - 0xdac01759, 0xdac1021b, 0xdac104d1, 0xdac10995, - 0xdac10c80, 0xdac1136c, 0xdac11791, 0xdac1185c, - 0xdac11d51, 0xd71f09ee, 0xd71f0dc3, 0xd73f0b2f, - 0xd73f0e6e, 0x1ac40a05, 0x1ac40f3a, 0x1acc2042, - 0x1ac8263d, 0x1ac42867, 0x1ada2c99, 0x9ad10899, - 0x9ad10f40, 0x9ad521f7, 0x9adb263c, 0x9ac0286a, - 0x9ac92f27, 0x9bdd7de6, 0x9b427d4f, 0x1b0b2cf1, - 0x1b1ddcf7, 0x9b0b2f6e, 0x9b0cbf04, 0x9b2b728e, - 0x9b2cdd6d, 0x9bae275e, 0x9ba7954d, 0x7ec315fe, - 0x1ef0098c, 0x1ef21bff, 0x1ef02ab3, 0x1ef5394f, - 0x1efc4942, 0x1eff5bc7, 0x1ee28832, 0x7ea3d546, - 0x1e270979, 0x1e201981, 0x1e3d2a63, 0x1e263ae6, - 0x1e3b4b80, 0x1e2758a2, 0x1e39899d, 0x7ef8d58d, - 0x1e720913, 0x1e751b56, 0x1e622a74, 0x1e683ade, - 0x1e754a76, 0x1e755a4c, 0x1e638a06, 0x1fc373a3, - 0x1f0a35cf, 0x1f0aea4c, 0x1f2f74e7, 0x1f2032e0, - 0x1f4d21d8, 0x1f49d0ef, 0x1f7f43b3, 0x1f705522, - 0x1e20409e, 0x1e20c361, 0x1e214319, 0x1e21c2ae, - 0x1e22c0cd, 0x1e23c32c, 0x1ee243d9, 0x1e6042bc, - 0x1e60c2f0, 0x1e6143a5, 0x1e61c276, 0x1e62428d, - 0x1ee1c393, 0x1e3800d1, 0x9e3800ed, 0x1e78035c, - 0x9e7800d1, 0x1e220081, 0x9e22028e, 0x1e6202a7, - 0x9e6202fb, 0x1e24028d, 0x9e64039e, 0x1e3002aa, - 0x9e700225, 0x1e2601cb, 0x9e6602ad, 0x1e2701db, - 0x9e6702e4, 0x1e3e2300, 0x1e6e2180, 0x1e202228, - 0x1e602388, 0x29021b40, 0x297c78c0, 0x69660970, - 0xa908018f, 0xa9427ae7, 0x29a03cfa, 0x29fc3d4b, - 0x69c84033, 0xa988240e, 0xa9fa0d9b, 0x28a02d88, - 0x28c8408a, 0x68f87a6a, 0xa8ba09f8, 0xa8c52a18, - 0x280257be, 0x28727948, 0xa83868de, 0xa8440a98, - 0x0c40733f, 0x4cdfa1e5, 0x0ccd6cea, 0x4cdf260d, - 0x0d40c227, 0x4ddfcb30, 0x0dc7cc6b, 0x4c408ced, - 0x0cdf8769, 0x4d60c346, 0x0dffca17, 0x4de8cda6, - 0x4cda4834, 0x0c4049ef, 0x4d40e6dd, 0x4ddfe946, - 0x0dcfeccf, 0x4cdf0546, 0x0cc7006b, 0x0d60e32c, - 0x0dffe5eb, 0x0dfce8de, 0x0e31bb9b, 0x4e31bbbc, - 0x0e71b841, 0x4e71bbbc, 0x4eb1b841, 0x0e30aab4, - 0x4e30abdd, 0x0e70aa30, 0x4e70a9cd, 0x4eb0a96a, - 0x6e30fbdd, 0x0e31abdd, 0x2e31aa93, 0x4e31aaf6, - 0x6e31a96a, 0x0e71a8a4, 0x2e71a81f, 0x4e71aad5, - 0x6e71a928, 0x4eb1a81f, 0x6eb1aa93, 0x6eb0f96a, - 0x7e30fbbc, 0x7e70f862, 0x7eb0fb59, 0x7ef0f8c5, - 0x0ea0c883, 0x4ea0c928, 0x4ee0caf6, 0x2ea0ca93, - 0x6ea0c9cd, 0x6ee0c8c5, 0x0ea0dbdd, 0x4ea0db38, - 0x4ee0dad5, 0x0ea0eb7a, 0x4ea0eb38, 0x4ee0e883, - 0x2ea0db38, 0x6ea0db7a, 0x6ee0db17, 0x0e20ba0f, - 0x4e20bad5, 0x0e60b883, 0x4e60bb38, 0x0ea0b928, - 0x4ea0bb59, 0x4ee0bab4, 0x0ea0fa30, 0x4ea0fa51, - 0x4ee0f862, 0x0ef8f841, 0x4ef8f820, 0x2ea0fb38, - 0x6ea0f8a4, 0x6ee0f883, 0x2ef8f9ac, 0x6ef8f81f, - 0x2ea1fbbc, 0x6ea1f96a, 0x6ee1fb7a, 0x2ef9f862, - 0x6ef9f9ac, 0x2e205a72, 0x6e20581f, 0x0e231c41, - 0x4e2f1dcd, 0x0ebf1fdd, 0x4ea21c20, 0x2e351e93, - 0x6e2e1dac, 0x0e338651, 0x4e3886f6, 0x0e6f85cd, - 0x4e7e87bc, 0x0ea087fe, 0x4ea1841f, 0x4ee38441, - 0x0e3c0f7a, 0x4e3e0fbc, 0x0e660ca4, 0x4e600ffe, - 0x0ea60ca4, 0x4ea80ce6, 0x4ee00ffe, 0x2e3c0f7a, - 0x6e340e72, 0x2e6b0d49, 0x6e6a0d28, 0x2eae0dac, - 0x6ea20c20, 0x6ef60eb4, 0x0e23d441, 0x4e3ad738, - 0x4e64d462, 0x0e421420, 0x4e4b1549, 0x2e3a8738, - 0x6e3c877a, 0x2e728630, 0x6e6087fe, 0x2ea58483, - 0x6eac856a, 0x6ef98717, 0x0e2c2d6a, 0x4e262ca4, - 0x0e742e72, 0x4e642c62, 0x0ead2d8b, 0x4eaa2d28, - 0x4eec2d6a, 0x2e312e0f, 0x6e332e51, 0x2e642c62, - 0x6e6c2d6a, 0x2eae2dac, 0x6eae2dac, 0x6ef12e0f, - 0x0eafd5cd, 0x4ea4d462, 0x4ee9d507, 0x0ed616b4, - 0x4edc177a, 0x0e329e30, 0x4e269ca4, 0x0e649c62, - 0x4e669ca4, 0x0eae9dac, 0x4eb49e72, 0x2eb7d6d5, - 0x6eb2d630, 0x6ef4d672, 0x2ecd158b, 0x6ed716d5, - 0x2e39d717, 0x6e2ed5ac, 0x6e7cd77a, 0x2e591717, - 0x6e5e17bc, 0x2e30ddee, 0x6e2ddd8b, 0x6e7adf38, - 0x2e431c41, 0x6e4e1dac, 0x0e61941f, 0x4e6c956a, - 0x0eb29630, 0x4ea99507, 0x0e24cc62, 0x4e25cc83, - 0x4e6fcdcd, 0x0e550e93, 0x4e530e51, 0x2e729630, - 0x6e659483, 0x2ea39441, 0x6ead958b, 0x0ea0cffe, - 0x4ea7ccc5, 0x4eeacd28, 0x0ed10e0f, 0x4edf0fdd, - 0x2e20fffe, 0x6e22fc20, 0x6e76feb4, 0x2e493d07, - 0x6e563eb4, 0x0e396717, 0x4e3e67bc, 0x0e7766d5, - 0x4e7d679b, 0x0ebb6759, 0x4ea764c5, 0x2e236441, - 0x6e396717, 0x2e726630, 0x6e61641f, 0x2ea764c5, - 0x6eae65ac, 0x0e2ba549, 0x4e3ea7bc, 0x0e71a60f, - 0x4e7fa7dd, 0x0eb8a6f6, 0x4ea1a41f, 0x0e35f693, - 0x4e21f41f, 0x4e67f4c5, 0x0e5035ee, 0x4e543672, - 0x0e216c1f, 0x4e346e72, 0x0e7d6f9b, 0x4e766eb4, - 0x0eb26e30, 0x4eae6dac, 0x2e2d6d8b, 0x6e2b6d49, - 0x2e686ce6, 0x6e606ffe, 0x2eb36e51, 0x6ebd6f9b, - 0x0e3eafbc, 0x4e20affe, 0x0e69ad07, 0x4e6cad6a, - 0x0eb6aeb4, 0x4eacad6a, 0x2e26aca4, 0x6e3aaf38, - 0x2e73ae51, 0x6e73ae51, 0x2eb8aef6, 0x6ea5ac83, - 0x2e3fa7dd, 0x6e31a60f, 0x2e78a6f6, 0x6e75a693, - 0x2eb5a693, 0x6eb8a6f6, 0x0e64b462, 0x4e71b60f, - 0x0ea8b4e6, 0x4eaeb5ac, 0x0e322630, 0x4e2d258b, - 0x0e6f25cd, 0x4e792717, 0x0ea32441, 0x4ea027fe, - 0x0eb5f693, 0x4ea7f4c5, 0x4ef3f651, 0x0ec43462, - 0x4ed23630, 0x2eb8eef6, 0x6eafedcd, 0x6eeced6a, - 0x2ed72ed5, 0x6edf2fdd, 0x0fa810e6, 0x4fa38841, - 0x4fc1100f, 0x0fab5149, 0x4f8688a4, 0x4fcf59cd, - 0x2f859083, 0x4f8d898b, 0x6fce99ac, 0x0f41800f, - 0x4f6b8949, 0x0f8d818b, 0x4f838841, 0x0e343672, - 0x4e223420, 0x0e7b3759, 0x4e7c377a, 0x0eb93717, - 0x4ea43462, 0x4ef43672, 0x0e2e3dac, 0x4e263ca4, - 0x0e7e3fbc, 0x4e603ffe, 0x0ebf3fdd, 0x4eb23e30, - 0x4efd3f9b, 0x2e288ce6, 0x6e2b8d49, 0x2e7f8fdd, - 0x6e748e72, 0x2ea98d07, 0x6ea68ca4, 0x6ee98d07, - 0x2e31360f, 0x6e2b3549, 0x2e793717, 0x6e6a3528, - 0x2ea43462, 0x6ebe37bc, 0x6ef736d5, 0x2e213c1f, - 0x6e273cc5, 0x2e7d3f9b, 0x6e623c20, 0x2eb33e51, - 0x6eb13e0f, 0x6ee63ca4, 0x0e3ce77a, 0x4e2ae528, - 0x4e7ee7bc, 0x2eb8e6f6, 0x6ebde79b, 0x6efde79b, - 0x2e3be759, 0x6e39e717, 0x6e62e420, 0x65d220c2, - 0x659029f2, 0x65903ca3, 0x65d13683, 0x65913173, - 0x65d320cf, 0x25cb83c6, 0x254c0fbb, 0x251e0308, - 0x25473a05, 0x25943096, 0x259d9270, 0x2423d187, - 0x242786fa, 0x24f0f1b9, 0x24e42043, 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, 0x0ef9b820, 0x4ef9b820, - 0x4e21c862, 0x0e79c862, 0x4e79c862, 0x4e61b8a4, - 0x0e79b8a4, 0x4e79b8a4, 0x05a08020, 0x05104fe0, - 0x05505001, 0x05906fe2, 0x05d03005, 0x05101fea, - 0x05901feb, 0x0590cc0b, 0x0590de0b, 0x04b0e3e0, - 0x0470e7e1, 0x042f9c20, 0x043f9c35, 0x047f9c20, - 0x04ff9c20, 0x04299420, 0x04319160, 0x0461943e, - 0x04a19020, 0x04038100, 0x040381a0, 0x040387e1, - 0x04438be2, 0x04c38fe3, 0x040181e0, 0x04018100, - 0x04018621, 0x04418b22, 0x04418822, 0x04818c23, - 0x040081e0, 0x04008120, 0x04008761, 0x04008621, - 0x04408822, 0x04808c23, 0x042053ff, 0x047f5401, - 0x25208028, 0x2538cfe0, 0x2578d001, 0x25b8efe2, - 0x25f8f007, 0x2538dfea, 0x25b8dfeb, 0xa400a3e0, - 0xa420a7e0, 0xa4484be0, 0xa467afe0, 0xa4a8a7ea, - 0xa547a814, 0xa4084ffe, 0xa55c53e0, 0xa5e1540b, - 0xe400fbf6, 0xe408ffff, 0xe420e7e0, 0xe4484be0, - 0xe460efe0, 0xe547e400, 0xe4014be0, 0xe4a84fe0, - 0xe5f15000, 0x858043e0, 0x85a043ff, 0xe59f5d08, - 0x0420e3e9, 0x0460e3ea, 0x04a0e3eb, 0x04e0e3ec, - 0x25104042, 0x25104871, 0x25904861, 0x25904c92, - 0x05344020, 0x05744041, 0x05b44062, 0x05f44083, - 0x252c8840, 0x253c1420, 0x25681572, 0x25a21ce3, - 0x25ea1e34, 0x253c0421, 0x25680572, 0x25a20ce3, - 0x25ea0e34, 0x0522c020, 0x05e6c0a4, 0x2401a001, - 0x2443a051, 0x24858881, 0x24c78cd1, 0x24850891, - 0x24c70cc1, 0x250f9001, 0x25508051, 0x25802491, - 0x25df28c1, 0x25850c81, 0x251e10d1, 0x65816001, - 0x65c36051, 0x65854891, 0x65c74cc1, 0x05733820, - 0x05b238a4, 0x05f138e6, 0x0570396a, 0x65d0a001, - 0x65d6a443, 0x65d4a826, 0x6594ac26, 0x6554ac26, - 0x6556ac26, 0x6552ac26, 0x65cbac85, 0x65caac01, - 0x6589ac85, 0x6588ac01, 0x65c9ac85, 0x65c8ac01, - 0x65dea833, 0x659ca509, 0x65d8a801, 0x65dcac01, - 0x655cb241, 0x0520a1e0, 0x0521a601, 0x052281e0, - 0x05238601, 0x04a14026, 0x042244a6, 0x046344a6, - 0x04a444a6, 0x04e544a7, 0x0568aca7, 0x05b23230, - 0x05302a30, 0x05702a30, 0x05b02a30, 0x05f02a30, - 0x853040af, 0xc5b040af, 0xe57080af, 0xe5b080af, - 0x25034440, 0x254054c4, 0x25034640, 0x25415a05, - 0x25834440, 0x25c54489, 0x250b5d3a, 0x2550dc20, - 0x2518e3e1, 0x2518e021, 0x2518e0a1, 0x2518e121, - 0x2518e1a1, 0x2558e3e2, 0x2558e042, 0x2558e0c2, - 0x2558e142, 0x2598e3e3, 0x2598e063, 0x2598e0e3, - 0x2598e163, 0x25d8e3e4, 0x25d8e084, 0x25d8e104, - 0x25d8e184, 0x2518e407, 0x05214800, 0x05614800, - 0x05a14800, 0x05e14800, 0x05214c00, 0x05614c00, - 0x05a14c00, 0x05e14c00, 0x05304001, 0x05314001, - 0x05a18610, 0x05e18610, 0x0420bc31, 0x05271e11, - 0x6545e891, 0x6585e891, 0x65c5e891, 0x6545c891, - 0x6585c891, 0x65c5c891, 0x052c8020, 0x056c8020, - 0x05ac8020, 0x05ec8020, 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, - 0xf8268290, 0xf82d028c, 0xf8281299, 0xf8332160, - 0xf8383286, 0xf83f520e, 0xf82640e0, 0xf82f7353, - 0xf82962ea, 0xf8b58396, 0xf8a201e3, 0xf8b310f4, - 0xf8a420fd, 0xf8a03209, 0xf8b45097, 0xf8b042ea, - 0xf8ab70d9, 0xf8bf61b0, 0xf8f7802c, 0xf8ee02a9, - 0xf8f011fa, 0xf8e421e4, 0xf8e833c6, 0xf8e4523d, - 0xf8fd413a, 0xf8ef7162, 0xf8fd60e3, 0xf86182bb, - 0xf870010e, 0xf8701336, 0xf86522b4, 0xf8703217, - 0xf87e5294, 0xf8604264, 0xf8787284, 0xf8646358, - 0xb8338102, 0xb828030e, 0xb83012df, 0xb824203f, - 0xb82a3194, 0xb82050e9, 0xb8384090, 0xb83b7146, - 0xb83b61b8, 0xb8b082df, 0xb8b603f4, 0xb8bd11c9, - 0xb8b42287, 0xb8bc3169, 0xb8ae528c, 0xb8a14138, - 0xb8b3726d, 0xb8b060b0, 0xb8e08183, 0xb8e801ef, - 0xb8f011e4, 0xb8fe2005, 0xb8ea3376, 0xb8e35120, - 0xb8f3415d, 0xb8f87284, 0xb8e763b8, 0xb86e8175, - 0xb87b01ed, 0xb87f11d1, 0xb863221e, 0xb87630f4, - 0xb8745023, 0xb87a4133, 0xb87072b1, 0xb8606044, - 0xce262dd8, 0xce1179d5, 0xce638c6c, 0xce83c537, - 0xce73807c, 0xce7a84f7, 0xcec081d5, 0xce7a8905, - 0x25a0d245, 0x2521c3f1, 0x05808909, 0x05400d2c, - 0x0500154b, 0x25a0c91f, 0x2561db50, 0x0582d157, - 0x054026a8, 0x05001eca, 0x25a0c0b6, 0x25a1da23, - 0x05822dc5, 0x05400e11, 0x0500155e, 0x25e0d502, - 0x25a1de17, 0x0580040c, 0x0540000f, 0x050287b3, - 0x25a0d66d, 0x2521cb02, 0x05801d74, 0x05400d38, - 0x05007854, 0x2560def5, 0x25e1dfb6, 0x05801c3a, - 0x0540158b, 0x05000e05, 0x046a00e2, 0x047a0493, - 0x659e0062, 0x65d408b4, 0x658d05bd, 0x046113ce, - 0x04e3187c, 0x04291729, 0x042e1d5a, 0x04d6b8f4, - 0x04c010d4, 0x045a03ad, 0x04108029, 0x041b19fb, - 0x04d9be24, 0x041aa302, 0x04191dba, 0x04d38e16, - 0x04d18571, 0x04100210, 0x04d7a6fc, 0x049eb15c, - 0x04981cf1, 0x05678f04, 0x05648969, 0x048816c4, - 0x044a01e4, 0x04c91f44, 0x044b1745, 0x0401033f, - 0x04dca468, 0x65c09b07, 0x658d9e38, 0x65868fca, - 0x65879ba8, 0x65c297ff, 0x04ddb4e0, 0x6582badd, - 0x6580ba9d, 0x6581b246, 0x658db51a, 0x65818b93, - 0x65f487d1, 0x65ee0e3c, 0x65b8396a, 0x65f7af8b, - 0x65f4def4, 0x65e6e378, 0x65ed4c8d, 0x65a6769a, - 0x049d5c1d, 0x04c864a3, 0x042d322d, 0x04a83148, - 0x047d3013, 0x04f731b0, 0x052d6bd7, 0x05606ed9, - 0x65889d79, 0x4556b2ee, 0x4540b645, 0x04223869, - 0x445887ae, 0x44da948e, 0x44998edb, 0x449b997f, - 0x041a338c, 0x04d8309c, 0x049921e6, 0x04883641, - 0x044a2882, 0x04892b8b, 0x044b37e3, 0x658735f8, - 0x65862d06, 0x65d83c95, 0x040134d8, 0x0e2610a4, - 0x4e2c116a, 0x0e6b1149, 0x4e7b1359, 0x0eac116a, - 0x4ea710c5, 0x2e21101f, 0x6e3812f6, 0x2e7b1359, - 0x6e71120f, 0x2ea51083, 0x6eb41272, + 0xd5033fdf, 0xd50330ff, 0xd503101a, 0xd503207f, + 0xd50320ff, 0xd503329f, 0xd50339bf, 0xd61f0280, + 0xd63f0140, 0xdac123fb, 0xdac127e8, 0xdac12be0, + 0xdac12fe1, 0xdac133f5, 0xdac137f1, 0xdac13bfd, + 0xdac13ffd, 0xdac147fc, 0xd61f083f, 0xd61f0eff, + 0xd63f0abf, 0xd63f0e9f, 0xd51b4436, 0xd51b421b, + 0xd53b4433, 0xd53b420b, 0xd53b00f0, 0xd53b0026, + 0xd53be0d1, 0xdac143e0, 0xc8047f0a, 0xc816fe6a, + 0xc85f7ca1, 0xc85ffd1e, 0xc89ffe2c, 0xc8dffdc9, + 0x88077ca1, 0x8810fd82, 0x885f7d8a, 0x885fff83, + 0x889fff4e, 0x88dffd5e, 0x480e7db5, 0x4809ff76, + 0x485f7e7c, 0x485fffcb, 0x489ffc53, 0x48dffee2, + 0x08017d80, 0x0810fded, 0x085f7eb1, 0x085ffd6d, + 0x089ffd1e, 0x08dffdb8, 0xc87f074b, 0xc87fedb5, + 0xc83430c3, 0xc821989d, 0x887f2e06, 0x887ff984, + 0x88353f9b, 0x8829d0cf, 0xf8183238, 0xb800a341, + 0x381ef00f, 0x7800d231, 0xf8431325, 0xb858c1f3, + 0x39401c74, 0x785e7093, 0x389fa26e, 0x789cb27c, + 0x78c0d36e, 0xb8988306, 0xfc457052, 0xbc5d0380, + 0xfc01739f, 0xbc02b32b, 0xf8147d0e, 0xb81a3d39, + 0x381f4ef0, 0x781c8d36, 0xf846df0b, 0xb8434e75, + 0x385feee6, 0x78415d07, 0x389e1d84, 0x789fcd68, + 0x78de4eae, 0xb89b9de0, 0xfc41dc5b, 0xbc410ead, + 0xfc010f6c, 0xbc1a5f22, 0xf81eb5aa, 0xb8032427, + 0x3800546a, 0x781df4c5, 0xf85626cd, 0xb859644d, + 0x385e860d, 0x785ea458, 0x389ff6e3, 0x789d5513, + 0x78df86e2, 0xb89a9793, 0xfc5af46f, 0xbc5b17ac, + 0xfc184435, 0xbc19d527, 0xf8226a85, 0xb83ed94e, + 0x383cd824, 0x783af945, 0xf87c7856, 0xb87c780c, + 0x386ff908, 0x786e5ab1, 0x38a8fb11, 0x78bef94a, + 0x78e07af1, 0xb8a07bd9, 0xfc775b05, 0xbc6f7876, + 0xfc30fba4, 0xbc3cda87, 0xf91ff41b, 0xb91f3115, + 0x391c0fb1, 0x791c685b, 0xf9586021, 0xb958b23d, + 0x39598921, 0x795d3077, 0x399d0675, 0x7998d8f3, + 0x79dbd02a, 0xb99d068a, 0xfd5d11a0, 0xbd58d76b, + 0xfd1ac72d, 0xbd1d9c14, 0x5800001a, 0x18ffda33, + 0xf8991100, 0xd8007880, 0xf8a758e0, 0xf9989d80, + 0x1a0b0298, 0x3a1c01a0, 0x5a0400ea, 0x7a02020f, + 0x9a1d028c, 0xba0e01ad, 0xda140186, 0xfa19022c, + 0x0b2b877e, 0x2b21c8ee, 0xcb3ba47d, 0x6b3ae9a0, + 0x8b256a36, 0xab28efd1, 0xcb37ce6a, 0xeb254fa6, + 0x3a498264, 0x7a4a72c2, 0xba4c91aa, 0xfa502303, + 0x3a4b68ed, 0x7a4a9b6b, 0xba4dd86d, 0xfa50cb45, + 0x1a9cd2aa, 0x1a9bd537, 0x5a8fd3aa, 0x5a95273e, + 0x9a95c220, 0x9a9426b0, 0xda8393d3, 0xda980573, + 0x5ac0033b, 0x5ac0046e, 0x5ac00a2e, 0x5ac011e7, + 0x5ac01798, 0xdac00331, 0xdac00742, 0xdac008bc, + 0xdac00f59, 0xdac0121b, 0xdac014d1, 0xdac10195, + 0xdac10480, 0xdac10b6c, 0xdac10f91, 0xdac1105c, + 0xdac11551, 0xdac119cf, 0xdac11c6e, 0xd71f0b2f, + 0xd71f0e6e, 0xd73f08b0, 0xd73f0c9a, 0x1ac20899, + 0x1add0d82, 0x1ac72111, 0x1ad92483, 0x1ad92b44, + 0x1ac02e24, 0x9ad70a3a, 0x9adc0eaf, 0x9aca2371, + 0x9ac72403, 0x9ac62939, 0x9acf2faf, 0x9bd17c4a, + 0x9b4b7d67, 0x1b1d5cf7, 0x1b0baf6e, 0x9b0c3f04, + 0x9b0bf28e, 0x9b2c5d6d, 0x9b2ea75e, 0x9ba7154d, + 0x9ba3adfd, 0x7edf160c, 0x1ef30a5f, 0x1eef1a15, + 0x1ee22aaa, 0x1ee73b8a, 0x1ef24bfe, 0x1ee65841, + 0x1ef9886a, 0x7ea1d4eb, 0x1e23080c, 0x1e261bb3, + 0x1e2028d7, 0x1e223b7c, 0x1e3d48e5, 0x1e2d5b2c, + 0x1e338b0c, 0x7ef6d648, 0x1e740aba, 0x1e7e1853, + 0x1e762916, 0x1e6c3ab3, 0x1e664ab2, 0x1e635870, + 0x1e7c887d, 0x1fca35cf, 0x1f0a6a4c, 0x1f0ff4e7, + 0x1f2032e0, 0x1f2d21d8, 0x1f4950ef, 0x1f5fc3b3, + 0x1f705522, 0x1f616c9e, 0x1e204319, 0x1e20c2ae, + 0x1e2140cd, 0x1e21c32c, 0x1e22c3d9, 0x1e23c2bc, + 0x1ee242f0, 0x1e6043a5, 0x1e60c276, 0x1e61428d, + 0x1e61c393, 0x1e6240d2, 0x1ee1c0ee, 0x1e38035c, + 0x9e3800d1, 0x1e780081, 0x9e7802ad, 0x1e2202a7, + 0x9e2202fb, 0x1e62028d, 0x9e62037f, 0x1e2402aa, + 0x9e640225, 0x1e3001cb, 0x9e7002ad, 0x1e2601da, + 0x9e660304, 0x1e2703b8, 0x9e6701cc, 0x1e3c2220, + 0x1e6022c0, 0x1e2020c8, 0x1e602368, 0x293c30db, + 0x29602e6e, 0x697a31e0, 0xa9025ee9, 0xa975134f, + 0x29ac20d1, 0x29f20887, 0x69fe26ce, 0xa9b0530d, + 0xa9c62d48, 0x28b21618, 0x28f06920, 0x68f00a38, + 0xa8bd45da, 0xa8c357be, 0x28325d51, 0x286c1bda, + 0xa804229e, 0xa8437536, 0x0c40702d, 0x4cdfa201, + 0x0cd36f36, 0x4cdf2759, 0x0d40c1e9, 0x4ddfcb2c, + 0x0dddcdc4, 0x4c408e31, 0x0cdf8777, 0x4d60c302, + 0x0dffc80b, 0x4df6cd82, 0x4ccd49b5, 0x0c40496c, + 0x4d40e5d2, 0x4ddfeab9, 0x0ddbee14, 0x4cdf0420, + 0x0cdd0360, 0x0d60e232, 0x0dffe705, 0x0df4e8bc, + 0x0e31b841, 0x4e31bab4, 0x0e71bbdd, 0x4e71ba30, + 0x4eb1b9cd, 0x0e30a96a, 0x4e30abdd, 0x0e70abdd, + 0x4e70aa93, 0x4eb0aaf6, 0x6e30f96a, 0x0e31a8a4, + 0x2e31a81f, 0x4e31aad5, 0x6e31a928, 0x0e71a81f, + 0x2e71aa93, 0x4e71a96a, 0x6e71abbc, 0x4eb1a862, + 0x6eb1ab59, 0x6eb0f8c5, 0x7e30f883, 0x7e70f928, + 0x7eb0faf6, 0x7ef0fa93, 0x0ea0c9cd, 0x4ea0c8c5, + 0x4ee0cbdd, 0x2ea0cb38, 0x6ea0cad5, 0x6ee0cb7a, + 0x0ea0db38, 0x4ea0d883, 0x4ee0db38, 0x0ea0eb7a, + 0x4ea0eb17, 0x4ee0ea0f, 0x2ea0dad5, 0x6ea0d883, + 0x6ee0db38, 0x0e20b928, 0x4e20bb59, 0x0e60bab4, + 0x4e60ba30, 0x0ea0ba51, 0x4ea0b862, 0x4ee0b841, + 0x0ea0f820, 0x4ea0fb38, 0x4ee0f8a4, 0x0ef8f883, + 0x4ef8f9ac, 0x2ea0f81f, 0x6ea0fbbc, 0x6ee0f96a, + 0x2ef8fb7a, 0x6ef8f862, 0x2ea1f9ac, 0x6ea1fa72, + 0x6ee1f81f, 0x2ef9f841, 0x6ef9f9cd, 0x2e205bdd, + 0x6e205820, 0x0e351e93, 0x4e2e1dac, 0x0eb31e51, + 0x4eb81ef6, 0x2e2f1dcd, 0x6e3e1fbc, 0x0e2087fe, + 0x4e21841f, 0x0e638441, 0x4e7c877a, 0x0ebe87bc, + 0x4ea684a4, 0x4ee087fe, 0x0e260ca4, 0x4e280ce6, + 0x0e600ffe, 0x4e7c0f7a, 0x0eb40e72, 0x4eab0d49, + 0x4eea0d28, 0x2e2e0dac, 0x6e220c20, 0x2e760eb4, + 0x6e630c41, 0x2eba0f38, 0x6ea40c62, 0x6ee20c20, + 0x0e2bd549, 0x4e3ad738, 0x4e7cd77a, 0x0e521630, + 0x4e4017fe, 0x2e258483, 0x6e2c856a, 0x2e798717, + 0x6e6c856a, 0x2ea684a4, 0x6eb48672, 0x6ee48462, + 0x0e2d2d8b, 0x4e2a2d28, 0x0e6c2d6a, 0x4e712e0f, + 0x0eb32e51, 0x4ea42c62, 0x4eec2d6a, 0x2e2e2dac, + 0x6e2e2dac, 0x2e712e0f, 0x6e6f2dcd, 0x2ea42c62, + 0x6ea92d07, 0x6ef62eb4, 0x0ebcd77a, 0x4eb2d630, + 0x4ee6d4a4, 0x0ec41462, 0x4ec614a4, 0x0e2e9dac, + 0x4e349e72, 0x0e779ed5, 0x4e729e30, 0x0eb49e72, + 0x4ead9d8b, 0x2eb7d6d5, 0x6eb9d717, 0x6eeed5ac, + 0x2edc177a, 0x6ed91717, 0x2e3ed7bc, 0x6e30d5ee, + 0x6e6dd58b, 0x2e5a1738, 0x6e431441, 0x2e2eddac, + 0x6e21dc1f, 0x6e6cdd6a, 0x2e521e30, 0x6e491d07, + 0x0e649462, 0x4e659483, 0x0eaf95cd, 0x4eb59693, + 0x0e33ce51, 0x4e32ce30, 0x4e65cc83, 0x0e430c41, + 0x4e4d0d8b, 0x2e6097fe, 0x6e6794c5, 0x2eaa9528, + 0x6eb1960f, 0x0ebfcfdd, 0x4ea0cffe, 0x4ee2cc20, + 0x0ed60eb4, 0x4ec90d07, 0x2e36feb4, 0x6e39ff17, + 0x6e7effbc, 0x2e573ed5, 0x6e5d3f9b, 0x0e3b6759, + 0x4e2764c5, 0x0e636441, 0x4e796717, 0x0eb26630, + 0x4ea1641f, 0x2e2764c5, 0x6e2e65ac, 0x2e6b6549, + 0x6e7e67bc, 0x2eb1660f, 0x6ebf67dd, 0x0e38a6f6, + 0x4e21a41f, 0x0e75a693, 0x4e61a41f, 0x0ea7a4c5, + 0x4eb0a5ee, 0x0e34f672, 0x4e21f41f, 0x4e74f672, + 0x0e5d379b, 0x4e5636b4, 0x0e326e30, 0x4e2e6dac, + 0x0e6d6d8b, 0x4e6b6d49, 0x0ea86ce6, 0x4ea06ffe, + 0x2e336e51, 0x6e3d6f9b, 0x2e7e6fbc, 0x6e606ffe, + 0x2ea96d07, 0x6eac6d6a, 0x0e36aeb4, 0x4e2cad6a, + 0x0e66aca4, 0x4e7aaf38, 0x0eb3ae51, 0x4eb3ae51, + 0x2e38aef6, 0x6e25ac83, 0x2e7fafdd, 0x6e71ae0f, + 0x2eb8aef6, 0x6eb5ae93, 0x2e35a693, 0x6e38a6f6, + 0x2e64a462, 0x6e71a60f, 0x2ea8a4e6, 0x6eaea5ac, + 0x0e72b630, 0x4e6db58b, 0x0eafb5cd, 0x4eb9b717, + 0x0e232441, 0x4e2027fe, 0x0e752693, 0x4e6724c5, + 0x0eb32651, 0x4ea42462, 0x0eb2f630, 0x4eb8f6f6, + 0x4eeff5cd, 0x0ecc356a, 0x4ed736d5, 0x2ebfefdd, + 0x6ebdef9b, 0x6eeeedac, 0x2edd2f9b, 0x6ec52c83, + 0x0f81100f, 0x4fab8949, 0x4fc618a4, 0x0faf51cd, + 0x4fa58083, 0x4fcd598b, 0x2fae91ac, 0x4f81800f, + 0x6fcb9949, 0x0f5d818b, 0x4f438841, 0x0fa28020, + 0x4faf89cd, 0x0e393717, 0x4e243462, 0x0e743672, + 0x4e6e35ac, 0x0ea634a4, 0x4ebe37bc, 0x4ee037fe, + 0x0e3f3fdd, 0x4e323e30, 0x0e7d3f9b, 0x4e683ce6, + 0x0eab3d49, 0x4ebf3fdd, 0x4ef43e72, 0x2e298d07, + 0x6e268ca4, 0x2e698d07, 0x6e718e0f, 0x2eab8d49, + 0x6eb98f17, 0x6eea8d28, 0x2e243462, 0x6e3e37bc, + 0x2e7736d5, 0x6e61341f, 0x2ea734c5, 0x6ebd379b, + 0x6ee23420, 0x2e333e51, 0x6e313e0f, 0x2e663ca4, + 0x6e7c3f7a, 0x2eaa3d28, 0x6ebe3fbc, 0x6ef83ef6, + 0x0e3de79b, 0x4e3de79b, 0x4e7be759, 0x2eb9e717, + 0x6ea2e420, 0x6ee6e4a4, 0x2e28e4e6, 0x6e34e672, + 0x6e62e420, 0x659229e2, 0x65903cb3, 0x65d03683, + 0x65913163, 0x65d120df, 0x65d323c6, 0x25dd8ecd, + 0x25d2063e, 0x258b0947, 0x2501358b, 0x25823032, + 0x254181d6, 0x24a646a1, 0x24719e73, 0x24233cd8, + 0x24adf4c2, 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, + 0x0ef9b820, 0x4ef9b820, 0x4e21c862, 0x0e79c862, + 0x4e79c862, 0x4e61b8a4, 0x0e79b8a4, 0x4e79b8a4, + 0x05a08020, 0x05104fe0, 0x05505001, 0x05906fe2, + 0x05d03005, 0x05101fea, 0x05901feb, 0x0590cc0b, + 0x0590de0b, 0x04b0e3e0, 0x0470e7e1, 0x042f9c20, + 0x043f9c35, 0x047f9c20, 0x04ff9c20, 0x04299420, + 0x04319160, 0x0461943e, 0x04a19020, 0x04038100, + 0x040381a0, 0x040387e1, 0x04438be2, 0x04c38fe3, + 0x040181e0, 0x04018100, 0x04018621, 0x04418b22, + 0x04418822, 0x04818c23, 0x040081e0, 0x04008120, + 0x04008761, 0x04008621, 0x04408822, 0x04808c23, + 0x042053ff, 0x047f5401, 0x25208028, 0x2538cfe0, + 0x2578d001, 0x25b8efe2, 0x25f8f007, 0x2538dfea, + 0x25b8dfeb, 0xa400a3e0, 0xa420a7e0, 0xa4484be0, + 0xa467afe0, 0xa4a8a7ea, 0xa547a814, 0xa4084ffe, + 0xa55c53e0, 0xa5e1540b, 0xe400fbf6, 0xe408ffff, + 0xe420e7e0, 0xe4484be0, 0xe460efe0, 0xe547e400, + 0xe4014be0, 0xe4a84fe0, 0xe5f15000, 0x858043e0, + 0x85a043ff, 0xe59f5d08, 0x0420e3e9, 0x0460e3ea, + 0x04a0e3eb, 0x04e0e3ec, 0x25104042, 0x25104871, + 0x25904861, 0x25904c92, 0x05344020, 0x05744041, + 0x05b44062, 0x05f44083, 0x252c8840, 0x253c1420, + 0x25681572, 0x25a21ce3, 0x25ea1e34, 0x253c0421, + 0x25680572, 0x25a20ce3, 0x25ea0e34, 0x0522c020, + 0x05e6c0a4, 0x2401a001, 0x2443a051, 0x24858881, + 0x24c78cd1, 0x24850891, 0x24c70cc1, 0x250f9001, + 0x25508051, 0x25802491, 0x25df28c1, 0x25850c81, + 0x251e10d1, 0x65816001, 0x65c36051, 0x65854891, + 0x65c74cc1, 0x05733820, 0x05b238a4, 0x05f138e6, + 0x0570396a, 0x65d0a001, 0x65d6a443, 0x65d4a826, + 0x6594ac26, 0x6554ac26, 0x6556ac26, 0x6552ac26, + 0x65cbac85, 0x65caac01, 0x6589ac85, 0x6588ac01, + 0x65c9ac85, 0x65c8ac01, 0x65dea833, 0x659ca509, + 0x65d8a801, 0x65dcac01, 0x655cb241, 0x0520a1e0, + 0x0521a601, 0x052281e0, 0x05238601, 0x04a14026, + 0x042244a6, 0x046344a6, 0x04a444a6, 0x04e544a7, + 0x0568aca7, 0x05b23230, 0x05302a30, 0x05702a30, + 0x05b02a30, 0x05f02a30, 0x853040af, 0xc5b040af, + 0xe57080af, 0xe5b080af, 0x25034440, 0x254054c4, + 0x25034640, 0x25415a05, 0x25834440, 0x25c54489, + 0x250b5d3a, 0x2550dc20, 0x2518e3e1, 0x2518e021, + 0x2518e0a1, 0x2518e121, 0x2518e1a1, 0x2558e3e2, + 0x2558e042, 0x2558e0c2, 0x2558e142, 0x2598e3e3, + 0x2598e063, 0x2598e0e3, 0x2598e163, 0x25d8e3e4, + 0x25d8e084, 0x25d8e104, 0x25d8e184, 0x2518e407, + 0x05214800, 0x05614800, 0x05a14800, 0x05e14800, + 0x05214c00, 0x05614c00, 0x05a14c00, 0x05e14c00, + 0x05304001, 0x05314001, 0x05a18610, 0x05e18610, + 0x0420bc31, 0x05271e11, 0x6545e891, 0x6585e891, + 0x65c5e891, 0x6545c891, 0x6585c891, 0x65c5c891, + 0x052c8020, 0x056c8020, 0x05ac8020, 0x05ec8020, + 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, 0xf82c8114, 0xf8390274, + 0xf820130b, 0xf82623f4, 0xf82e30d0, 0xf82051e7, + 0xf833413a, 0xf82a72b7, 0xf836605c, 0xf8a3826f, + 0xf8b40087, 0xf8bd1007, 0xf8a92290, 0xf8b73204, + 0xf8aa5177, 0xf8b943e6, 0xf8b072ed, 0xf8ac61c1, + 0xf8e98215, 0xf8fa008f, 0xf8e41110, 0xf8e6209e, + 0xf8fd33b1, 0xf8fa51e9, 0xf8e243ab, 0xf8e37027, + 0xf8fb61f5, 0xf86e81e8, 0xf87600b9, 0xf87411f5, + 0xf87723d0, 0xf8743014, 0xf8645313, 0xf8644094, + 0xf878727a, 0xf8626108, 0xb82e81f8, 0xb83f0096, + 0xb83f1141, 0xb834200c, 0xb8293307, 0xb8305364, + 0xb826436a, 0xb838720d, 0xb83f62d6, 0xb8b483bf, + 0xb8a9028e, 0xb8a71394, 0xb8a921cb, 0xb8ac3034, + 0xb8b85269, 0xb8ad41f3, 0xb8b07005, 0xb8a3610c, + 0xb8ef820f, 0xb8e403cf, 0xb8e51140, 0xb8f6207b, + 0xb8e03269, 0xb8fd530a, 0xb8e440f4, 0xb8f871dd, + 0xb8f5636b, 0xb86d83f0, 0xb871006e, 0xb87e12d0, + 0xb8742287, 0xb8633341, 0xb8735209, 0xb8714015, + 0xb8647302, 0xb86e6166, 0xce3179d5, 0xce035c6c, + 0xce788c69, 0xce93bc7c, 0xce758347, 0xce6884ae, + 0xcec080ba, 0xce718a56, 0x2520c9e0, 0x2561c834, + 0x05800d2c, 0x0540154b, 0x0500093f, 0x25e0d78f, + 0x25a1c81c, 0x058026a8, 0x05401eca, 0x05008816, + 0x25e0c5d7, 0x25e1d35a, 0x05800e11, 0x0540155e, + 0x05026c22, 0x25e0ccf6, 0x2521c0a8, 0x0580000f, + 0x054287b3, 0x0500b04d, 0x2560d481, 0x25a1d84c, + 0x05800d38, 0x05407854, 0x050015d5, 0x25e0dabf, + 0x25a1cf12, 0x0580158b, 0x05400e05, 0x05003682, + 0x047a0093, 0x043e0462, 0x65d400b4, 0x658d09bd, + 0x658107ce, 0x04e3107c, 0x04291b29, 0x042e155a, + 0x04e71f54, 0x04d6b0d4, 0x044003ad, 0x041a0029, + 0x041099fb, 0x04db1e24, 0x0419a302, 0x041abdba, + 0x04d90e16, 0x04d38571, 0x04118210, 0x04d006fc, + 0x0497b15c, 0x049ebcf1, 0x04580f04, 0x05278969, + 0x05a496c4, 0x044801e4, 0x04ca1f44, 0x04491745, + 0x040b033f, 0x04810468, 0x04dcbb07, 0x65809e38, + 0x658d8fca, 0x65869ba8, 0x65c797ff, 0x65c294e0, + 0x049dbadd, 0x6582ba9d, 0x6580b246, 0x6581b51a, + 0x658dab93, 0x65c187d1, 0x65b19dd8, 0x65eb0b53, + 0x65fc29e0, 0x65f7b797, 0x65bbd81d, 0x65a4ed97, + 0x65b45aff, 0x65e07fa2, 0x04454097, 0x044d6e3c, + 0x04283148, 0x04bd3013, 0x047731b0, 0x04ed33d7, + 0x05606ad9, 0x056b6fd9, 0x658896ce, 0x4540b245, + 0x45c3b449, 0x04243bae, 0x44d8948e, 0x449a8edb, + 0x4499997f, 0x441b938c, 0x04da309c, 0x049821e6, + 0x04993641, 0x04482882, 0x048a2b8b, 0x044937e3, + 0x044b35f8, 0x65872d06, 0x65c63c95, 0x659834d8, + 0x04c12924, 0x0e2c116a, 0x4e2710c5, 0x0e61101f, + 0x4e7812f6, 0x0ebb1359, 0x4eb1120f, 0x2e251083, + 0x6e341272, 0x2e7011ee, 0x6e6c116a, 0x2ea41062, + 0x6eac116a, }; // END Generated code -- do not edit diff --git a/test/hotspot/jtreg/compiler/onSpinWait/TestOnSpinWaitAArch64.java b/test/hotspot/jtreg/compiler/onSpinWait/TestOnSpinWaitAArch64.java index 3bcd60ed50c..e487e921dd2 100644 --- a/test/hotspot/jtreg/compiler/onSpinWait/TestOnSpinWaitAArch64.java +++ b/test/hotspot/jtreg/compiler/onSpinWait/TestOnSpinWaitAArch64.java @@ -22,7 +22,7 @@ */ /** - * @test TestOnSpinWaitAArch64 + * @test id=TestOnSpinWaitAArch64 * @summary Checks that java.lang.Thread.onSpinWait is intrinsified with instructions specified with '-XX:OnSpinWaitInst' and '-XX:OnSpinWaitInstCount' * @bug 8186670 * @library /test/lib @@ -41,6 +41,22 @@ * @run driver compiler.onSpinWait.TestOnSpinWaitAArch64 c1 sb 1 */ +/** + * @test id=TestOnSpinWaitAArch64-wfet + * @summary Checks that java.lang.Thread.onSpinWait is intrinsified when -XX:OnSpinWaitInst=wfet is used + * @bug 8366441 + * @library /test/lib + * + * @requires vm.flagless + * @requires (os.arch=="aarch64" & os.family=="linux") + * @requires vm.debug + * + * @run driver compiler.onSpinWait.TestOnSpinWaitAArch64 c2 wfet 1 1 + * @run driver compiler.onSpinWait.TestOnSpinWaitAArch64 c2 wfet 1 1000 + * @run driver compiler.onSpinWait.TestOnSpinWaitAArch64 c1 wfet 1 1 + * @run driver compiler.onSpinWait.TestOnSpinWaitAArch64 c1 wfet 1 1000 + */ + package compiler.onSpinWait; import java.util.Arrays; @@ -56,6 +72,7 @@ public class TestOnSpinWaitAArch64 { String compiler = args[0]; String spinWaitInst = args[1]; String spinWaitInstCount = args[2]; + String spinWaitDelay = (args.length >= 4 ? args[3] : ""); ArrayList command = new ArrayList(); command.add("-XX:+IgnoreUnrecognizedVMOptions"); command.add("-showversion"); @@ -70,8 +87,14 @@ public class TestOnSpinWaitAArch64 { throw new RuntimeException("Unknown compiler: " + compiler); } command.add("-Xbatch"); + if ("wfet".equals(spinWaitInst)) { + command.add("-XX:+UnlockExperimentalVMOptions"); + } command.add("-XX:OnSpinWaitInst=" + spinWaitInst); command.add("-XX:OnSpinWaitInstCount=" + spinWaitInstCount); + if (!spinWaitDelay.isEmpty()) { + command.add("-XX:OnSpinWaitDelay=" + spinWaitDelay); + } command.add("-XX:CompileCommand=compileonly," + Launcher.class.getName() + "::" + "test"); command.add("-XX:CompileCommand=print," + Launcher.class.getName() + "::" + "test"); command.add(Launcher.class.getName()); @@ -85,6 +108,14 @@ public class TestOnSpinWaitAArch64 { return; } + if ("wfet".equals(spinWaitInst) && + (analyzer.contains("CPU does not support the SB instruction") || + analyzer.contains("CPU does not support the FEAT_ECV") || + analyzer.contains("CPU does not support the WFET instruction"))) { + System.out.println("Skipping the test. The CPU does not support SB or WFET instruction, or FEAT_ECV."); + return; + } + analyzer.shouldHaveExitValue(0); System.out.println(analyzer.getOutput()); @@ -101,6 +132,9 @@ public class TestOnSpinWaitAArch64 { return "3f2003d5"; } else if ("sb".equals(spinWaitInst)) { return "ff3003d5"; + } else if ("wfet".equals(spinWaitInst)) { + // This assumes rscratch1 is r8. + return "081003d5"; } else { throw new RuntimeException("Unknown spin wait instruction: " + spinWaitInst); } @@ -166,7 +200,7 @@ public class TestOnSpinWaitAArch64 { // When code is disassembled, we have one instruction per line. // Otherwise, there can be multiple hex instructions separated by '|'. foundCount += (int)Arrays.stream(line.split("\\|")) - .takeWhile(i -> i.startsWith(expectedInst)) + .filter(i -> i.startsWith(expectedInst)) .count(); } From 78e9df5088a89ca49a43c846dca0f5c47a482f0a Mon Sep 17 00:00:00 2001 From: Leo Korinth Date: Tue, 31 Mar 2026 11:41:57 +0000 Subject: [PATCH 118/359] 8380987: Fix implicit narrowing conversion in klass.hpp Reviewed-by: stefank, ayang --- src/hotspot/share/oops/klass.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/oops/klass.hpp b/src/hotspot/share/oops/klass.hpp index d59db9744cb..1c6b28127b8 100644 --- a/src/hotspot/share/oops/klass.hpp +++ b/src/hotspot/share/oops/klass.hpp @@ -466,9 +466,9 @@ protected: static const int _lh_log2_element_size_shift = BitsPerByte*0; static const int _lh_log2_element_size_mask = BitsPerLong-1; static const int _lh_element_type_shift = BitsPerByte*1; - static const int _lh_element_type_mask = right_n_bits(BitsPerByte); // shifted mask + static const int _lh_element_type_mask = right_n_bits(BitsPerByte); // shifted mask static const int _lh_header_size_shift = BitsPerByte*2; - static const int _lh_header_size_mask = right_n_bits(BitsPerByte); // shifted mask + static const int _lh_header_size_mask = right_n_bits(BitsPerByte); // shifted mask static const int _lh_array_tag_bits = 2; static const int _lh_array_tag_shift = BitsPerInt - _lh_array_tag_bits; static const int _lh_array_tag_obj_value = ~0x01; // 0x80000000 >> 30 From 8c38e725a57e2b20c27da170b99b8768253603b4 Mon Sep 17 00:00:00 2001 From: Ashutosh Mehra Date: Tue, 31 Mar 2026 14:11:06 +0000 Subject: [PATCH 119/359] 8380464: Inconsistency in emitting warning messages in vm_version_x86.cpp Reviewed-by: kvn, dholmes --- src/hotspot/cpu/x86/vm_version_x86.cpp | 111 ++++++++++++++++--------- 1 file changed, 74 insertions(+), 37 deletions(-) diff --git a/src/hotspot/cpu/x86/vm_version_x86.cpp b/src/hotspot/cpu/x86/vm_version_x86.cpp index 4301bd328d6..a77105efbbf 100644 --- a/src/hotspot/cpu/x86/vm_version_x86.cpp +++ b/src/hotspot/cpu/x86/vm_version_x86.cpp @@ -1264,8 +1264,9 @@ void VM_Version::get_processor_features() { UseGHASHIntrinsics = true; } } else if (UseGHASHIntrinsics) { - if (!FLAG_IS_DEFAULT(UseGHASHIntrinsics)) + if (!FLAG_IS_DEFAULT(UseGHASHIntrinsics)) { warning("GHASH intrinsic requires CLMUL and SSE2 instructions on this CPU"); + } FLAG_SET_DEFAULT(UseGHASHIntrinsics, false); } @@ -1275,26 +1276,27 @@ void VM_Version::get_processor_features() { // based on the VM capabilities whether to use an AVX2 or AVX512-enabled // version. if (UseAVX >= 1) { - if (FLAG_IS_DEFAULT(UseChaCha20Intrinsics)) { - UseChaCha20Intrinsics = true; - } + if (FLAG_IS_DEFAULT(UseChaCha20Intrinsics)) { + UseChaCha20Intrinsics = true; + } } else if (UseChaCha20Intrinsics) { - if (!FLAG_IS_DEFAULT(UseChaCha20Intrinsics)) { - warning("ChaCha20 intrinsic requires AVX instructions"); - } - FLAG_SET_DEFAULT(UseChaCha20Intrinsics, false); + if (!FLAG_IS_DEFAULT(UseChaCha20Intrinsics)) { + warning("ChaCha20 intrinsic requires AVX instructions"); + } + FLAG_SET_DEFAULT(UseChaCha20Intrinsics, false); } // Kyber Intrinsics // Currently we only have them for AVX512 if (supports_evex() && supports_avx512bw()) { - if (FLAG_IS_DEFAULT(UseKyberIntrinsics)) { - UseKyberIntrinsics = true; - } - } else - if (UseKyberIntrinsics) { - warning("Intrinsics for ML-KEM are not available on this CPU."); - FLAG_SET_DEFAULT(UseKyberIntrinsics, false); + if (FLAG_IS_DEFAULT(UseKyberIntrinsics)) { + UseKyberIntrinsics = true; + } + } else if (UseKyberIntrinsics) { + if (!FLAG_IS_DEFAULT(UseKyberIntrinsics)) { + warning("Intrinsics for ML-KEM are not available on this CPU."); + } + FLAG_SET_DEFAULT(UseKyberIntrinsics, false); } // Dilithium Intrinsics @@ -1303,8 +1305,10 @@ void VM_Version::get_processor_features() { UseDilithiumIntrinsics = true; } } else if (UseDilithiumIntrinsics) { + if (!FLAG_IS_DEFAULT(UseDilithiumIntrinsics)) { warning("Intrinsics for ML-DSA are not available on this CPU."); - FLAG_SET_DEFAULT(UseDilithiumIntrinsics, false); + } + FLAG_SET_DEFAULT(UseDilithiumIntrinsics, false); } // Base64 Intrinsics (Check the condition for which the intrinsic will be active) @@ -1313,8 +1317,9 @@ void VM_Version::get_processor_features() { UseBASE64Intrinsics = true; } } else if (UseBASE64Intrinsics) { - if (!FLAG_IS_DEFAULT(UseBASE64Intrinsics)) + if (!FLAG_IS_DEFAULT(UseBASE64Intrinsics)) { warning("Base64 intrinsic requires EVEX instructions on this CPU"); + } FLAG_SET_DEFAULT(UseBASE64Intrinsics, false); } @@ -1323,7 +1328,9 @@ void VM_Version::get_processor_features() { UseFMA = true; } } else if (UseFMA) { - warning("FMA instructions are not available on this CPU"); + if (!FLAG_IS_DEFAULT(UseFMA)) { + warning("FMA instructions are not available on this CPU"); + } FLAG_SET_DEFAULT(UseFMA, false); } @@ -1336,7 +1343,9 @@ void VM_Version::get_processor_features() { UseSHA = true; } } else if (UseSHA) { - warning("SHA instructions are not available on this CPU"); + if (!FLAG_IS_DEFAULT(UseSHA)) { + warning("SHA instructions are not available on this CPU"); + } FLAG_SET_DEFAULT(UseSHA, false); } @@ -1345,7 +1354,9 @@ void VM_Version::get_processor_features() { FLAG_SET_DEFAULT(UseSHA1Intrinsics, true); } } else if (UseSHA1Intrinsics) { - warning("Intrinsics for SHA-1 crypto hash functions not available on this CPU."); + if (!FLAG_IS_DEFAULT(UseSHA1Intrinsics)) { + warning("Intrinsics for SHA-1 crypto hash functions not available on this CPU."); + } FLAG_SET_DEFAULT(UseSHA1Intrinsics, false); } @@ -1354,7 +1365,9 @@ void VM_Version::get_processor_features() { FLAG_SET_DEFAULT(UseSHA256Intrinsics, true); } } else if (UseSHA256Intrinsics) { - warning("Intrinsics for SHA-224 and SHA-256 crypto hash functions not available on this CPU."); + if (!FLAG_IS_DEFAULT(UseSHA256Intrinsics)) { + warning("Intrinsics for SHA-224 and SHA-256 crypto hash functions not available on this CPU."); + } FLAG_SET_DEFAULT(UseSHA256Intrinsics, false); } @@ -1363,7 +1376,9 @@ void VM_Version::get_processor_features() { FLAG_SET_DEFAULT(UseSHA512Intrinsics, true); } } else if (UseSHA512Intrinsics) { - warning("Intrinsics for SHA-384 and SHA-512 crypto hash functions not available on this CPU."); + if (!FLAG_IS_DEFAULT(UseSHA512Intrinsics)) { + warning("Intrinsics for SHA-384 and SHA-512 crypto hash functions not available on this CPU."); + } FLAG_SET_DEFAULT(UseSHA512Intrinsics, false); } @@ -1372,7 +1387,9 @@ void VM_Version::get_processor_features() { FLAG_SET_DEFAULT(UseSHA3Intrinsics, true); } } else if (UseSHA3Intrinsics) { - warning("Intrinsics for SHA3-224, SHA3-256, SHA3-384 and SHA3-512 crypto hash functions not available on this CPU."); + if (!FLAG_IS_DEFAULT(UseSHA3Intrinsics)) { + warning("Intrinsics for SHA3-224, SHA3-256, SHA3-384 and SHA3-512 crypto hash functions not available on this CPU."); + } FLAG_SET_DEFAULT(UseSHA3Intrinsics, false); } @@ -1435,7 +1452,9 @@ void VM_Version::get_processor_features() { FLAG_SET_DEFAULT(UsePoly1305Intrinsics, true); } } else if (UsePoly1305Intrinsics) { - warning("Intrinsics for Poly1305 crypto hash functions not available on this CPU."); + if (!FLAG_IS_DEFAULT(UsePoly1305Intrinsics)) { + warning("Intrinsics for Poly1305 crypto hash functions not available on this CPU."); + } FLAG_SET_DEFAULT(UsePoly1305Intrinsics, false); } @@ -1444,7 +1463,9 @@ void VM_Version::get_processor_features() { FLAG_SET_DEFAULT(UseIntPolyIntrinsics, true); } } else if (UseIntPolyIntrinsics) { - warning("Intrinsics for Polynomial crypto functions not available on this CPU."); + if (!FLAG_IS_DEFAULT(UseIntPolyIntrinsics)) { + warning("Intrinsics for Polynomial crypto functions not available on this CPU."); + } FLAG_SET_DEFAULT(UseIntPolyIntrinsics, false); } @@ -1694,8 +1715,8 @@ void VM_Version::get_processor_features() { if (FLAG_IS_DEFAULT(UseSSE42Intrinsics)) { FLAG_SET_DEFAULT(UseSSE42Intrinsics, true); } - } else { - if (UseSSE42Intrinsics && !FLAG_IS_DEFAULT(UseSSE42Intrinsics)) { + } else if (UseSSE42Intrinsics) { + if (!FLAG_IS_DEFAULT(UseSSE42Intrinsics)) { warning("SSE4.2 intrinsics require SSE4.2 instructions or higher. Intrinsics will be disabled."); } FLAG_SET_DEFAULT(UseSSE42Intrinsics, false); @@ -1705,15 +1726,17 @@ void VM_Version::get_processor_features() { UseVectorizedMismatchIntrinsic = true; } } else if (UseVectorizedMismatchIntrinsic) { - if (!FLAG_IS_DEFAULT(UseVectorizedMismatchIntrinsic)) + if (!FLAG_IS_DEFAULT(UseVectorizedMismatchIntrinsic)) { warning("vectorizedMismatch intrinsics are not available on this CPU"); + } FLAG_SET_DEFAULT(UseVectorizedMismatchIntrinsic, false); } if (UseAVX >= 2) { FLAG_SET_DEFAULT(UseVectorizedHashCodeIntrinsic, true); } else if (UseVectorizedHashCodeIntrinsic) { - if (!FLAG_IS_DEFAULT(UseVectorizedHashCodeIntrinsic)) + if (!FLAG_IS_DEFAULT(UseVectorizedHashCodeIntrinsic)) { warning("vectorizedHashCode intrinsics are not available on this CPU"); + } FLAG_SET_DEFAULT(UseVectorizedHashCodeIntrinsic, false); } @@ -1723,7 +1746,9 @@ void VM_Version::get_processor_features() { UseCountLeadingZerosInstruction = true; } } else if (UseCountLeadingZerosInstruction) { - warning("lzcnt instruction is not available on this CPU"); + if (!FLAG_IS_DEFAULT(UseCountLeadingZerosInstruction)) { + warning("lzcnt instruction is not available on this CPU"); + } FLAG_SET_DEFAULT(UseCountLeadingZerosInstruction, false); } @@ -1739,7 +1764,9 @@ void VM_Version::get_processor_features() { } } } else if (UseCountTrailingZerosInstruction) { - warning("tzcnt instruction is not available on this CPU"); + if (!FLAG_IS_DEFAULT(UseCountTrailingZerosInstruction)) { + warning("tzcnt instruction is not available on this CPU"); + } FLAG_SET_DEFAULT(UseCountTrailingZerosInstruction, false); } @@ -1750,7 +1777,9 @@ void VM_Version::get_processor_features() { UseBMI1Instructions = true; } } else if (UseBMI1Instructions) { - warning("BMI1 instructions are not available on this CPU (AVX is also required)"); + if (!FLAG_IS_DEFAULT(UseBMI1Instructions)) { + warning("BMI1 instructions are not available on this CPU (AVX is also required)"); + } FLAG_SET_DEFAULT(UseBMI1Instructions, false); } @@ -1759,7 +1788,9 @@ void VM_Version::get_processor_features() { UseBMI2Instructions = true; } } else if (UseBMI2Instructions) { - warning("BMI2 instructions are not available on this CPU (AVX is also required)"); + if (!FLAG_IS_DEFAULT(UseBMI2Instructions)) { + warning("BMI2 instructions are not available on this CPU (AVX is also required)"); + } FLAG_SET_DEFAULT(UseBMI2Instructions, false); } @@ -1769,7 +1800,9 @@ void VM_Version::get_processor_features() { UsePopCountInstruction = true; } } else if (UsePopCountInstruction) { - warning("POPCNT instruction is not available on this CPU"); + if (!FLAG_IS_DEFAULT(UsePopCountInstruction)) { + warning("POPCNT instruction is not available on this CPU"); + } FLAG_SET_DEFAULT(UsePopCountInstruction, false); } @@ -1779,7 +1812,9 @@ void VM_Version::get_processor_features() { UseFastStosb = true; } } else if (UseFastStosb) { - warning("fast-string operations are not available on this CPU"); + if (!FLAG_IS_DEFAULT(UseFastStosb)) { + warning("fast-string operations are not available on this CPU"); + } FLAG_SET_DEFAULT(UseFastStosb, false); } @@ -1805,7 +1840,9 @@ void VM_Version::get_processor_features() { UseXMMForObjInit = true; } } else if (UseXMMForObjInit) { - warning("UseXMMForObjInit requires SSE2 and unaligned load/stores. Feature is switched off."); + if (!FLAG_IS_DEFAULT(UseXMMForObjInit)) { + warning("UseXMMForObjInit requires SSE2 and unaligned load/stores. Feature is switched off."); + } FLAG_SET_DEFAULT(UseXMMForObjInit, false); } @@ -1885,7 +1922,7 @@ void VM_Version::get_processor_features() { if (FLAG_IS_DEFAULT(ContendedPaddingWidth) && (cache_line_size > ContendedPaddingWidth)) - ContendedPaddingWidth = cache_line_size; + ContendedPaddingWidth = cache_line_size; // This machine allows unaligned memory accesses if (FLAG_IS_DEFAULT(UseUnalignedAccesses)) { From e3a66f0170ed8e6ca4a16d4897d7d3ffceb2553c Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Tue, 31 Mar 2026 15:01:10 +0000 Subject: [PATCH 120/359] 8380649: Parallel: Inline initialize_region_data and create_vspace of ParallelCompactData Reviewed-by: iwalulya, tschatzl --- .../share/gc/parallel/psParallelCompact.cpp | 39 ++++++------------- .../share/gc/parallel/psParallelCompact.hpp | 3 -- 2 files changed, 12 insertions(+), 30 deletions(-) diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.cpp b/src/hotspot/share/gc/parallel/psParallelCompact.cpp index d03bc3cda45..ca1fd2c120b 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.cpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.cpp @@ -232,14 +232,10 @@ bool ParallelCompactData::initialize(MemRegion reserved_heap) assert(region_align_down(_heap_start) == _heap_start, "region start not aligned"); + assert(is_aligned(heap_size, RegionSize), "precondition"); - return initialize_region_data(heap_size); -} - -PSVirtualSpace* -ParallelCompactData::create_vspace(size_t count, size_t element_size) -{ - const size_t raw_bytes = count * element_size; + const size_t count = heap_size >> Log2RegionSize; + const size_t raw_bytes = count * sizeof(RegionData); const size_t page_sz = os::page_size_for_region_aligned(raw_bytes, 10); const size_t granularity = os::vm_allocation_granularity(); const size_t rs_align = MAX2(page_sz, granularity); @@ -253,7 +249,7 @@ ParallelCompactData::create_vspace(size_t count, size_t element_size) if (!rs.is_reserved()) { // Failed to reserve memory. - return nullptr; + return false; } os::trace_page_sizes("Parallel Compact Data", raw_bytes, raw_bytes, rs.base(), @@ -261,34 +257,23 @@ ParallelCompactData::create_vspace(size_t count, size_t element_size) MemTracker::record_virtual_memory_tag(rs, mtGC); - PSVirtualSpace* vspace = new PSVirtualSpace(rs, page_sz); + PSVirtualSpace* region_vspace = new PSVirtualSpace(rs, page_sz); - if (!vspace->expand_by(_reserved_byte_size)) { + if (!region_vspace->expand_by(_reserved_byte_size)) { // Failed to commit memory. - delete vspace; + delete region_vspace; // Release memory reserved in the space. MemoryReserver::release(rs); - return nullptr; + return false; } - return vspace; -} - -bool ParallelCompactData::initialize_region_data(size_t heap_size) -{ - assert(is_aligned(heap_size, RegionSize), "precondition"); - - const size_t count = heap_size >> Log2RegionSize; - _region_vspace = create_vspace(count, sizeof(RegionData)); - if (_region_vspace != nullptr) { - _region_data = (RegionData*)_region_vspace->reserved_low_addr(); - _region_count = count; - return true; - } - return false; + _region_vspace = region_vspace; + _region_data = (RegionData*)_region_vspace->reserved_low_addr(); + _region_count = count; + return true; } void ParallelCompactData::clear_range(size_t beg_region, size_t end_region) { diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.hpp b/src/hotspot/share/gc/parallel/psParallelCompact.hpp index f5ab041fa97..25f4f66de6f 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.hpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.hpp @@ -395,9 +395,6 @@ public: #endif // #ifdef ASSERT private: - bool initialize_region_data(size_t heap_size); - PSVirtualSpace* create_vspace(size_t count, size_t element_size); - HeapWord* _heap_start; #ifdef ASSERT HeapWord* _heap_end; From 819533964cb0fc015f51cd1deb44649f87b06f94 Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Tue, 31 Mar 2026 15:08:02 +0000 Subject: [PATCH 121/359] 8380913: Sealed graph taglet omits public subtypes of invisible subtypes Reviewed-by: hannesw, vromero --- .../build/tools/taglet/SealedGraph.java | 45 +++++--- .../TestSerializedFormWithClassFile.java | 4 +- .../TestVisibleMembers.java | 12 +-- .../jdk/javadoc/taglet/JdkTaglets.java | 53 +++++++++ .../taglet/sealedGraph/TestSealedTaglet.java | 101 ++++++++++++++++++ .../tools/lib/builder/AbstractBuilder.java | 9 +- .../tools/lib/builder/ClassBuilder.java | 48 ++++++--- test/langtools/tools/lib/toolbox/ToolBox.java | 23 +++- 8 files changed, 256 insertions(+), 39 deletions(-) create mode 100644 test/langtools/jdk/javadoc/taglet/JdkTaglets.java create mode 100644 test/langtools/jdk/javadoc/taglet/sealedGraph/TestSealedTaglet.java diff --git a/make/jdk/src/classes/build/tools/taglet/SealedGraph.java b/make/jdk/src/classes/build/tools/taglet/SealedGraph.java index 3e93826c180..2ffd92e3409 100644 --- a/make/jdk/src/classes/build/tools/taglet/SealedGraph.java +++ b/make/jdk/src/classes/build/tools/taglet/SealedGraph.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -138,20 +138,25 @@ public final class SealedGraph implements Taglet { // Generates a graph in DOT format String graph(TypeElement rootClass, Set exports) { + if (!isInPublicApi(rootClass, exports)) { + // Alternatively we can return "" for the graph since there is no single root to render + throw new IllegalArgumentException("Root not in public API: " + rootClass.getQualifiedName()); + } final State state = new State(rootClass); traverse(state, rootClass, exports); return state.render(); } static void traverse(State state, TypeElement node, Set exports) { + if (!isInPublicApi(node, exports)) { + throw new IllegalArgumentException("Bad request, not in public API: " + node.getQualifiedName()); + } state.addNode(node); if (!(node.getModifiers().contains(Modifier.SEALED) || node.getModifiers().contains(Modifier.FINAL))) { state.addNonSealedEdge(node); } else { for (TypeElement subNode : permittedSubclasses(node, exports)) { - if (isInPublicApi(node, exports) && isInPublicApi(subNode, exports)) { - state.addEdge(node, subNode); - } + state.addEdge(node, subNode); traverse(state, subNode, exports); } } @@ -292,14 +297,30 @@ public final class SealedGraph implements Taglet { } private static List permittedSubclasses(TypeElement node, Set exports) { - return node.getPermittedSubclasses().stream() - .filter(DeclaredType.class::isInstance) - .map(DeclaredType.class::cast) - .map(DeclaredType::asElement) - .filter(TypeElement.class::isInstance) - .map(TypeElement.class::cast) - .filter(te -> isInPublicApi(te, exports)) - .toList(); + List dfsStack = new ArrayList().reversed(); // Faster operations to head + SequencedCollection result = new LinkedHashSet<>(); // Deduplicate diamond interface inheritance + // The starting node may be in the public API - still expand it + prependSubclasses(node, dfsStack); + + while (!dfsStack.isEmpty()) { + TypeElement now = dfsStack.removeFirst(); + if (isInPublicApi(now, exports)) { + result.addLast(now); + } else { + // Skip the non-exported classes in the hierarchy + prependSubclasses(now, dfsStack); + } + } + + return List.copyOf(result); + } + + private static void prependSubclasses(TypeElement node, List dfs) { + for (var e : node.getPermittedSubclasses().reversed()) { + if (e instanceof DeclaredType dt && dt.asElement() instanceof TypeElement te) { + dfs.addFirst(te); + } + } } private static boolean isInPublicApi(TypeElement typeElement, Set exports) { diff --git a/test/langtools/jdk/javadoc/doclet/testSerializedFormWithClassFile/TestSerializedFormWithClassFile.java b/test/langtools/jdk/javadoc/doclet/testSerializedFormWithClassFile/TestSerializedFormWithClassFile.java index 25613dffd95..1db0b6af8d4 100644 --- a/test/langtools/jdk/javadoc/doclet/testSerializedFormWithClassFile/TestSerializedFormWithClassFile.java +++ b/test/langtools/jdk/javadoc/doclet/testSerializedFormWithClassFile/TestSerializedFormWithClassFile.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,8 +106,8 @@ public class TestSerializedFormWithClassFile extends JavadocTester { new JavacTask(tb).files(srcDir.resolve("A.java")).outdir(classes).run(); new ClassBuilder(tb, "B") - .setExtends("A") .setModifiers("public", "class") + .setExtends("A") .write(srcDir); } } diff --git a/test/langtools/jdk/javadoc/doclet/testVisibleMembers/TestVisibleMembers.java b/test/langtools/jdk/javadoc/doclet/testVisibleMembers/TestVisibleMembers.java index 09f6f92e2b6..fe5f1212b09 100644 --- a/test/langtools/jdk/javadoc/doclet/testVisibleMembers/TestVisibleMembers.java +++ b/test/langtools/jdk/javadoc/doclet/testVisibleMembers/TestVisibleMembers.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -135,7 +135,7 @@ public class TestVisibleMembers extends JavadocTester { "@param lvalue an lvalue", "@return something"); new ClassBuilder(tb, "p.B") - .setModifiers( "public", "interface") + .setModifiers("public", "interface") .setExtends("A") .addMembers(mbWith1, mbWith2) .write(srcDir); @@ -358,7 +358,7 @@ public class TestVisibleMembers extends JavadocTester { MethodBuilder.parse("public I sub() {return null;}"), MethodBuilder.parse("public I sub1() {return null;}") .setComments(Kind.INHERIT_DOC), - MethodBuilder.parse(" public void method() {}") + MethodBuilder.parse("public void method() {}") .setComments("A method ", "@see #sub", "@see #sub1"), MethodBuilder.parse("public int length(){return 1;}") .setComments(Kind.NO_API_COMMENT) @@ -380,7 +380,7 @@ public class TestVisibleMembers extends JavadocTester { ).write(srcDir); new ClassBuilder(tb, "p.QLong") - .setModifiers("public interface") + .setModifiers("public", "interface") .addMembers( MethodBuilder.parse("default void forEach(Q action) {}") ).write(srcDir); @@ -663,7 +663,7 @@ public class TestVisibleMembers extends JavadocTester { ).write(srcDir); new ClassBuilder(tb, "p.I3") - .setExtends("I1, I2") + .addImplements("I1", "I2") .setModifiers("public", "interface") .addMembers( FieldBuilder.parse("public static int field = 3;"), @@ -677,8 +677,8 @@ public class TestVisibleMembers extends JavadocTester { .write(srcDir); new ClassBuilder(tb, "p.C2") - .setExtends("C1") .setModifiers("public", "abstract", "class") + .setExtends("C1") .addMembers( FieldBuilder.parse("public int field;"), MethodBuilder.parse("public void method(){}"), diff --git a/test/langtools/jdk/javadoc/taglet/JdkTaglets.java b/test/langtools/jdk/javadoc/taglet/JdkTaglets.java new file mode 100644 index 00000000000..537904450aa --- /dev/null +++ b/test/langtools/jdk/javadoc/taglet/JdkTaglets.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 java.nio.file.Path; +import java.util.stream.Stream; + +import toolbox.JavacTask; +import toolbox.ToolBox; + +/// Utilities to build the JDK-specific taglets. +/// This guy uses JavacTask so can't be in javadoc.tester. +public final class JdkTaglets { + + /// Build a taglet and return its path for `-tagletpath`. + public static Path build(ToolBox tb, Path base, String... tagletFiles) throws IOException { + Path tagletOutDir = base.resolve("tagletClasses"); + Files.createDirectories(tagletOutDir); + tb.cleanDirectory(tagletOutDir); + Path tagletRoot = tb.findFromTestRoot("../../make/jdk/src/classes/build/tools/taglet"); + + new JavacTask(tb) + .files(Stream.of(tagletFiles) + .map(tagletFile -> tagletRoot.resolve(tagletFile + ".java")) + .toArray(Path[]::new)) + .outdir(tagletOutDir) + .run(JavacTask.Expect.SUCCESS); + return tagletOutDir; + } + + private JdkTaglets() {} +} diff --git a/test/langtools/jdk/javadoc/taglet/sealedGraph/TestSealedTaglet.java b/test/langtools/jdk/javadoc/taglet/sealedGraph/TestSealedTaglet.java new file mode 100644 index 00000000000..3ac6f0601b2 --- /dev/null +++ b/test/langtools/jdk/javadoc/taglet/sealedGraph/TestSealedTaglet.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 General tests for SealedGraph block tag + * @bug 8380913 + * @library /tools/lib /jdk/javadoc/lib ../ + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * jdk.javadoc/jdk.javadoc.internal.tool + * @build javadoc.tester.* toolbox.ToolBox builder.ClassBuilder JdkTaglets + * @run main ${test.main.class} + */ + +import java.nio.file.Path; + +import builder.ClassBuilder; +import javadoc.tester.JavadocTester; +import toolbox.ToolBox; + +public class TestSealedTaglet extends JavadocTester { + + final ToolBox tb; + final Path tagletPath; + + public static void main(String... args) throws Exception { + var tester = new TestSealedTaglet(); + tester.runTests(); + } + + TestSealedTaglet() throws Exception { + tb = new ToolBox(); + tagletPath = JdkTaglets.build(tb, Path.of(""), "SealedGraph"); + setAutomaticCheckLinks(false); // Don't fail for missing svg + } + + @Test + public void testInvisibleInMiddle(Path base) throws Exception { + Path srcDir = base.resolve("src"); + Path outDir = base.resolve("out"); + + tb.writeFile(srcDir.resolve("module-info.java"), + """ + module test { + exports pkg; + } + """); + new ClassBuilder(tb, "pkg.A") + .setModifiers("public", "abstract", "sealed", "interface") + .setComments("@sealedGraph") + .addPermits("pkg.B") + .write(srcDir); + new ClassBuilder(tb, "pkg.B") + .setModifiers("abstract", "sealed", "interface") + .addImplements("pkg.A") + .addPermits("pkg.C", "pkg.D") + .write(srcDir); + new ClassBuilder(tb, "pkg.C") + .setModifiers("abstract", "sealed", "interface") + .addImplements("pkg.A", "pkg.B") + .addPermits("pkg.D") + .write(srcDir); + new ClassBuilder(tb, "pkg.D") + .setModifiers("public", "final", "class") + .addImplements("pkg.B", "pkg.C") + .write(srcDir); + + System.setProperty("sealedDotOutputDir", outDir.toString()); + + javadoc("-tagletpath", tagletPath.toString(), + "-taglet", "build.tools.taglet.SealedGraph", + "-d", outDir.toString(), + "-sourcepath", srcDir.toString(), + "pkg"); + + checkExit(Exit.OK); + // D is displayed as a direct subtype of A, bypassing B, C, one link only + checkUnique("test_pkg.A.dot", "\"pkg.D\" -> \"pkg.A\";"); + } +} diff --git a/test/langtools/tools/lib/builder/AbstractBuilder.java b/test/langtools/tools/lib/builder/AbstractBuilder.java index e528fe60792..4717f456d08 100644 --- a/test/langtools/tools/lib/builder/AbstractBuilder.java +++ b/test/langtools/tools/lib/builder/AbstractBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -203,6 +203,13 @@ public abstract class AbstractBuilder { this.modifiers = modifiers; } + boolean isInterface() { + if (modifiers.isEmpty()) { + throw new IllegalStateException("modifiers not initialized"); + } + return modifiers.getLast().endsWith("interface"); + } + @Override public String toString() { OutputWriter ow = new OutputWriter(); diff --git a/test/langtools/tools/lib/builder/ClassBuilder.java b/test/langtools/tools/lib/builder/ClassBuilder.java index feafa77db56..2c57f0e0c13 100644 --- a/test/langtools/tools/lib/builder/ClassBuilder.java +++ b/test/langtools/tools/lib/builder/ClassBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.ListIterator; import java.util.regex.Matcher; @@ -54,6 +55,7 @@ public class ClassBuilder extends AbstractBuilder { private String extendsType; private final List implementsTypes; + private final List permitsTypes; private final List members; private final List inners; private final List nested; @@ -86,6 +88,7 @@ public class ClassBuilder extends AbstractBuilder { } imports = new ArrayList<>(); implementsTypes = new ArrayList<>(); + permitsTypes = new ArrayList<>(); members = new ArrayList<>(); nested = new ArrayList<>(); inners = new ArrayList<>(); @@ -153,7 +156,11 @@ public class ClassBuilder extends AbstractBuilder { * @return this builder. */ public ClassBuilder setExtends(String name) { - extendsType = name; + if (modifiers.isInterface()) { + implementsTypes.add(name); + } else { + extendsType = name; + } return this; } @@ -163,7 +170,17 @@ public class ClassBuilder extends AbstractBuilder { * @return this builder. */ public ClassBuilder addImplements(String... names) { - implementsTypes.addAll(List.of(names)); + implementsTypes.addAll(Arrays.asList(names)); + return this; + } + + /** + * Adds a permits declaration(s). + * @param names the subtypes + * @return this builder + */ + public ClassBuilder addPermits(String... names) { + permitsTypes.addAll(Arrays.asList(names)); return this; } @@ -225,28 +242,25 @@ public class ClassBuilder extends AbstractBuilder { ow.println("// NO_API_COMMENT"); break; } + assert !modifiers.modifiers.isEmpty(); ow.print(modifiers.toString()); ow.print(clsname); if (typeParameter != null) { - ow.print(typeParameter + " "); - } else { - ow.print(" "); + ow.print(typeParameter); } if (extendsType != null && !extendsType.isEmpty()) { - ow.print("extends " + extendsType + " "); + assert !modifiers.isInterface(); + ow.print(" extends " + extendsType); } if (!implementsTypes.isEmpty()) { - ow.print("implements "); - - ListIterator iter = implementsTypes.listIterator(); - while (iter.hasNext()) { - String s = iter.next() ; - ow.print(s); - if (iter.hasNext()) - ow.print(", "); - } + ow.print(modifiers.isInterface() ? " extends " : " implements "); + ow.print(String.join(", ", implementsTypes)); } - ow.print("{"); + if (!permitsTypes.isEmpty()) { + ow.print(" permits "); + ow.print(String.join(", ", permitsTypes)); + } + ow.print(" {"); if (!nested.isEmpty()) { ow.println(""); nested.forEach(m -> ow.println(m.toString())); diff --git a/test/langtools/tools/lib/toolbox/ToolBox.java b/test/langtools/tools/lib/toolbox/ToolBox.java index ee217ab2c0c..1cb2fa6d3f9 100644 --- a/test/langtools/tools/lib/toolbox/ToolBox.java +++ b/test/langtools/tools/lib/toolbox/ToolBox.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -666,6 +666,27 @@ public class ToolBox { return Path.of(testJDK, "bin", tool); } + /** + * Finds a file with a path relative to the langtools test root directory. + * + * @param path the desired path from test/langtools + * @return the file, if found + */ + public Path findFromTestRoot(String path) { + Path testSrc = Path.of(System.getProperty("test.src", ".")); + + for (Path d = testSrc; d != null; d = d.getParent()) { + if (Files.exists(d.resolve("TEST.ROOT"))) { + Path file = d.resolve(path); + if (Files.exists(file)) { + return file; + } + } + } + + return null; + } + /** * Returns a string representing the contents of an {@code Iterable} as a list. * From 74eff77554acf6186e7f12546215efb493d0f90d Mon Sep 17 00:00:00 2001 From: Matias Saavedra Silva Date: Tue, 31 Mar 2026 15:51:40 +0000 Subject: [PATCH 122/359] 8347462: Improve TraceClassLoading to add link information Reviewed-by: dholmes, coleenp --- src/hotspot/share/oops/instanceKlass.cpp | 6 ++ .../jtreg/runtime/logging/LogLinkingTest.java | 48 ++++++++++++++ .../logging/classes/test/LinkageErrorApp.java | 64 +++++++++++++++++++ 3 files changed, 118 insertions(+) create mode 100644 test/hotspot/jtreg/runtime/logging/LogLinkingTest.java create mode 100644 test/hotspot/jtreg/runtime/logging/classes/test/LinkageErrorApp.java diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp index d3333e72c2a..cb071f2abf0 100644 --- a/src/hotspot/share/oops/instanceKlass.cpp +++ b/src/hotspot/share/oops/instanceKlass.cpp @@ -1121,6 +1121,12 @@ bool InstanceKlass::link_class_impl(TRAPS) { } } } + + if (log_is_enabled(Info, class, link)) { + ResourceMark rm(THREAD); + log_info(class, link)("Linked class %s", external_name()); + } + return true; } diff --git a/test/hotspot/jtreg/runtime/logging/LogLinkingTest.java b/test/hotspot/jtreg/runtime/logging/LogLinkingTest.java new file mode 100644 index 00000000000..86958a60ca0 --- /dev/null +++ b/test/hotspot/jtreg/runtime/logging/LogLinkingTest.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 LogLinkingTest + * @bug 8347462 + * @library /test/lib + * @library classes + * @requires vm.flagless + * @build test.LinkageErrorApp + * @run driver LogLinkingTest + */ + +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.process.OutputAnalyzer; + +public class LogLinkingTest { + public static void main(String[] args) throws Exception { + ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-Xlog:class+load,class+link", "LinkageErrorApp"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldHaveExitValue(1); + output.shouldMatch("class,load.*SingleDefinition source"); + output.shouldMatch("class,load.*DuplicateDefinition source"); + output.shouldMatch("class,link.*Linked class.*SingleDefinition"); + output.shouldNotMatch("class,link.*Linked class.*DuplicateDefinition"); + } +} diff --git a/test/hotspot/jtreg/runtime/logging/classes/test/LinkageErrorApp.java b/test/hotspot/jtreg/runtime/logging/classes/test/LinkageErrorApp.java new file mode 100644 index 00000000000..79b8781a468 --- /dev/null +++ b/test/hotspot/jtreg/runtime/logging/classes/test/LinkageErrorApp.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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.io.InputStream; + +public class LinkageErrorApp { + + static class SingleDefinition { } + static class DuplicateDefinition { } + + static class DuplicateLoader extends ClassLoader { + DuplicateLoader() { + super(null); + } + + Class define(byte[] bytes, String classname) { + return defineClass(classname, bytes, 0, bytes.length); + } + } + + private static byte[] readClassBytes(Class clazz) throws IOException { + String resource = clazz.getName().replace('.', '/') + ".class"; + ClassLoader loader = clazz.getClassLoader(); + if (loader != null) { + InputStream in = loader.getResourceAsStream(resource); + if (in == null) { + throw new RuntimeException("Could not find " + clazz.getName()); + } + return in.readAllBytes(); + } + return null; + } + + public static void main(String[] args) throws Exception { + byte[] duplicateDefBytes = readClassBytes(DuplicateDefinition.class); + DuplicateLoader loader = new DuplicateLoader(); + + SingleDefinition s = new SingleDefinition(); + loader.define(duplicateDefBytes, "LinkageErrorApp$DuplicateDefinition"); + // This will throw a LinkageError + loader.define(duplicateDefBytes, "LinkageErrorApp$DuplicateDefinition"); + } +} From ba34f300db6388d343dd9c496de4830dc62d31a7 Mon Sep 17 00:00:00 2001 From: Dingli Zhang Date: Tue, 31 Mar 2026 15:56:48 +0000 Subject: [PATCH 123/359] 8381250: Enable VectorLogicalOpIdentityTest.java IR tests for RISC-V Reviewed-by: fyang --- .../vectorapi/VectorLogicalOpIdentityTest.java | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/test/hotspot/jtreg/compiler/vectorapi/VectorLogicalOpIdentityTest.java b/test/hotspot/jtreg/compiler/vectorapi/VectorLogicalOpIdentityTest.java index 1a2402222ed..df178f5363e 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/VectorLogicalOpIdentityTest.java +++ b/test/hotspot/jtreg/compiler/vectorapi/VectorLogicalOpIdentityTest.java @@ -1,6 +1,6 @@ /* * Copyright (c) 2022, 2023, Arm Limited. All rights reserved. - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,7 +45,8 @@ import jdk.test.lib.Utils; * @key randomness * @library /test/lib / * @summary Add identity transformations for vector logic operations - * @requires (os.simpleArch == "x64" & vm.cpu.features ~= ".*avx.*") | os.arch=="aarch64" + * @requires (os.simpleArch == "x64" & vm.cpu.features ~= ".*avx.*") | os.arch=="aarch64" | + (os.arch == "riscv64" & vm.cpu.features ~= ".*rvv.*") * @modules jdk.incubator.vector * * @run driver compiler.vectorapi.VectorLogicalOpIdentityTest @@ -302,7 +303,7 @@ public class VectorLogicalOpIdentityTest { // Transform AndV(AndV(a, b, m), b, m) ==> AndV(a, b, m) @Test @Warmup(10000) - @IR(counts = {IRNode.AND_VI, "1"}, applyIfCPUFeatureOr = {"sve", "true", "avx512", "true"}) + @IR(counts = {IRNode.AND_VI, "1"}, applyIfCPUFeatureOr = {"sve", "true", "avx512", "true", "rvv", "true"}) public static void testAndMaskSameValue1() { VectorMask mask = VectorMask.fromArray(I_SPECIES, m, 0); IntVector av = IntVector.fromArray(I_SPECIES, ia, 0); @@ -323,7 +324,7 @@ public class VectorLogicalOpIdentityTest { // Transform AndV(AndV(a, b, m), a, m) ==> AndV(a, b, m) @Test @Warmup(10000) - @IR(counts = {IRNode.AND_VL, "1"}, applyIfCPUFeatureOr = {"sve", "true", "avx512", "true"}) + @IR(counts = {IRNode.AND_VL, "1"}, applyIfCPUFeatureOr = {"sve", "true", "avx512", "true", "rvv", "true"}) public static void testAndMaskSameValue2() { VectorMask mask = VectorMask.fromArray(L_SPECIES, m, 0); LongVector av = LongVector.fromArray(L_SPECIES, la, 0); @@ -344,7 +345,7 @@ public class VectorLogicalOpIdentityTest { // Transform AndV(a, AndV(a, b, m), m) ==> AndV(a, b, m) @Test @Warmup(10000) - @IR(counts = {IRNode.AND_VI, "1"}, applyIfCPUFeatureOr = {"sve", "true", "avx512", "true"}) + @IR(counts = {IRNode.AND_VI, "1"}, applyIfCPUFeatureOr = {"sve", "true", "avx512", "true", "rvv", "true"}) public static void testAndMaskSameValue3() { VectorMask mask = VectorMask.fromArray(I_SPECIES, m, 0); IntVector av = IntVector.fromArray(I_SPECIES, ia, 0); @@ -566,7 +567,7 @@ public class VectorLogicalOpIdentityTest { // Transform OrV(OrV(a, b, m), b, m) ==> OrV(a, b, m) @Test @Warmup(10000) - @IR(counts = {IRNode.OR_VI, "1"}, applyIfCPUFeatureOr = {"sve", "true", "avx512", "true"}) + @IR(counts = {IRNode.OR_VI, "1"}, applyIfCPUFeatureOr = {"sve", "true", "avx512", "true", "rvv", "true"}) public static void testOrMaskSameValue1() { VectorMask mask = VectorMask.fromArray(I_SPECIES, m, 0); IntVector av = IntVector.fromArray(I_SPECIES, ia, 0); @@ -587,7 +588,7 @@ public class VectorLogicalOpIdentityTest { // Transform OrV(OrV(a, b, m), a, m) ==> OrV(a, b, m) @Test @Warmup(10000) - @IR(counts = {IRNode.OR_VL, "1"}, applyIfCPUFeatureOr = {"sve", "true", "avx512", "true"}) + @IR(counts = {IRNode.OR_VL, "1"}, applyIfCPUFeatureOr = {"sve", "true", "avx512", "true", "rvv", "true"}) public static void testOrMaskSameValue2() { VectorMask mask = VectorMask.fromArray(L_SPECIES, m, 0); LongVector av = LongVector.fromArray(L_SPECIES, la, 0); @@ -608,7 +609,7 @@ public class VectorLogicalOpIdentityTest { // Transform OrV(a, OrV(a, b, m), m) ==> OrV(a, b, m) @Test @Warmup(10000) - @IR(counts = {IRNode.OR_VI, "1"}, applyIfCPUFeatureOr = {"sve", "true", "avx512", "true"}) + @IR(counts = {IRNode.OR_VI, "1"}, applyIfCPUFeatureOr = {"sve", "true", "avx512", "true", "rvv", "true"}) public static void testOrMaskSameValue3() { VectorMask mask = VectorMask.fromArray(I_SPECIES, m, 0); IntVector av = IntVector.fromArray(I_SPECIES, ia, 0); From 207bb159b2bc53348599b256c3b3b16137c6b4b0 Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Tue, 31 Mar 2026 16:52:34 +0000 Subject: [PATCH 124/359] 8381409: Fix whitespace and variable name in classfile code Reviewed-by: liach, lfoltan --- .../share/classfile/classFileParser.cpp | 18 +++++----- .../share/classfile/fieldLayoutBuilder.cpp | 26 +++++++------- .../share/classfile/fieldLayoutBuilder.hpp | 6 ++-- .../share/classfile/stackMapTableFormat.hpp | 35 ++++++++++++------- .../share/classfile/systemDictionary.cpp | 4 +-- 5 files changed, 50 insertions(+), 39 deletions(-) diff --git a/src/hotspot/share/classfile/classFileParser.cpp b/src/hotspot/share/classfile/classFileParser.cpp index c1f00cbe536..404693f5cee 100644 --- a/src/hotspot/share/classfile/classFileParser.cpp +++ b/src/hotspot/share/classfile/classFileParser.cpp @@ -194,7 +194,7 @@ void ClassFileParser::parse_constant_pool_entries(const ClassFileStream* const s // so we don't need bounds-check for reading tag. const u1 tag = cfs->get_u1_fast(); switch (tag) { - case JVM_CONSTANT_Class : { + case JVM_CONSTANT_Class: { cfs->guarantee_more(3, CHECK); // name_index, tag/access_flags const u2 name_index = cfs->get_u2_fast(); cp->klass_index_at_put(index, name_index); @@ -4403,14 +4403,14 @@ void ClassFileParser::verify_legal_field_modifiers(jint flags, TRAPS) const { if (!_need_verify) { return; } - const bool is_public = (flags & JVM_ACC_PUBLIC) != 0; - const bool is_protected = (flags & JVM_ACC_PROTECTED) != 0; - const bool is_private = (flags & JVM_ACC_PRIVATE) != 0; - const bool is_static = (flags & JVM_ACC_STATIC) != 0; - const bool is_final = (flags & JVM_ACC_FINAL) != 0; - const bool is_volatile = (flags & JVM_ACC_VOLATILE) != 0; - const bool is_transient = (flags & JVM_ACC_TRANSIENT) != 0; - const bool is_enum = (flags & JVM_ACC_ENUM) != 0; + const bool is_public = (flags & JVM_ACC_PUBLIC) != 0; + const bool is_protected = (flags & JVM_ACC_PROTECTED) != 0; + const bool is_private = (flags & JVM_ACC_PRIVATE) != 0; + const bool is_static = (flags & JVM_ACC_STATIC) != 0; + const bool is_final = (flags & JVM_ACC_FINAL) != 0; + const bool is_volatile = (flags & JVM_ACC_VOLATILE) != 0; + const bool is_transient = (flags & JVM_ACC_TRANSIENT) != 0; + const bool is_enum = (flags & JVM_ACC_ENUM) != 0; const bool major_gte_1_5 = _major_version >= JAVA_1_5_VERSION; bool is_illegal = false; diff --git a/src/hotspot/share/classfile/fieldLayoutBuilder.cpp b/src/hotspot/share/classfile/fieldLayoutBuilder.cpp index 8a9f5946091..adf4e1e63fa 100644 --- a/src/hotspot/share/classfile/fieldLayoutBuilder.cpp +++ b/src/hotspot/share/classfile/fieldLayoutBuilder.cpp @@ -37,7 +37,7 @@ LayoutRawBlock::LayoutRawBlock(Kind kind, int size) : _next_block(nullptr), _prev_block(nullptr), - _kind(kind), + _block_kind(kind), _offset(-1), _alignment(1), _size(size), @@ -52,7 +52,7 @@ LayoutRawBlock::LayoutRawBlock(Kind kind, int size) : LayoutRawBlock::LayoutRawBlock(int index, Kind kind, int size, int alignment, bool is_reference) : _next_block(nullptr), _prev_block(nullptr), - _kind(kind), + _block_kind(kind), _offset(-1), _alignment(alignment), _size(size), @@ -148,8 +148,8 @@ void FieldLayout::initialize_instance_layout(const InstanceKlass* super_klass, b LayoutRawBlock* FieldLayout::first_field_block() { LayoutRawBlock* block = _start; - while (block->kind() != LayoutRawBlock::INHERITED && block->kind() != LayoutRawBlock::REGULAR - && block->kind() != LayoutRawBlock::FLATTENED && block->kind() != LayoutRawBlock::PADDING) { + while (block->block_kind() != LayoutRawBlock::INHERITED && block->block_kind() != LayoutRawBlock::REGULAR + && block->block_kind() != LayoutRawBlock::FLATTENED && block->block_kind() != LayoutRawBlock::PADDING) { block = block->next_block(); } return block; @@ -190,7 +190,7 @@ void FieldLayout::add(GrowableArray* list, LayoutRawBlock* star assert(cursor != nullptr, "Sanity check"); last_search_success = true; while (cursor != start) { - if (cursor->kind() == LayoutRawBlock::EMPTY && cursor->fit(b->size(), b->alignment())) { + if (cursor->block_kind() == LayoutRawBlock::EMPTY && cursor->fit(b->size(), b->alignment())) { if (candidate == nullptr || cursor->size() < candidate->size()) { candidate = cursor; } @@ -202,7 +202,7 @@ void FieldLayout::add(GrowableArray* list, LayoutRawBlock* star last_search_success = false; } assert(candidate != nullptr, "Candidate must not be null"); - assert(candidate->kind() == LayoutRawBlock::EMPTY, "Candidate must be an empty block"); + assert(candidate->block_kind() == LayoutRawBlock::EMPTY, "Candidate must be an empty block"); assert(candidate->fit(b->size(), b->alignment()), "Candidate must be able to store the block"); } @@ -221,7 +221,7 @@ void FieldLayout::add_field_at_offset(LayoutRawBlock* block, int offset, LayoutR while (slot != nullptr) { if ((slot->offset() <= block->offset() && (slot->offset() + slot->size()) > block->offset()) || slot == _last){ - assert(slot->kind() == LayoutRawBlock::EMPTY, "Matching slot must be an empty slot"); + assert(slot->block_kind() == LayoutRawBlock::EMPTY, "Matching slot must be an empty slot"); assert(slot->size() >= block->offset() + block->size() ,"Matching slot must be big enough"); if (slot->offset() < block->offset()) { int adjustment = block->offset() - slot->offset(); @@ -261,7 +261,7 @@ void FieldLayout::add_contiguously(GrowableArray* list, LayoutR } else { LayoutRawBlock* first = list->at(0); candidate = last_block()->prev_block(); - while (candidate->kind() != LayoutRawBlock::EMPTY || !candidate->fit(size, first->alignment())) { + while (candidate->block_kind() != LayoutRawBlock::EMPTY || !candidate->fit(size, first->alignment())) { if (candidate == start) { candidate = last_block(); break; @@ -269,7 +269,7 @@ void FieldLayout::add_contiguously(GrowableArray* list, LayoutR candidate = candidate->prev_block(); } assert(candidate != nullptr, "Candidate must not be null"); - assert(candidate->kind() == LayoutRawBlock::EMPTY, "Candidate must be an empty block"); + assert(candidate->block_kind() == LayoutRawBlock::EMPTY, "Candidate must be an empty block"); assert(candidate->fit(size, first->alignment()), "Candidate must be able to store the whole contiguous block"); } @@ -281,7 +281,7 @@ void FieldLayout::add_contiguously(GrowableArray* list, LayoutR } LayoutRawBlock* FieldLayout::insert_field_block(LayoutRawBlock* slot, LayoutRawBlock* block) { - assert(slot->kind() == LayoutRawBlock::EMPTY, "Blocks can only be inserted in empty blocks"); + assert(slot->block_kind() == LayoutRawBlock::EMPTY, "Blocks can only be inserted in empty blocks"); if (slot->offset() % block->alignment() != 0) { int adjustment = block->alignment() - (slot->offset() % block->alignment()); LayoutRawBlock* adj = new LayoutRawBlock(LayoutRawBlock::EMPTY, adjustment); @@ -362,7 +362,7 @@ void FieldLayout::fill_holes(const InstanceKlass* super_klass) { b = b->next_block(); } assert(b->next_block() == nullptr, "Invariant at this point"); - assert(b->kind() != LayoutRawBlock::EMPTY, "Sanity check"); + assert(b->block_kind() != LayoutRawBlock::EMPTY, "Sanity check"); // If the super class has @Contended annotation, a padding block is // inserted at the end to ensure that fields from the subclasses won't share @@ -384,7 +384,7 @@ void FieldLayout::fill_holes(const InstanceKlass* super_klass) { } LayoutRawBlock* FieldLayout::insert(LayoutRawBlock* slot, LayoutRawBlock* block) { - assert(slot->kind() == LayoutRawBlock::EMPTY, "Blocks can only be inserted in empty blocks"); + assert(slot->block_kind() == LayoutRawBlock::EMPTY, "Blocks can only be inserted in empty blocks"); assert(slot->offset() % block->alignment() == 0, "Incompatible alignment"); block->set_offset(slot->offset()); slot->set_offset(slot->offset() + block->size()); @@ -425,7 +425,7 @@ void FieldLayout::print(outputStream* output, bool is_static, const InstanceKlas ResourceMark rm; LayoutRawBlock* b = _blocks; while(b != _last) { - switch(b->kind()) { + switch(b->block_kind()) { case LayoutRawBlock::REGULAR: { FieldInfo* fi = _field_info->adr_at(b->field_index()); output->print_cr(" @%d \"%s\" %s %d/%d %s", diff --git a/src/hotspot/share/classfile/fieldLayoutBuilder.hpp b/src/hotspot/share/classfile/fieldLayoutBuilder.hpp index eab0b7d08a9..a45131ec9a3 100644 --- a/src/hotspot/share/classfile/fieldLayoutBuilder.hpp +++ b/src/hotspot/share/classfile/fieldLayoutBuilder.hpp @@ -65,7 +65,7 @@ class LayoutRawBlock : public ResourceObj { private: LayoutRawBlock* _next_block; LayoutRawBlock* _prev_block; - Kind _kind; + Kind _block_kind; int _offset; int _alignment; int _size; @@ -79,7 +79,7 @@ class LayoutRawBlock : public ResourceObj { void set_next_block(LayoutRawBlock* next) { _next_block = next; } LayoutRawBlock* prev_block() const { return _prev_block; } void set_prev_block(LayoutRawBlock* prev) { _prev_block = prev; } - Kind kind() const { return _kind; } + Kind block_kind() const { return _block_kind; } int offset() const { assert(_offset >= 0, "Must be initialized"); return _offset; @@ -173,7 +173,7 @@ class FieldLayout : public ResourceObj { LayoutRawBlock* first_empty_block() { LayoutRawBlock* block = _start; - while (block->kind() != LayoutRawBlock::EMPTY) { + while (block->block_kind() != LayoutRawBlock::EMPTY) { block = block->next_block(); } return block; diff --git a/src/hotspot/share/classfile/stackMapTableFormat.hpp b/src/hotspot/share/classfile/stackMapTableFormat.hpp index 2b89c53278a..4906f4b9d80 100644 --- a/src/hotspot/share/classfile/stackMapTableFormat.hpp +++ b/src/hotspot/share/classfile/stackMapTableFormat.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -221,9 +221,11 @@ class stack_map_frame { class same_frame : public stack_map_frame { private: static int frame_type_to_offset_delta(u1 frame_type) { - return frame_type + 1; } + return frame_type + 1; + } static u1 offset_delta_to_frame_type(int offset_delta) { - return checked_cast(offset_delta - 1); } + return checked_cast(offset_delta - 1); + } public: @@ -327,9 +329,11 @@ class same_locals_1_stack_item_frame : public stack_map_frame { address type_addr() const { return frame_type_addr() + sizeof(u1); } static int frame_type_to_offset_delta(u1 frame_type) { - return frame_type - 63; } + return frame_type - 63; + } static u1 offset_delta_to_frame_type(int offset_delta) { - return (u1)(offset_delta + 63); } + return (u1)(offset_delta + 63); + } public: static bool is_frame_type(u1 tag) { @@ -657,9 +661,11 @@ class full_frame : public stack_map_frame { address num_locals_addr() const { return offset_delta_addr() + sizeof(u2); } address locals_addr() const { return num_locals_addr() + sizeof(u2); } address stack_slots_addr(address end_of_locals) const { - return end_of_locals; } + return end_of_locals; + } address stack_addr(address end_of_locals) const { - return stack_slots_addr(end_of_locals) + sizeof(u2); } + return stack_slots_addr(end_of_locals) + sizeof(u2); + } enum { _frame_id = 255 }; @@ -930,11 +936,14 @@ class stack_map_table { class stack_map_table_attribute { private: address name_index_addr() const { - return (address)this; } + return (address)this; + } address attribute_length_addr() const { - return name_index_addr() + sizeof(u2); } + return name_index_addr() + sizeof(u2); + } address stack_map_table_addr() const { - return attribute_length_addr() + sizeof(u4); } + return attribute_length_addr() + sizeof(u4); + } NONCOPYABLE(stack_map_table_attribute); protected: @@ -948,9 +957,11 @@ class stack_map_table_attribute { } u2 name_index() const { - return Bytes::get_Java_u2(name_index_addr()); } + return Bytes::get_Java_u2(name_index_addr()); + } u4 attribute_length() const { - return Bytes::get_Java_u4(attribute_length_addr()); } + return Bytes::get_Java_u4(attribute_length_addr()); + } stack_map_table* table() const { return stack_map_table::at(stack_map_table_addr()); } diff --git a/src/hotspot/share/classfile/systemDictionary.cpp b/src/hotspot/share/classfile/systemDictionary.cpp index 0b47c749df8..8483551fd4f 100644 --- a/src/hotspot/share/classfile/systemDictionary.cpp +++ b/src/hotspot/share/classfile/systemDictionary.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -416,7 +416,7 @@ static inline void log_circularity_error(Symbol* name, PlaceholderEntry* probe) // // resolve_with_circularity_detection adds a DETECT_CIRCULARITY placeholder to the placeholder table before calling // resolve_instance_class_or_null. ClassCircularityError is detected when a DETECT_CIRCULARITY or LOAD_INSTANCE -// placeholder for the same thread, class, classloader is found. +// placeholder for the same thread, class, and classloader is found. // This can be seen with logging option: -Xlog:class+load+placeholders=debug. // InstanceKlass* SystemDictionary::resolve_with_circularity_detection(Symbol* class_name, From abeceb1f8c7b09a396c5152f499c84d3c72a920b Mon Sep 17 00:00:00 2001 From: Vladimir Kozlov Date: Tue, 31 Mar 2026 17:07:33 +0000 Subject: [PATCH 125/359] 8379687: Reduce C heap usage when VerifyMethodHandles flags is on Reviewed-by: mhaessig, chagedorn --- src/hotspot/cpu/arm/methodHandles_arm.cpp | 9 ++++----- src/hotspot/cpu/ppc/methodHandles_ppc.cpp | 13 ++++++------- src/hotspot/cpu/s390/methodHandles_s390.cpp | 14 +++++--------- src/hotspot/cpu/x86/methodHandles_x86.cpp | 13 ++++++------- src/hotspot/share/prims/methodHandles.cpp | 13 +++++++++++++ src/hotspot/share/prims/methodHandles.hpp | 2 ++ 6 files changed, 36 insertions(+), 28 deletions(-) diff --git a/src/hotspot/cpu/arm/methodHandles_arm.cpp b/src/hotspot/cpu/arm/methodHandles_arm.cpp index 3710fa33f36..2da14d8ffed 100644 --- a/src/hotspot/cpu/arm/methodHandles_arm.cpp +++ b/src/hotspot/cpu/arm/methodHandles_arm.cpp @@ -104,14 +104,13 @@ void MethodHandles::verify_ref_kind(MacroAssembler* _masm, int ref_kind, Registe __ andr(temp, temp, (unsigned)java_lang_invoke_MemberName::MN_REFERENCE_KIND_MASK); __ cmp(temp, ref_kind); __ b(L, eq); - { char* buf = NEW_C_HEAP_ARRAY(char, 100, mtInternal); - jio_snprintf(buf, 100, "verify_ref_kind expected %x", ref_kind); + const char* msg = ref_kind_to_verify_msg(ref_kind); if (ref_kind == JVM_REF_invokeVirtual || - ref_kind == JVM_REF_invokeSpecial) + ref_kind == JVM_REF_invokeSpecial) { // could do this for all ref_kinds, but would explode assembly code size - trace_method_handle(_masm, buf); - __ stop(buf); + trace_method_handle(_masm, msg); } + __ stop(msg); BLOCK_COMMENT("} verify_ref_kind"); __ bind(L); } diff --git a/src/hotspot/cpu/ppc/methodHandles_ppc.cpp b/src/hotspot/cpu/ppc/methodHandles_ppc.cpp index 45537e0ea96..ae94a9618b5 100644 --- a/src/hotspot/cpu/ppc/methodHandles_ppc.cpp +++ b/src/hotspot/cpu/ppc/methodHandles_ppc.cpp @@ -104,14 +104,13 @@ void MethodHandles::verify_ref_kind(MacroAssembler* _masm, int ref_kind, Registe __ andi(temp, temp, java_lang_invoke_MemberName::MN_REFERENCE_KIND_MASK); __ cmpwi(CR1, temp, ref_kind); __ beq(CR1, L); - { char* buf = NEW_C_HEAP_ARRAY(char, 100, mtInternal); - jio_snprintf(buf, 100, "verify_ref_kind expected %x", ref_kind); - if (ref_kind == JVM_REF_invokeVirtual || - ref_kind == JVM_REF_invokeSpecial) - // could do this for all ref_kinds, but would explode assembly code size - trace_method_handle(_masm, buf); - __ stop(buf); + const char* msg = ref_kind_to_verify_msg(ref_kind); + if (ref_kind == JVM_REF_invokeVirtual || + ref_kind == JVM_REF_invokeSpecial) { + // could do this for all ref_kinds, but would explode assembly code size + trace_method_handle(_masm, msg); } + __ stop(msg); BLOCK_COMMENT("} verify_ref_kind"); __ BIND(L); } diff --git a/src/hotspot/cpu/s390/methodHandles_s390.cpp b/src/hotspot/cpu/s390/methodHandles_s390.cpp index e3de6d911be..dfb8ce09b27 100644 --- a/src/hotspot/cpu/s390/methodHandles_s390.cpp +++ b/src/hotspot/cpu/s390/methodHandles_s390.cpp @@ -120,16 +120,12 @@ void MethodHandles::verify_ref_kind(MacroAssembler* _masm, int ref_kind, __ z_nilf(temp, java_lang_invoke_MemberName::MN_REFERENCE_KIND_MASK); __ compare32_and_branch(temp, constant(ref_kind), Assembler::bcondEqual, L); - { - char *buf = NEW_C_HEAP_ARRAY(char, 100, mtInternal); - - jio_snprintf(buf, 100, "verify_ref_kind expected %x", ref_kind); - if (ref_kind == JVM_REF_invokeVirtual || ref_kind == JVM_REF_invokeSpecial) { - // Could do this for all ref_kinds, but would explode assembly code size. - trace_method_handle(_masm, buf); - } - __ stop(buf); + const char* msg = ref_kind_to_verify_msg(ref_kind); + if (ref_kind == JVM_REF_invokeVirtual || ref_kind == JVM_REF_invokeSpecial) { + // Could do this for all ref_kinds, but would explode assembly code size. + trace_method_handle(_masm, msg); } + __ stop(msg); BLOCK_COMMENT("} verify_ref_kind"); diff --git a/src/hotspot/cpu/x86/methodHandles_x86.cpp b/src/hotspot/cpu/x86/methodHandles_x86.cpp index 54376c6ad9a..5b15444bc32 100644 --- a/src/hotspot/cpu/x86/methodHandles_x86.cpp +++ b/src/hotspot/cpu/x86/methodHandles_x86.cpp @@ -110,14 +110,13 @@ void MethodHandles::verify_ref_kind(MacroAssembler* _masm, int ref_kind, Registe __ andl(temp, java_lang_invoke_MemberName::MN_REFERENCE_KIND_MASK); __ cmpl(temp, ref_kind); __ jcc(Assembler::equal, L); - { char* buf = NEW_C_HEAP_ARRAY(char, 100, mtInternal); - jio_snprintf(buf, 100, "verify_ref_kind expected %x", ref_kind); - if (ref_kind == JVM_REF_invokeVirtual || - ref_kind == JVM_REF_invokeSpecial) - // could do this for all ref_kinds, but would explode assembly code size - trace_method_handle(_masm, buf); - __ STOP(buf); + const char* msg = ref_kind_to_verify_msg(ref_kind); + if (ref_kind == JVM_REF_invokeVirtual || + ref_kind == JVM_REF_invokeSpecial) { + // could do this for all ref_kinds, but would explode assembly code size + trace_method_handle(_masm, msg); } + __ STOP(msg); BLOCK_COMMENT("} verify_ref_kind"); __ bind(L); } diff --git a/src/hotspot/share/prims/methodHandles.cpp b/src/hotspot/share/prims/methodHandles.cpp index 584f077eddc..03cb98d8e75 100644 --- a/src/hotspot/share/prims/methodHandles.cpp +++ b/src/hotspot/share/prims/methodHandles.cpp @@ -157,6 +157,19 @@ int MethodHandles::ref_kind_to_flags(int ref_kind) { return flags; } +#ifdef ASSERT +const char* MethodHandles::ref_kind_to_verify_msg(int ref_kind) { + switch (ref_kind) { + case JVM_REF_invokeSpecial: return "verify_ref_kind expected invokeSpecial"; + case JVM_REF_invokeStatic: return "verify_ref_kind expected invokeStatic"; + case JVM_REF_invokeVirtual: return "verify_ref_kind expected invokeVirtual"; + case JVM_REF_invokeInterface: return "verify_ref_kind expected invokeInterface"; + default: assert(false, "unexpected ref_kind: %d", ref_kind); + } + return ""; +} +#endif + Handle MethodHandles::resolve_MemberName_type(Handle mname, Klass* caller, TRAPS) { Handle empty; Handle type(THREAD, java_lang_invoke_MemberName::type(mname())); diff --git a/src/hotspot/share/prims/methodHandles.hpp b/src/hotspot/share/prims/methodHandles.hpp index 73da28a6cf5..a2a549fe051 100644 --- a/src/hotspot/share/prims/methodHandles.hpp +++ b/src/hotspot/share/prims/methodHandles.hpp @@ -182,6 +182,8 @@ public: static int ref_kind_to_flags(int ref_kind); + DEBUG_ONLY( static const char* ref_kind_to_verify_msg(int ref_kind); ) + #include CPU_HEADER(methodHandles) // Tracing From 48132fbb65bd4938debf360f806d5fd7dd39856c Mon Sep 17 00:00:00 2001 From: Erik Gahlin Date: Tue, 31 Mar 2026 17:13:58 +0000 Subject: [PATCH 126/359] 8381170: JFR: Recursion in jdk.MethodTrace caused by Integer::reverseBytes Reviewed-by: shade --- .../classes/jdk/jfr/internal/tracing/ExcludeList.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/tracing/ExcludeList.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/tracing/ExcludeList.java index 58408da811e..4ba6887e6a5 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/tracing/ExcludeList.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/tracing/ExcludeList.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -59,7 +59,14 @@ public final class ExcludeList { "java.lang.String::checkIndex", // Used by charAt(int) "java.lang.String::isLatin1", // Used by charAt() "java.lang.String::equals", // Used by StringPool - "java.lang.String::hashCode" // Used by StringPool + "java.lang.String::hashCode", // Used by StringPool + // Used by Bits during Event::commit(), directly or indirectly + "java.lang.Integer::reverseBytes", + "java.lang.Long::reverseBytes", + "java.lang.Float::floatToIntBits", + "java.lang.Float::isNaN", + "java.lang.Double::doubleToLongBits", + "java.lang.Double::isNaN" ); public static boolean containsMethod(String methodName) { From e191df7f156e43cc350e0dcc2ef126d9ef3cf24a Mon Sep 17 00:00:00 2001 From: Phil Race Date: Tue, 31 Mar 2026 17:54:55 +0000 Subject: [PATCH 127/359] 8134541: latent concurrency bug in ScriptRunData Reviewed-by: honkar, dnguyen, serb --- src/java.desktop/share/classes/sun/font/ScriptRunData.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/java.desktop/share/classes/sun/font/ScriptRunData.java b/src/java.desktop/share/classes/sun/font/ScriptRunData.java index 1f1f6b44d59..4e13fb5bbd0 100644 --- a/src/java.desktop/share/classes/sun/font/ScriptRunData.java +++ b/src/java.desktop/share/classes/sun/font/ScriptRunData.java @@ -38,11 +38,12 @@ public final class ScriptRunData { private static final int CHAR_START = 0; private static final int CHAR_LIMIT = 0x110000; - private static int cache = 0; + private static volatile int cache = 0; public static int getScript(int cp) { + int lcache = cache; // optimize for runs of characters in the same script - if (cp >= data[cache] && cp < data[cache+2]) { - return data[cache+1]; + if (cp >= data[lcache] && cp < data[lcache+2]) { + return data[lcache+1]; } if ((cp >= CHAR_START) && (cp < CHAR_LIMIT)) { int probe = dataPower; From 644cccae78d65de347f965e4a2f652422a415330 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Tue, 31 Mar 2026 17:58:53 +0000 Subject: [PATCH 128/359] 8381020: Remove AppContext from java.awt.Dialog Reviewed-by: dnguyen, kizune --- .../share/classes/java/awt/Dialog.java | 37 +------------------ 1 file changed, 2 insertions(+), 35 deletions(-) diff --git a/src/java.desktop/share/classes/java/awt/Dialog.java b/src/java.desktop/share/classes/java/awt/Dialog.java index 83aa89b9bf7..038aa5b65e3 100644 --- a/src/java.desktop/share/classes/java/awt/Dialog.java +++ b/src/java.desktop/share/classes/java/awt/Dialog.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 @@ import javax.accessibility.AccessibleRole; import javax.accessibility.AccessibleState; import javax.accessibility.AccessibleStateSet; -import sun.awt.AppContext; import sun.awt.SunToolkit; import sun.awt.util.IdentityArrayList; @@ -1013,30 +1012,12 @@ public class Dialog extends Window { if (!isModal()) { conditionalShow(null, null); } else { - AppContext showAppContext = AppContext.getAppContext(); - AtomicLong time = new AtomicLong(); Component predictedFocusOwner = null; try { predictedFocusOwner = getMostRecentFocusOwner(); if (conditionalShow(predictedFocusOwner, time)) { modalFilter = ModalEventFilter.createFilterForDialog(this); - // if this dialog is toolkit-modal, the filter should be added - // to all EDTs (for all AppContexts) - if (modalityType == ModalityType.TOOLKIT_MODAL) { - for (AppContext appContext : AppContext.getAppContexts()) { - if (appContext == showAppContext) { - continue; - } - EventQueue eventQueue = (EventQueue)appContext.get(AppContext.EVENT_QUEUE_KEY); - // it may occur that EDT for appContext hasn't been started yet, so - // we post an empty invocation event to trigger EDT initialization - eventQueue.postEvent(new InvocationEvent(this, () -> {})); - EventDispatchThread edt = eventQueue.getDispatchThread(); - edt.addEventFilter(modalFilter); - } - } - modalityPushed(); try { EventQueue eventQueue = Toolkit.getDefaultToolkit().getSystemEventQueue(); @@ -1047,19 +1028,6 @@ public class Dialog extends Window { } finally { modalityPopped(); } - - // if this dialog is toolkit-modal, its filter must be removed - // from all EDTs (for all AppContexts) - if (modalityType == ModalityType.TOOLKIT_MODAL) { - for (AppContext appContext : AppContext.getAppContexts()) { - if (appContext == showAppContext) { - continue; - } - EventQueue eventQueue = (EventQueue)appContext.get(AppContext.EVENT_QUEUE_KEY); - EventDispatchThread edt = eventQueue.getDispatchThread(); - edt.removeEventFilter(modalFilter); - } - } } } finally { if (predictedFocusOwner != null) { @@ -1482,8 +1450,7 @@ public class Dialog extends Window { return getDocumentRoot() == w.getDocumentRoot(); } case APPLICATION_MODAL: - return !w.isModalExcluded(ModalExclusionType.APPLICATION_EXCLUDE) && - (appContext == w.appContext); + return !w.isModalExcluded(ModalExclusionType.APPLICATION_EXCLUDE); case TOOLKIT_MODAL: return !w.isModalExcluded(ModalExclusionType.TOOLKIT_EXCLUDE); } From 20c3082aac4381a5d38ed3abb34b3651b2d28e08 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Tue, 31 Mar 2026 18:41:51 +0000 Subject: [PATCH 129/359] 8380578: Remove miscellaneous AppContext uses, mostly in XAWT Reviewed-by: serb, azvegint --- .../classes/sun/awt/util/PerformanceLogger.java | 7 +------ .../unix/classes/sun/awt/X11/InfoWindow.java | 7 ++++--- .../classes/sun/awt/X11/XBaseMenuWindow.java | 8 ++------ .../sun/awt/X11/XEmbedChildProxyPeer.java | 8 ++++---- .../unix/classes/sun/awt/X11/XTaskbarPeer.java | 4 ++-- .../unix/classes/sun/awt/X11/XToolkit.java | 16 +--------------- .../unix/classes/sun/awt/X11/XTrayIconPeer.java | 12 ++++++------ .../unix/classes/sun/awt/X11InputMethodBase.java | 4 ++-- .../unix/native/common/awt/awt_Component.h | 3 +-- .../unix/native/libawt_xawt/xawt/XToolkit.c | 6 +----- .../native/libawt/windows/awt_Component.cpp | 8 +------- .../native/libawt/windows/awt_Component.h | 3 +-- 12 files changed, 26 insertions(+), 60 deletions(-) diff --git a/src/java.desktop/share/classes/sun/awt/util/PerformanceLogger.java b/src/java.desktop/share/classes/sun/awt/util/PerformanceLogger.java index 4a1dde6538d..cf0ff1d9958 100644 --- a/src/java.desktop/share/classes/sun/awt/util/PerformanceLogger.java +++ b/src/java.desktop/share/classes/sun/awt/util/PerformanceLogger.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2026, Oracle and/or its affiliates. All rights reserved. * 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,11 +43,6 @@ import java.io.Writer; * for setting and getting all times and for doing whatever * analysis is interesting; this class is merely a central container * for those timing values. - * Note that, due to the variables in this class being static, - * use of particular time values by multiple AppContexts will cause - * confusing results. For example, if two contexts run - * simultaneously, the initTime for those will collide - * and the results may be undefined. *

* To automatically track startup performance in an app * use the command-line parameter sun.perflog as follows:
diff --git a/src/java.desktop/unix/classes/sun/awt/X11/InfoWindow.java b/src/java.desktop/unix/classes/sun/awt/X11/InfoWindow.java index bab0f34f90f..c03eae62225 100644 --- a/src/java.desktop/unix/classes/sun/awt/X11/InfoWindow.java +++ b/src/java.desktop/unix/classes/sun/awt/X11/InfoWindow.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,7 @@ import java.awt.Color; import java.awt.Component; import java.awt.Container; import java.awt.Dimension; +import java.awt.EventQueue; import java.awt.Font; import java.awt.Frame; import java.awt.GridLayout; @@ -91,7 +92,7 @@ public abstract class InfoWindow extends Window { // Must be executed on EDT. @SuppressWarnings("deprecation") protected void show(Point corner, int indent) { - assert SunToolkit.isDispatchThreadForAppContext(this); + assert EventQueue.isDispatchThread(); pack(); @@ -464,7 +465,7 @@ public abstract class InfoWindow extends Window { ActionEvent aev = new ActionEvent(target, ActionEvent.ACTION_PERFORMED, liveArguments.getActionCommand(), e.getWhen(), e.getModifiers()); - XToolkit.postEvent(XToolkit.targetToAppContext(aev.getSource()), aev); + XToolkit.postEvent(aev); } } } diff --git a/src/java.desktop/unix/classes/sun/awt/X11/XBaseMenuWindow.java b/src/java.desktop/unix/classes/sun/awt/X11/XBaseMenuWindow.java index f8fcb30d8d8..9512d1d0351 100644 --- a/src/java.desktop/unix/classes/sun/awt/X11/XBaseMenuWindow.java +++ b/src/java.desktop/unix/classes/sun/awt/X11/XBaseMenuWindow.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -114,8 +114,6 @@ public abstract class XBaseMenuWindow extends XWindow { protected Point grabInputPoint = null; protected boolean hasPointerMoved = false; - private AppContext disposeAppContext; - /************************************************ * * Mapping data @@ -175,8 +173,6 @@ public abstract class XBaseMenuWindow extends XWindow { XBaseMenuWindow() { super(new XCreateWindowParams(new Object[] { DELAYED, Boolean.TRUE})); - - disposeAppContext = AppContext.getAppContext(); } /************************************************ @@ -920,7 +916,7 @@ public abstract class XBaseMenuWindow extends XWindow { public void dispose() { setDisposed(true); - SunToolkit.invokeLaterOnAppContext(disposeAppContext, new Runnable() { + SunToolkit.invokeLater(new Runnable() { public void run() { doDispose(); } diff --git a/src/java.desktop/unix/classes/sun/awt/X11/XEmbedChildProxyPeer.java b/src/java.desktop/unix/classes/sun/awt/X11/XEmbedChildProxyPeer.java index efae47d6f23..03593761111 100644 --- a/src/java.desktop/unix/classes/sun/awt/X11/XEmbedChildProxyPeer.java +++ b/src/java.desktop/unix/classes/sun/awt/X11/XEmbedChildProxyPeer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -201,7 +201,7 @@ public final class XEmbedChildProxyPeer implements ComponentPeer, XEventDispatch public void updateCursorImmediately() {} void postEvent(AWTEvent event) { - XToolkit.postEvent(XToolkit.targetToAppContext(proxy), event); + XToolkit.postEvent(event); } boolean simulateMotifRequestFocus(Component lightweightChild, boolean temporary, @@ -323,9 +323,9 @@ public final class XEmbedChildProxyPeer implements ComponentPeer, XEventDispatch } void childResized() { - XToolkit.postEvent(XToolkit.targetToAppContext(proxy), new ComponentEvent(proxy, ComponentEvent.COMPONENT_RESIZED)); + XToolkit.postEvent(new ComponentEvent(proxy, ComponentEvent.COMPONENT_RESIZED)); container.childResized(proxy); -// XToolkit.postEvent(XToolkit.targetToAppContext(proxy), new InvocationEvent(proxy, new Runnable() { +// XToolkit.postEvent(new InvocationEvent(proxy, new Runnable() { // public void run() { // getTopLevel(proxy).invalidate(); // getTopLevel(proxy).pack(); diff --git a/src/java.desktop/unix/classes/sun/awt/X11/XTaskbarPeer.java b/src/java.desktop/unix/classes/sun/awt/X11/XTaskbarPeer.java index 7f0629e101e..cb80f0abd0e 100644 --- a/src/java.desktop/unix/classes/sun/awt/X11/XTaskbarPeer.java +++ b/src/java.desktop/unix/classes/sun/awt/X11/XTaskbarPeer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -152,7 +152,7 @@ final class XTaskbarPeer implements TaskbarPeer { mi.getActionCommand()); try { XToolkit.awtLock(); - XToolkit.postEvent(XToolkit.targetToAppContext(ae.getSource()), ae); + XToolkit.postEvent(ae); } finally { XToolkit.awtUnlock(); } diff --git a/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java b/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java index 5dcd1b763e1..1ec0039febd 100644 --- a/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java +++ b/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java @@ -625,14 +625,8 @@ public final class XToolkit extends UNIXToolkit implements Runnable { while(true) { // Fix for 6829923: we should gracefully handle toolkit thread interruption if (Thread.currentThread().isInterrupted()) { - // We expect interruption from the AppContext.dispose() method only. // If the thread is interrupted from another place, let's skip it - // for compatibility reasons. Probably some time later we'll remove - // the check for AppContext.isDisposed() and will unconditionally - // break the loop here. - if (AppContext.getAppContext().isDisposed()) { - break; - } + // for compatibility reasons. } awtLock(); try { @@ -2054,14 +2048,6 @@ public final class XToolkit extends UNIXToolkit implements Runnable { (exclusionType == Dialog.ModalExclusionType.TOOLKIT_EXCLUDE); } - static EventQueue getEventQueue(Object target) { - AppContext appContext = targetToAppContext(target); - if (appContext != null) { - return (EventQueue)appContext.get(AppContext.EVENT_QUEUE_KEY); - } - return null; - } - static void removeSourceEvents(EventQueue queue, Object source, boolean removeAllEvents) { diff --git a/src/java.desktop/unix/classes/sun/awt/X11/XTrayIconPeer.java b/src/java.desktop/unix/classes/sun/awt/X11/XTrayIconPeer.java index 9f0ac241f5b..5ab97125991 100644 --- a/src/java.desktop/unix/classes/sun/awt/X11/XTrayIconPeer.java +++ b/src/java.desktop/unix/classes/sun/awt/X11/XTrayIconPeer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2026, Oracle and/or its affiliates. All rights reserved. * 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,7 @@ public final class XTrayIconPeer implements TrayIconPeer, @Override public void dispose() { - if (SunToolkit.isDispatchThreadForAppContext(target)) { + if (EventQueue.isDispatchThread()) { disposeOnEDT(); } else { try { @@ -329,7 +329,7 @@ public final class XTrayIconPeer implements TrayIconPeer, } }; - if (!SunToolkit.isDispatchThreadForAppContext(target)) { + if (!EventQueue.isDispatchThread()) { SunToolkit.executeOnEventHandlerThread(target, r); } else { r.run(); @@ -355,7 +355,7 @@ public final class XTrayIconPeer implements TrayIconPeer, if (isDisposed()) return; - assert SunToolkit.isDispatchThreadForAppContext(target); + assert EventQueue.isDispatchThread(); PopupMenu newPopup = target.getPopupMenu(); if (popup != newPopup) { @@ -476,7 +476,7 @@ public final class XTrayIconPeer implements TrayIconPeer, // other class tries to cast source field to Component). // We already filter DRAG events out (CR 6565779). e.setSource(xtiPeer.target); - XToolkit.postEvent(XToolkit.targetToAppContext(e.getSource()), e); + XToolkit.postEvent(e); } @Override @SuppressWarnings("deprecation") @@ -487,7 +487,7 @@ public final class XTrayIconPeer implements TrayIconPeer, ActionEvent aev = new ActionEvent(xtiPeer.target, ActionEvent.ACTION_PERFORMED, xtiPeer.target.getActionCommand(), e.getWhen(), e.getModifiers()); - XToolkit.postEvent(XToolkit.targetToAppContext(aev.getSource()), aev); + XToolkit.postEvent(aev); } if (xtiPeer.balloon.isVisible()) { xtiPeer.balloon.hide(); diff --git a/src/java.desktop/unix/classes/sun/awt/X11InputMethodBase.java b/src/java.desktop/unix/classes/sun/awt/X11InputMethodBase.java index d9eaa9629d1..3aa1624a1dd 100644 --- a/src/java.desktop/unix/classes/sun/awt/X11InputMethodBase.java +++ b/src/java.desktop/unix/classes/sun/awt/X11InputMethodBase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -434,7 +434,7 @@ public abstract class X11InputMethodBase extends InputMethodAdapter { if (source != null) { InputMethodEvent event = new InputMethodEvent(source, id, when, text, committedCharacterCount, caret, visiblePosition); - SunToolkit.postEvent(SunToolkit.targetToAppContext(source), (AWTEvent)event); + SunToolkit.postEvent((AWTEvent)event); } } diff --git a/src/java.desktop/unix/native/common/awt/awt_Component.h b/src/java.desktop/unix/native/common/awt/awt_Component.h index 089691a8a4d..7ef0a0de94b 100644 --- a/src/java.desktop/unix/native/common/awt/awt_Component.h +++ b/src/java.desktop/unix/native/common/awt/awt_Component.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 @@ struct ComponentIDs { jfieldID graphicsConfig; jfieldID name; jfieldID isProxyActive; - jfieldID appContext; jmethodID getParent; jmethodID getLocationOnScreen; }; diff --git a/src/java.desktop/unix/native/libawt_xawt/xawt/XToolkit.c b/src/java.desktop/unix/native/libawt_xawt/xawt/XToolkit.c index d5f3130386d..c84aa4ff8f9 100644 --- a/src/java.desktop/unix/native/libawt_xawt/xawt/XToolkit.c +++ b/src/java.desktop/unix/native/libawt_xawt/xawt/XToolkit.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2026, Oracle and/or its affiliates. All rights reserved. * 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,10 +195,6 @@ Java_java_awt_Component_initIDs "Z"); CHECK_NULL(componentIDs.isProxyActive); - componentIDs.appContext = - (*env)->GetFieldID(env, cls, "appContext", - "Lsun/awt/AppContext;"); - (*env)->DeleteLocalRef(env, keyclass); } diff --git a/src/java.desktop/windows/native/libawt/windows/awt_Component.cpp b/src/java.desktop/windows/native/libawt/windows/awt_Component.cpp index b67c5dfcf8d..eca8290a1aa 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_Component.cpp +++ b/src/java.desktop/windows/native/libawt/windows/awt_Component.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -178,7 +178,6 @@ jfieldID AwtComponent::parentID; jfieldID AwtComponent::graphicsConfigID; jfieldID AwtComponent::peerGCID; jfieldID AwtComponent::focusableID; -jfieldID AwtComponent::appContextID; jfieldID AwtComponent::cursorID; jfieldID AwtComponent::hwndID; @@ -6573,11 +6572,6 @@ Java_java_awt_Component_initIDs(JNIEnv *env, jclass cls) DASSERT(AwtComponent::focusableID); CHECK_NULL(AwtComponent::focusableID); - AwtComponent::appContextID = env->GetFieldID(cls, "appContext", - "Lsun/awt/AppContext;"); - DASSERT(AwtComponent::appContextID); - CHECK_NULL(AwtComponent::appContextID); - AwtComponent::peerGCID = env->GetFieldID(peerCls, "winGraphicsConfig", "Lsun/awt/Win32GraphicsConfig;"); DASSERT(AwtComponent::peerGCID); diff --git a/src/java.desktop/windows/native/libawt/windows/awt_Component.h b/src/java.desktop/windows/native/libawt/windows/awt_Component.h index 740eb8c72f9..1246f6cb06e 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_Component.h +++ b/src/java.desktop/windows/native/libawt/windows/awt_Component.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2026, Oracle and/or its affiliates. All rights reserved. * 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,7 +112,6 @@ public: static jfieldID graphicsConfigID; static jfieldID peerGCID; static jfieldID focusableID; - static jfieldID appContextID; static jfieldID hwndID; static jmethodID getFontMID; From f46a6981137bd09e9387c168eb24e4bc2edf32c4 Mon Sep 17 00:00:00 2001 From: Daniel Gredler Date: Tue, 31 Mar 2026 21:46:05 +0000 Subject: [PATCH 130/359] 8381015: CharsetEncoder.canEncode(CharSequence) is slow for UTF-8, UTF-16, UTF-32 Reviewed-by: naoto, vyazici --- .../share/classes/sun/nio/cs/UTF_32Coder.java | 9 +++- .../share/classes/sun/nio/cs/UTF_8.java | 4 ++ .../share/classes/sun/nio/cs/Unicode.java | 21 ++++++++- .../classes/sun/nio/cs/UnicodeEncoder.java | 6 ++- .../nio/charset/CharsetEncoder/CanEncode.java | 46 +++++++++++++++---- .../bench/java/nio/CharsetCanEncode.java | 23 ++++++++++ 6 files changed, 97 insertions(+), 12 deletions(-) diff --git a/src/java.base/share/classes/sun/nio/cs/UTF_32Coder.java b/src/java.base/share/classes/sun/nio/cs/UTF_32Coder.java index c6f38ec9bfc..72e59d22e2c 100644 --- a/src/java.base/share/classes/sun/nio/cs/UTF_32Coder.java +++ b/src/java.base/share/classes/sun/nio/cs/UTF_32Coder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -185,5 +185,12 @@ class UTF_32Coder { doneBOM = !doBOM; } + public boolean canEncode(char c) { + return !Character.isSurrogate(c); + } + + public boolean canEncode(CharSequence cs) { + return Unicode.isValidUnicode(cs); + } } } diff --git a/src/java.base/share/classes/sun/nio/cs/UTF_8.java b/src/java.base/share/classes/sun/nio/cs/UTF_8.java index 2928ae6d509..fda8e5eec1f 100644 --- a/src/java.base/share/classes/sun/nio/cs/UTF_8.java +++ b/src/java.base/share/classes/sun/nio/cs/UTF_8.java @@ -424,6 +424,10 @@ public final class UTF_8 extends Unicode { return !Character.isSurrogate(c); } + public boolean canEncode(CharSequence cs) { + return Unicode.isValidUnicode(cs); + } + public boolean isLegalReplacement(byte[] repl) { return ((repl.length == 1 && repl[0] >= 0) || super.isLegalReplacement(repl)); diff --git a/src/java.base/share/classes/sun/nio/cs/Unicode.java b/src/java.base/share/classes/sun/nio/cs/Unicode.java index aac77a13ffb..06a50f125c5 100644 --- a/src/java.base/share/classes/sun/nio/cs/Unicode.java +++ b/src/java.base/share/classes/sun/nio/cs/Unicode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -95,4 +95,23 @@ abstract class Unicode extends Charset || (cs.name().equals("x-Johab")) || (cs.name().equals("Shift_JIS"))); } + + static boolean isValidUnicode(CharSequence cs) { + int length = cs.length(); + for (int i = 0; i < length;) { + char c = cs.charAt(i++); + if (Character.isHighSurrogate(c)) { + if (i == length) { + return false; + } + char low = cs.charAt(i++); + if (!Character.isLowSurrogate(low)) { + return false; + } + } else if (Character.isLowSurrogate(c)) { + return false; + } + } + return true; + } } diff --git a/src/java.base/share/classes/sun/nio/cs/UnicodeEncoder.java b/src/java.base/share/classes/sun/nio/cs/UnicodeEncoder.java index 7b34fb2d512..6f7413dcbf8 100644 --- a/src/java.base/share/classes/sun/nio/cs/UnicodeEncoder.java +++ b/src/java.base/share/classes/sun/nio/cs/UnicodeEncoder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * 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,4 +108,8 @@ public abstract class UnicodeEncoder extends CharsetEncoder { public boolean canEncode(char c) { return ! Character.isSurrogate(c); } + + public boolean canEncode(CharSequence cs) { + return Unicode.isValidUnicode(cs); + } } diff --git a/test/jdk/java/nio/charset/CharsetEncoder/CanEncode.java b/test/jdk/java/nio/charset/CharsetEncoder/CanEncode.java index 8545ef61be9..d4dabf70910 100644 --- a/test/jdk/java/nio/charset/CharsetEncoder/CanEncode.java +++ b/test/jdk/java/nio/charset/CharsetEncoder/CanEncode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2026, Oracle and/or its affiliates. All rights reserved. * 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,14 +66,21 @@ public class CanEncode { Charset cs = Charset.forName(csn); CharsetEncoder ce = cs.newEncoder(); - if (cs.name().equals("US-ASCII")) { - ck(ce, 'x', true); - ck(ce, '\u00B6', false); - ck(ce, "x", true); - ck(ce, "\u00B6", false); - ck(ce, "xyzzy", true); - ck(ce, "xy\u00B6", false); - } + // Basic multilingual plane + boolean utf = csn.startsWith("UTF-"); + ck(ce, 'x', true); + ck(ce, '\u00B6', utf); + ck(ce, "", true); + ck(ce, "x", true); + ck(ce, "\u00B6", utf); + ck(ce, "xyzzy", true); + ck(ce, "xy\u00B6", utf); + + // Paired surrogates + ck(ce, "\uD83D\uDE00", utf); + ck(ce, "XX\uD83D\uDE00", utf); + ck(ce, "\uD83D\uDE00XX", utf); + ck(ce, "X\uD83D\uDE00X", utf); // Unpaired surrogates should never be encodable ck(ce, '\ud800', false); @@ -81,15 +88,36 @@ public class CanEncode { ck(ce, '\udffe', false); ck(ce, '\udfff', false); ck(ce, "\ud800", false); + ck(ce, "XX\ud800", false); + ck(ce, "\ud800XX", false); + ck(ce, "X\ud800X", false); ck(ce, "\ud801", false); + ck(ce, "XX\ud801", false); + ck(ce, "\ud801XX", false); + ck(ce, "X\ud801X", false); ck(ce, "\udffe", false); + ck(ce, "XX\udffe", false); + ck(ce, "\udffeXX", false); + ck(ce, "X\udffeX", false); ck(ce, "\udfff", false); + ck(ce, "XX\udfff", false); + ck(ce, "\udfffXX", false); + ck(ce, "X\udfffX", false); + if (errors > 0) { + throw new RuntimeException(errors + " errors for Charset " + csn); + } } public static void main(String[] args) throws Exception { test("US-ASCII"); test("UTF-8"); + test("UTF-16"); + test("UTF-16LE"); + test("UTF-16BE"); + test("UTF-32"); + test("UTF-32LE"); + test("UTF-32BE"); } } diff --git a/test/micro/org/openjdk/bench/java/nio/CharsetCanEncode.java b/test/micro/org/openjdk/bench/java/nio/CharsetCanEncode.java index ebfbc217a95..8c08a876696 100644 --- a/test/micro/org/openjdk/bench/java/nio/CharsetCanEncode.java +++ b/test/micro/org/openjdk/bench/java/nio/CharsetCanEncode.java @@ -65,6 +65,9 @@ public class CharsetCanEncode { // sun.nio.cs.UTF_16LE private CharsetEncoder utf16le = Charset.forName("UTF-16LE").newEncoder(); + // sun.nio.cs.UTF_32LE + private CharsetEncoder utf32le = Charset.forName("UTF-32LE").newEncoder(); + @Benchmark public boolean asciiCanEncodeCharYes() { return ascii.canEncode('D'); @@ -184,4 +187,24 @@ public class CharsetCanEncode { public boolean utf16leCanEncodeStringNo() { return utf16le.canEncode(String.valueOf(Character.MIN_SURROGATE)); } + + @Benchmark + public boolean utf32leCanEncodeCharYes() { + return utf32le.canEncode('D'); + } + + @Benchmark + public boolean utf32leCanEncodeStringYes() { + return utf32le.canEncode("D"); + } + + @Benchmark + public boolean utf32leCanEncodeCharNo() { + return utf32le.canEncode(Character.MIN_SURROGATE); + } + + @Benchmark + public boolean utf32leCanEncodeStringNo() { + return utf32le.canEncode(String.valueOf(Character.MIN_SURROGATE)); + } } From 3f6271b2b91c096d1b6fcb74c279c5607e116357 Mon Sep 17 00:00:00 2001 From: Kerem Kat Date: Wed, 1 Apr 2026 00:10:02 +0000 Subject: [PATCH 131/359] 8375442: C2: Notify nodes that inspect the graph deeply of changes far away during IGVN Reviewed-by: qamai, aseoane --- src/hotspot/share/opto/c2_globals.hpp | 4 + src/hotspot/share/opto/cfgnode.cpp | 4 +- src/hotspot/share/opto/compile.cpp | 10 +- src/hotspot/share/opto/escape.cpp | 2 +- src/hotspot/share/opto/graphKit.cpp | 4 +- src/hotspot/share/opto/ifnode.cpp | 29 +- src/hotspot/share/opto/loopnode.cpp | 8 +- src/hotspot/share/opto/loopopts.cpp | 18 +- src/hotspot/share/opto/macro.cpp | 24 +- src/hotspot/share/opto/memnode.cpp | 2 +- src/hotspot/share/opto/phaseX.cpp | 290 +++++++++++------- src/hotspot/share/opto/phaseX.hpp | 78 ++++- src/hotspot/share/opto/split_if.cpp | 24 +- .../compiler/arraycopy/TestCloneAccess.java | 12 +- .../compiler/c2/igvn/TestDeepIGVNRevisit.java | 83 +++++ .../igvn/TestFoldComparesCleanup.java | 56 ++++ .../compiler/lib/ir_framework/IRNode.java | 5 + 17 files changed, 467 insertions(+), 186 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/c2/igvn/TestDeepIGVNRevisit.java create mode 100644 test/hotspot/jtreg/compiler/igvn/TestFoldComparesCleanup.java diff --git a/src/hotspot/share/opto/c2_globals.hpp b/src/hotspot/share/opto/c2_globals.hpp index a4f6d04f6a3..983ac8a32c6 100644 --- a/src/hotspot/share/opto/c2_globals.hpp +++ b/src/hotspot/share/opto/c2_globals.hpp @@ -705,6 +705,10 @@ develop(bool, TraceIterativeGVN, false, \ "Print progress during Iterative Global Value Numbering") \ \ + develop(bool, UseDeepIGVNRevisit, true, \ + "Re-process nodes that could benefit from a deep revisit after " \ + "the IGVN worklist drains") \ + \ develop(uint, VerifyIterativeGVN, 0, \ "Verify Iterative Global Value Numbering =FEDCBA, with:" \ " F: verify Node::Ideal does not return nullptr if the node" \ diff --git a/src/hotspot/share/opto/cfgnode.cpp b/src/hotspot/share/opto/cfgnode.cpp index 0915f79a503..828e5bf299f 100644 --- a/src/hotspot/share/opto/cfgnode.cpp +++ b/src/hotspot/share/opto/cfgnode.cpp @@ -735,7 +735,7 @@ Node *RegionNode::Ideal(PhaseGVN *phase, bool can_reshape) { #endif } // Remove the RegionNode itself from DefUse info - igvn->remove_dead_node(this); + igvn->remove_dead_node(this, PhaseIterGVN::NodeOrigin::Graph); return nullptr; } return this; // Record progress @@ -1007,7 +1007,7 @@ bool RegionNode::optimize_trichotomy(PhaseIterGVN* igvn) { BoolNode* new_bol = new BoolNode(bol2->in(1), res); igvn->replace_input_of(iff2, 1, igvn->transform((proj2->_con == 1) ? new_bol : new_bol->negate(igvn))); if (new_bol->outcnt() == 0) { - igvn->remove_dead_node(new_bol); + igvn->remove_dead_node(new_bol, PhaseIterGVN::NodeOrigin::Speculative); } } return false; diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index 7ab384a29c7..7b5f78a8ad3 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -2277,7 +2277,7 @@ void Compile::remove_root_to_sfpts_edges(PhaseIterGVN& igvn) { if (n != nullptr && n->is_SafePoint()) { r->rm_prec(i); if (n->outcnt() == 0) { - igvn.remove_dead_node(n); + igvn.remove_dead_node(n, PhaseIterGVN::NodeOrigin::Graph); } --i; } @@ -2321,7 +2321,7 @@ void Compile::Optimize() { #endif { TracePhase tp(_t_iterGVN); - igvn.optimize(); + igvn.optimize(true); } if (failing()) return; @@ -2385,7 +2385,7 @@ void Compile::Optimize() { PhaseRenumberLive prl(initial_gvn(), *igvn_worklist()); } igvn.reset(); - igvn.optimize(); + igvn.optimize(true); if (failing()) return; } @@ -2418,7 +2418,7 @@ void Compile::Optimize() { int mcount = macro_count(); // Record number of allocations and locks before IGVN // Optimize out fields loads from scalar replaceable allocations. - igvn.optimize(); + igvn.optimize(true); print_method(PHASE_ITER_GVN_AFTER_EA, 2); if (failing()) return; @@ -2498,7 +2498,7 @@ void Compile::Optimize() { { TracePhase tp(_t_iterGVN2); igvn.reset_from_igvn(&ccp); - igvn.optimize(); + igvn.optimize(true); } print_method(PHASE_ITER_GVN2, 2); diff --git a/src/hotspot/share/opto/escape.cpp b/src/hotspot/share/opto/escape.cpp index 7041eb0b810..64ee60037d6 100644 --- a/src/hotspot/share/opto/escape.cpp +++ b/src/hotspot/share/opto/escape.cpp @@ -933,7 +933,7 @@ void ConnectionGraph::reduce_phi_on_castpp_field_load(Node* curr_castpp, Growabl j = MIN2(j, (int)use->outcnt()-1); } - _igvn->remove_dead_node(use); + _igvn->remove_dead_node(use, PhaseIterGVN::NodeOrigin::Graph); } --i; i = MIN2(i, (int)curr_castpp->outcnt()-1); diff --git a/src/hotspot/share/opto/graphKit.cpp b/src/hotspot/share/opto/graphKit.cpp index e297292770e..8d32694e9a5 100644 --- a/src/hotspot/share/opto/graphKit.cpp +++ b/src/hotspot/share/opto/graphKit.cpp @@ -2911,8 +2911,8 @@ Node* Phase::gen_subtype_check(Node* subklass, Node* superklass, Node** ctrl, No *ctrl = iftrue1; // We need exactly the 1 test above PhaseIterGVN* igvn = gvn.is_IterGVN(); if (igvn != nullptr) { - igvn->remove_globally_dead_node(r_ok_subtype); - igvn->remove_globally_dead_node(r_not_subtype); + igvn->remove_globally_dead_node(r_ok_subtype, PhaseIterGVN::NodeOrigin::Speculative); + igvn->remove_globally_dead_node(r_not_subtype, PhaseIterGVN::NodeOrigin::Speculative); } return not_subtype_ctrl; } diff --git a/src/hotspot/share/opto/ifnode.cpp b/src/hotspot/share/opto/ifnode.cpp index 762791d467d..ad8f0ced6ea 100644 --- a/src/hotspot/share/opto/ifnode.cpp +++ b/src/hotspot/share/opto/ifnode.cpp @@ -132,7 +132,7 @@ static Node* split_if(IfNode *iff, PhaseIterGVN *igvn) { cmp2->set_req(2,con2); const Type *t = cmp2->Value(igvn); // This compare is dead, so whack it! - igvn->remove_dead_node(cmp2); + igvn->remove_dead_node(cmp2, PhaseIterGVN::NodeOrigin::Speculative); if( !t->singleton() ) return nullptr; // No intervening control, like a simple Call @@ -443,7 +443,7 @@ static Node* split_if(IfNode *iff, PhaseIterGVN *igvn) { } l -= uses_found; // we deleted 1 or more copies of this edge } - igvn->remove_dead_node(p); + igvn->remove_dead_node(p, PhaseIterGVN::NodeOrigin::Graph); } // Force the original merge dead @@ -455,14 +455,14 @@ static Node* split_if(IfNode *iff, PhaseIterGVN *igvn) { r->set_req(0, nullptr); } else { assert(u->outcnt() == 0, "only dead users"); - igvn->remove_dead_node(u); + igvn->remove_dead_node(u, PhaseIterGVN::NodeOrigin::Graph); } l -= 1; } - igvn->remove_dead_node(r); + igvn->remove_dead_node(r, PhaseIterGVN::NodeOrigin::Graph); // Now remove the bogus extra edges used to keep things alive - igvn->remove_dead_node( hook ); + igvn->remove_dead_node(hook, PhaseIterGVN::NodeOrigin::Speculative); // Must return either the original node (now dead) or a new node // (Do not return a top here, since that would break the uniqueness of top.) @@ -905,6 +905,7 @@ bool IfNode::fold_compares_helper(IfProjNode* proj, IfProjNode* success, IfProjN IfNode* dom_iff = proj->in(0)->as_If(); BoolNode* dom_bool = dom_iff->in(1)->as_Bool(); Node* lo = dom_iff->in(1)->in(1)->in(2); + Node* orig_lo = lo; Node* hi = this_cmp->in(2); Node* n = this_cmp->in(1); IfProjNode* otherproj = proj->other_if_proj(); @@ -916,6 +917,7 @@ bool IfNode::fold_compares_helper(IfProjNode* proj, IfProjNode* success, IfProjN BoolTest::mask hi_test = this_bool->_test._test; BoolTest::mask cond = hi_test; + PhaseTransform::SpeculativeProgressGuard progress_guard(igvn); // convert: // // dom_bool = x {<,<=,>,>=} a @@ -1053,6 +1055,7 @@ bool IfNode::fold_compares_helper(IfProjNode* proj, IfProjNode* success, IfProjN // previous if determines the result of this if so // replace Bool with constant igvn->replace_input_of(this, 1, igvn->intcon(success->_con)); + progress_guard.commit(); return true; } } @@ -1087,11 +1090,14 @@ bool IfNode::fold_compares_helper(IfProjNode* proj, IfProjNode* success, IfProjN // min(limit, max(-2 + min_jint + 1, min_jint)) // = min(limit, min_jint) // = min_jint + if (lo != orig_lo && lo->outcnt() == 0) { + igvn->remove_dead_node(lo, PhaseIterGVN::NodeOrigin::Speculative); + } if (adjusted_val->outcnt() == 0) { - igvn->remove_dead_node(adjusted_val); + igvn->remove_dead_node(adjusted_val, PhaseIterGVN::NodeOrigin::Speculative); } if (adjusted_lim->outcnt() == 0) { - igvn->remove_dead_node(adjusted_lim); + igvn->remove_dead_node(adjusted_lim, PhaseIterGVN::NodeOrigin::Speculative); } igvn->C->record_for_post_loop_opts_igvn(this); return false; @@ -1103,6 +1109,7 @@ bool IfNode::fold_compares_helper(IfProjNode* proj, IfProjNode* success, IfProjN igvn->replace_input_of(dom_iff, 1, igvn->intcon(proj->_con)); igvn->replace_input_of(this, 1, newbool); + progress_guard.commit(); return true; } @@ -1592,11 +1599,11 @@ Node* IfNode::dominated_by(Node* prev_dom, PhaseIterGVN* igvn, bool prev_dom_not } } // End for each child of a projection - igvn->remove_dead_node(ifp); + igvn->remove_dead_node(ifp, PhaseIterGVN::NodeOrigin::Graph); } // End for each IfTrue/IfFalse child of If // Kill the IfNode - igvn->remove_dead_node(this); + igvn->remove_dead_node(this, PhaseIterGVN::NodeOrigin::Graph); // Must return either the original node (now dead) or a new node // (Do not return a top here, since that would break the uniqueness of top.) @@ -1758,7 +1765,7 @@ Node* IfNode::simple_subsuming(PhaseIterGVN* igvn) { } if (bol->outcnt() == 0) { - igvn->remove_dead_node(bol); // Kill the BoolNode. + igvn->remove_dead_node(bol, PhaseIterGVN::NodeOrigin::Graph); // Kill the BoolNode. } return this; } @@ -1903,7 +1910,7 @@ static IfNode* idealize_test(PhaseGVN* phase, IfNode* iff) { Node *prior = igvn->hash_find_insert(iff); if( prior ) { - igvn->remove_dead_node(iff); + igvn->remove_dead_node(iff, PhaseIterGVN::NodeOrigin::Graph); iff = (IfNode*)prior; } else { // Cannot call transform on it just yet diff --git a/src/hotspot/share/opto/loopnode.cpp b/src/hotspot/share/opto/loopnode.cpp index 23186a25320..6963a67118f 100644 --- a/src/hotspot/share/opto/loopnode.cpp +++ b/src/hotspot/share/opto/loopnode.cpp @@ -697,7 +697,7 @@ SafePointNode* PhaseIdealLoop::find_safepoint(Node* back_control, const Node* he } #ifdef ASSERT if (mm != nullptr) { - _igvn.remove_dead_node(mm); + _igvn.remove_dead_node(mm, PhaseIterGVN::NodeOrigin::Speculative); } #endif } @@ -2002,7 +2002,7 @@ bool CountedLoopConverter::stress_long_counted_loop() { Node* n = iv_nodes.at(i); Node* clone = old_new[n->_idx]; if (clone != nullptr) { - igvn->remove_dead_node(clone); + igvn->remove_dead_node(clone, PhaseIterGVN::NodeOrigin::Speculative); } } return false; @@ -4676,7 +4676,7 @@ void PhaseIdealLoop::replace_parallel_iv(IdealLoopTree *loop) { _igvn.replace_node( phi2, add ); // Sometimes an induction variable is unused if (add->outcnt() == 0) { - _igvn.remove_dead_node(add); + _igvn.remove_dead_node(add, PhaseIterGVN::NodeOrigin::Graph); } --i; // deleted this phi; rescan starting with next position } @@ -5354,7 +5354,7 @@ void PhaseIdealLoop::build_and_optimize() { // clear out the dead code after build_loop_late while (_deadlist.size()) { - _igvn.remove_globally_dead_node(_deadlist.pop()); + _igvn.remove_globally_dead_node(_deadlist.pop(), PhaseIterGVN::NodeOrigin::Graph); } eliminate_useless_zero_trip_guard(); diff --git a/src/hotspot/share/opto/loopopts.cpp b/src/hotspot/share/opto/loopopts.cpp index 4e447edee8d..11b23d7c365 100644 --- a/src/hotspot/share/opto/loopopts.cpp +++ b/src/hotspot/share/opto/loopopts.cpp @@ -161,7 +161,7 @@ Node* PhaseIdealLoop::split_thru_phi(Node* n, Node* region, int policy) { } if (the_clone != x) { - _igvn.remove_dead_node(the_clone); + _igvn.remove_dead_node(the_clone, PhaseIterGVN::NodeOrigin::Speculative); } else if (region->is_Loop() && i == LoopNode::LoopBackControl && n->is_Load() && can_move_to_inner_loop(n, region->as_Loop(), x)) { // it is not a win if 'x' moved from an outer to an inner loop @@ -172,7 +172,7 @@ Node* PhaseIdealLoop::split_thru_phi(Node* n, Node* region, int policy) { } // Too few wins? if (!wins.profitable(policy)) { - _igvn.remove_dead_node(phi); + _igvn.remove_dead_node(phi, PhaseIterGVN::NodeOrigin::Speculative); return nullptr; } @@ -1866,7 +1866,7 @@ void PhaseIdealLoop::try_sink_out_of_loop(Node* n) { assert(cast != nullptr, "must have added a cast to pin the node"); } } - _igvn.remove_dead_node(n); + _igvn.remove_dead_node(n, PhaseIterGVN::NodeOrigin::Graph); } _dom_lca_tags_round = 0; } @@ -2082,7 +2082,7 @@ Node* PhaseIdealLoop::clone_iff(PhiNode* phi) { // Register with optimizer Node *hit1 = _igvn.hash_find_insert(phi1); if (hit1) { // Hit, toss just made Phi - _igvn.remove_dead_node(phi1); // Remove new phi + _igvn.remove_dead_node(phi1, PhaseIterGVN::NodeOrigin::Speculative); // Remove new phi assert(hit1->is_Phi(), "" ); phi1 = (PhiNode*)hit1; // Use existing phi } else { // Miss @@ -2090,7 +2090,7 @@ Node* PhaseIdealLoop::clone_iff(PhiNode* phi) { } Node *hit2 = _igvn.hash_find_insert(phi2); if (hit2) { // Hit, toss just made Phi - _igvn.remove_dead_node(phi2); // Remove new phi + _igvn.remove_dead_node(phi2, PhaseIterGVN::NodeOrigin::Speculative); // Remove new phi assert(hit2->is_Phi(), "" ); phi2 = (PhiNode*)hit2; // Use existing phi } else { // Miss @@ -2165,7 +2165,7 @@ CmpNode*PhaseIdealLoop::clone_bool(PhiNode* phi) { // Register with optimizer Node *hit1 = _igvn.hash_find_insert(phi1); if( hit1 ) { // Hit, toss just made Phi - _igvn.remove_dead_node(phi1); // Remove new phi + _igvn.remove_dead_node(phi1, PhaseIterGVN::NodeOrigin::Speculative); // Remove new phi assert( hit1->is_Phi(), "" ); phi1 = (PhiNode*)hit1; // Use existing phi } else { // Miss @@ -2173,7 +2173,7 @@ CmpNode*PhaseIdealLoop::clone_bool(PhiNode* phi) { } Node *hit2 = _igvn.hash_find_insert(phi2); if( hit2 ) { // Hit, toss just made Phi - _igvn.remove_dead_node(phi2); // Remove new phi + _igvn.remove_dead_node(phi2, PhaseIterGVN::NodeOrigin::Speculative); // Remove new phi assert( hit2->is_Phi(), "" ); phi2 = (PhiNode*)hit2; // Use existing phi } else { // Miss @@ -2324,7 +2324,7 @@ void PhaseIdealLoop::clone_loop_handle_data_uses(Node* old, Node_List &old_new, _igvn.register_new_node_with_optimizer(phi); // Register new phi } else { // or // Remove the new phi from the graph and use the hit - _igvn.remove_dead_node(phi); + _igvn.remove_dead_node(phi, phi == prev ? PhaseIterGVN::NodeOrigin::Graph : PhaseIterGVN::NodeOrigin::Speculative); phi = hit; // Use existing phi } set_ctrl(phi, prev); @@ -3472,7 +3472,7 @@ void PhaseIdealLoop::insert_phi_for_loop( Node* use, uint idx, Node* lp_entry_va set_ctrl(phi, lp); } else { // Remove the new phi from the graph and use the hit - _igvn.remove_dead_node(phi); + _igvn.remove_dead_node(phi, PhaseIterGVN::NodeOrigin::Speculative); phi = hit; } _igvn.replace_input_of(use, idx, phi); diff --git a/src/hotspot/share/opto/macro.cpp b/src/hotspot/share/opto/macro.cpp index c78f6533840..1c54a11e2a4 100644 --- a/src/hotspot/share/opto/macro.cpp +++ b/src/hotspot/share/opto/macro.cpp @@ -973,7 +973,7 @@ void PhaseMacroExpand::process_users_of_allocation(CallNode *alloc) { } k -= (oc2 - use->outcnt()); } - _igvn.remove_dead_node(use); + _igvn.remove_dead_node(use, PhaseIterGVN::NodeOrigin::Graph); } else if (use->is_ArrayCopy()) { // Disconnect ArrayCopy node ArrayCopyNode* ac = use->as_ArrayCopy(); @@ -1008,7 +1008,7 @@ void PhaseMacroExpand::process_users_of_allocation(CallNode *alloc) { // src can be top at this point if src and dest of the // arraycopy were the same if (src->outcnt() == 0 && !src->is_top()) { - _igvn.remove_dead_node(src); + _igvn.remove_dead_node(src, PhaseIterGVN::NodeOrigin::Graph); } } _igvn._worklist.push(ac); @@ -1018,7 +1018,7 @@ void PhaseMacroExpand::process_users_of_allocation(CallNode *alloc) { j -= (oc1 - res->outcnt()); } assert(res->outcnt() == 0, "all uses of allocated objects must be deleted"); - _igvn.remove_dead_node(res); + _igvn.remove_dead_node(res, PhaseIterGVN::NodeOrigin::Graph); } // @@ -1502,7 +1502,7 @@ void PhaseMacroExpand::expand_allocate_common( transform_later(_callprojs.fallthrough_memproj); } migrate_outs(_callprojs.catchall_memproj, _callprojs.fallthrough_memproj); - _igvn.remove_dead_node(_callprojs.catchall_memproj); + _igvn.remove_dead_node(_callprojs.catchall_memproj, PhaseIterGVN::NodeOrigin::Graph); } // An allocate node has separate i_o projections for the uses on the control @@ -1521,7 +1521,7 @@ void PhaseMacroExpand::expand_allocate_common( transform_later(_callprojs.fallthrough_ioproj); } migrate_outs(_callprojs.catchall_ioproj, _callprojs.fallthrough_ioproj); - _igvn.remove_dead_node(_callprojs.catchall_ioproj); + _igvn.remove_dead_node(_callprojs.catchall_ioproj, PhaseIterGVN::NodeOrigin::Graph); } // if we generated only a slow call, we are done @@ -1585,11 +1585,11 @@ void PhaseMacroExpand::yank_alloc_node(AllocateNode* alloc) { --i; // back up iterator } assert(_callprojs.resproj->outcnt() == 0, "all uses must be deleted"); - _igvn.remove_dead_node(_callprojs.resproj); + _igvn.remove_dead_node(_callprojs.resproj, PhaseIterGVN::NodeOrigin::Graph); } if (_callprojs.fallthrough_catchproj != nullptr) { migrate_outs(_callprojs.fallthrough_catchproj, ctrl); - _igvn.remove_dead_node(_callprojs.fallthrough_catchproj); + _igvn.remove_dead_node(_callprojs.fallthrough_catchproj, PhaseIterGVN::NodeOrigin::Graph); } if (_callprojs.catchall_catchproj != nullptr) { _igvn.rehash_node_delayed(_callprojs.catchall_catchproj); @@ -1597,16 +1597,16 @@ void PhaseMacroExpand::yank_alloc_node(AllocateNode* alloc) { } if (_callprojs.fallthrough_proj != nullptr) { Node* catchnode = _callprojs.fallthrough_proj->unique_ctrl_out(); - _igvn.remove_dead_node(catchnode); - _igvn.remove_dead_node(_callprojs.fallthrough_proj); + _igvn.remove_dead_node(catchnode, PhaseIterGVN::NodeOrigin::Graph); + _igvn.remove_dead_node(_callprojs.fallthrough_proj, PhaseIterGVN::NodeOrigin::Graph); } if (_callprojs.fallthrough_memproj != nullptr) { migrate_outs(_callprojs.fallthrough_memproj, mem); - _igvn.remove_dead_node(_callprojs.fallthrough_memproj); + _igvn.remove_dead_node(_callprojs.fallthrough_memproj, PhaseIterGVN::NodeOrigin::Graph); } if (_callprojs.fallthrough_ioproj != nullptr) { migrate_outs(_callprojs.fallthrough_ioproj, i_o); - _igvn.remove_dead_node(_callprojs.fallthrough_ioproj); + _igvn.remove_dead_node(_callprojs.fallthrough_ioproj, PhaseIterGVN::NodeOrigin::Graph); } if (_callprojs.catchall_memproj != nullptr) { _igvn.rehash_node_delayed(_callprojs.catchall_memproj); @@ -1625,7 +1625,7 @@ void PhaseMacroExpand::yank_alloc_node(AllocateNode* alloc) { } } #endif - _igvn.remove_dead_node(alloc); + _igvn.remove_dead_node(alloc, PhaseIterGVN::NodeOrigin::Graph); } void PhaseMacroExpand::expand_initialize_membar(AllocateNode* alloc, InitializeNode* init, diff --git a/src/hotspot/share/opto/memnode.cpp b/src/hotspot/share/opto/memnode.cpp index 46f6729c82f..c8723d6ec0f 100644 --- a/src/hotspot/share/opto/memnode.cpp +++ b/src/hotspot/share/opto/memnode.cpp @@ -1889,7 +1889,7 @@ Node* LoadNode::split_through_phi(PhaseGVN* phase, bool ignore_missing_instance_ } } if (x != the_clone && the_clone != nullptr) { - igvn->remove_dead_node(the_clone); + igvn->remove_dead_node(the_clone, PhaseIterGVN::NodeOrigin::Speculative); } phi->set_req(i, x); } diff --git a/src/hotspot/share/opto/phaseX.cpp b/src/hotspot/share/opto/phaseX.cpp index 29961e152b3..06963eff4cf 100644 --- a/src/hotspot/share/opto/phaseX.cpp +++ b/src/hotspot/share/opto/phaseX.cpp @@ -575,7 +575,7 @@ PhaseValues::~PhaseValues() { _table.dump(); // Statistics for value progress and efficiency if( PrintCompilation && Verbose && WizardMode ) { - tty->print("\n%sValues: %d nodes ---> %d/%d (%d)", + tty->print("\n%sValues: %d nodes ---> " UINT64_FORMAT "/%d (%d)", is_IterGVN() ? "Iter" : " ", C->unique(), made_progress(), made_transforms(), made_new_values()); if( made_transforms() != 0 ) { tty->print_cr(" ratio %f", made_progress()/(float)made_transforms() ); @@ -731,14 +731,14 @@ Node* PhaseGVN::transform(Node* n) { } if (t->singleton() && !k->is_Con()) { - NOT_PRODUCT(set_progress();) + set_progress(); return makecon(t); // Turn into a constant } // Now check for Identities i = k->Identity(this); // Look for a nearby replacement if (i != k) { // Found? Return replacement! - NOT_PRODUCT(set_progress();) + set_progress(); return i; } @@ -746,7 +746,7 @@ Node* PhaseGVN::transform(Node* n) { i = hash_find_insert(k); // Insert if new if (i && (i != k)) { // Return the pre-existing node - NOT_PRODUCT(set_progress();) + set_progress(); return i; } @@ -977,7 +977,7 @@ void PhaseIterGVN::init_verifyPhaseIterGVN() { #endif } -void PhaseIterGVN::verify_PhaseIterGVN() { +void PhaseIterGVN::verify_PhaseIterGVN(bool deep_revisit_converged) { #ifdef ASSERT // Verify nodes with changed inputs. Unique_Node_List* modified_list = C->modified_nodes(); @@ -1010,7 +1010,7 @@ void PhaseIterGVN::verify_PhaseIterGVN() { } } - verify_optimize(); + verify_optimize(deep_revisit_converged); #endif } #endif /* PRODUCT */ @@ -1040,38 +1040,54 @@ void PhaseIterGVN::trace_PhaseIterGVN_verbose(Node* n, int num_processed) { } #endif /* ASSERT */ -void PhaseIterGVN::optimize() { - DEBUG_ONLY(uint num_processed = 0;) - NOT_PRODUCT(init_verifyPhaseIterGVN();) - NOT_PRODUCT(C->reset_igv_phase_iter(PHASE_AFTER_ITER_GVN_STEP);) - C->print_method(PHASE_BEFORE_ITER_GVN, 3); - if (StressIGVN) { - shuffle_worklist(); +bool PhaseIterGVN::needs_deep_revisit(const Node* n) const { + // LoadNode::Value() -> can_see_stored_value() walks up through many memory + // nodes. LoadNode::Ideal() -> find_previous_store() also walks up to 50 + // nodes through stores and arraycopy nodes. + if (n->is_Load()) { + return true; } + // CmpPNode::sub() -> detect_ptr_independence() -> all_controls_dominate() + // walks CFG dominator relationships extensively. This only triggers when + // both inputs are oop pointers (subnode.cpp:984). + if (n->Opcode() == Op_CmpP) { + const Type* t1 = type_or_null(n->in(1)); + const Type* t2 = type_or_null(n->in(2)); + return t1 != nullptr && t1->isa_oopptr() && + t2 != nullptr && t2->isa_oopptr(); + } + // IfNode::Ideal() -> search_identical() walks up the CFG dominator tree. + // RangeCheckNode::Ideal() scans up to ~999 nodes up the chain. + // CountedLoopEndNode/LongCountedLoopEndNode::Ideal() via simple_subsuming + // looks for dominating test that subsumes the current test. + switch (n->Opcode()) { + case Op_If: + case Op_RangeCheck: + case Op_CountedLoopEnd: + case Op_LongCountedLoopEnd: + return true; + default: + break; + } + return false; +} - // The node count check in the loop below (check_node_count) assumes that we - // increase the live node count with at most - // max_live_nodes_increase_per_iteration in between checks. If this - // assumption does not hold, there is a risk that we exceed the max node - // limit in between checks and trigger an assert during node creation. +bool PhaseIterGVN::drain_worklist() { + uint loop_count = 1; const int max_live_nodes_increase_per_iteration = NodeLimitFudgeFactor * 3; - - uint loop_count = 0; - // Pull from worklist and transform the node. If the node has changed, - // update edge info and put uses on worklist. - while (_worklist.size() > 0) { + while (_worklist.size() != 0) { if (C->check_node_count(max_live_nodes_increase_per_iteration, "Out of nodes")) { C->print_method(PHASE_AFTER_ITER_GVN, 3); - return; + return true; } Node* n = _worklist.pop(); if (loop_count >= K * C->live_nodes()) { - DEBUG_ONLY(dump_infinite_loop_info(n, "PhaseIterGVN::optimize");) - C->record_method_not_compilable("infinite loop in PhaseIterGVN::optimize"); + DEBUG_ONLY(dump_infinite_loop_info(n, "PhaseIterGVN::drain_worklist");) + C->record_method_not_compilable("infinite loop in PhaseIterGVN::drain_worklist"); C->print_method(PHASE_AFTER_ITER_GVN, 3); - return; + return true; } - DEBUG_ONLY(trace_PhaseIterGVN_verbose(n, num_processed++);) + DEBUG_ONLY(trace_PhaseIterGVN_verbose(n, _num_processed++);) if (n->outcnt() != 0) { NOT_PRODUCT(const Type* oldtype = type_or_null(n)); // Do the transformation @@ -1079,7 +1095,7 @@ void PhaseIterGVN::optimize() { Node* nn = transform_old(n); DEBUG_ONLY(int live_nodes_after = C->live_nodes();) // Ensure we did not increase the live node count with more than - // max_live_nodes_increase_per_iteration during the call to transform_old + // max_live_nodes_increase_per_iteration during the call to transform_old. DEBUG_ONLY(int increase = live_nodes_after - live_nodes_before;) assert(increase < max_live_nodes_increase_per_iteration, "excessive live node increase in single iteration of IGVN: %d " @@ -1087,16 +1103,115 @@ void PhaseIterGVN::optimize() { increase, max_live_nodes_increase_per_iteration); NOT_PRODUCT(trace_PhaseIterGVN(n, nn, oldtype);) } else if (!n->is_top()) { - remove_dead_node(n); + remove_dead_node(n, NodeOrigin::Graph); } loop_count++; } - NOT_PRODUCT(verify_PhaseIterGVN();) + return false; +} + +void PhaseIterGVN::push_deep_revisit_candidates() { + ResourceMark rm; + Unique_Node_List all_nodes; + all_nodes.push(C->root()); + for (uint j = 0; j < all_nodes.size(); j++) { + Node* n = all_nodes.at(j); + if (needs_deep_revisit(n)) { + _worklist.push(n); + } + for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { + all_nodes.push(n->fast_out(i)); + } + } +} + +bool PhaseIterGVN::deep_revisit() { + // Re-process nodes that inspect the graph deeply. After the main worklist drains, walk + // the graph to find all live deep-inspection nodes and push them to the worklist + // for re-evaluation. If any produce changes, drain the worklist again. + // Repeat until stable. This mirrors PhaseCCP::analyze()'s revisit loop. + const uint max_deep_revisit_rounds = 10; // typically converges in <2 rounds + uint round = 0; + for (; round < max_deep_revisit_rounds; round++) { + push_deep_revisit_candidates(); + if (_worklist.size() == 0) { + break; // No deep-inspection nodes to revisit, done. + } + +#ifndef PRODUCT + uint candidates = _worklist.size(); + uint n_if = 0; uint n_rc = 0; uint n_load = 0; uint n_cmpp = 0; uint n_cle = 0; uint n_lcle = 0; + if (TraceIterativeGVN) { + for (uint i = 0; i < _worklist.size(); i++) { + Node* n = _worklist.at(i); + switch (n->Opcode()) { + case Op_If: n_if++; break; + case Op_RangeCheck: n_rc++; break; + case Op_CountedLoopEnd: n_cle++; break; + case Op_LongCountedLoopEnd: n_lcle++; break; + case Op_CmpP: n_cmpp++; break; + default: if (n->is_Load()) n_load++; break; + } + } + } +#endif + + // Convergence: if the drain does not make progress (no Ideal, Value, Identity or GVN changes), + // we are at a fixed point. We use made_progress() rather than live_nodes because live_nodes + // misses non-structural changes like a LoadNode dropping its control input. + uint progress_before = made_progress(); + if (drain_worklist()) { + return false; + } + uint progress = made_progress() - progress_before; + +#ifndef PRODUCT + if (TraceIterativeGVN) { + tty->print("deep_revisit round %u: %u candidates (If=%u RC=%u Load=%u CmpP=%u CLE=%u LCLE=%u), progress=%u (%s)", + round, candidates, n_if, n_rc, n_load, n_cmpp, n_cle, n_lcle, progress, progress != 0 ? "changed" : "converged"); + if (C->method() != nullptr) { + tty->print(", "); + C->method()->print_short_name(tty); + } + tty->cr(); + } +#endif + + if (progress == 0) { + break; + } + } + return round < max_deep_revisit_rounds; +} + +void PhaseIterGVN::optimize(bool deep) { + bool deep_revisit_converged = false; + DEBUG_ONLY(_num_processed = 0;) + NOT_PRODUCT(init_verifyPhaseIterGVN();) + NOT_PRODUCT(C->reset_igv_phase_iter(PHASE_AFTER_ITER_GVN_STEP);) + C->print_method(PHASE_BEFORE_ITER_GVN, 3); + if (StressIGVN) { + shuffle_worklist(); + } + + // Pull from worklist and transform the node. + if (drain_worklist()) { + return; + } + + if (deep && UseDeepIGVNRevisit) { + deep_revisit_converged = deep_revisit(); + if (C->failing()) { + return; + } + } + + NOT_PRODUCT(verify_PhaseIterGVN(deep_revisit_converged);) C->print_method(PHASE_AFTER_ITER_GVN, 3); } #ifdef ASSERT -void PhaseIterGVN::verify_optimize() { +void PhaseIterGVN::verify_optimize(bool deep_revisit_converged) { assert(_worklist.size() == 0, "igvn worklist must be empty before verify"); if (is_verify_Value() || @@ -1114,11 +1229,11 @@ void PhaseIterGVN::verify_optimize() { // in PhaseIterGVN::add_users_to_worklist to update it again or add an exception // in the verification methods below if that is not possible for some reason (like Load nodes). if (is_verify_Value()) { - verify_Value_for(n); + verify_Value_for(n, deep_revisit_converged /* strict */); } if (is_verify_Ideal()) { - verify_Ideal_for(n, false); - verify_Ideal_for(n, true); + verify_Ideal_for(n, false /* can_reshape */, deep_revisit_converged); + verify_Ideal_for(n, true /* can_reshape */, deep_revisit_converged); } if (is_verify_Identity()) { verify_Identity_for(n); @@ -1240,52 +1355,15 @@ void PhaseIterGVN::verify_Value_for(const Node* n, bool strict) { // Check that all Ideal optimizations that could be done were done. // Asserts if it found missed optimization opportunities or encountered unexpected changes, and // returns normally otherwise (no missed optimization, or skipped verification). -void PhaseIterGVN::verify_Ideal_for(Node* n, bool can_reshape) { +void PhaseIterGVN::verify_Ideal_for(Node* n, bool can_reshape, bool deep_revisit_converged) { + if (!deep_revisit_converged && needs_deep_revisit(n)) { + return; + } + // First, we check a list of exceptions, where we skip verification, // because there are known cases where Ideal can optimize after IGVN. // Some may be expected and cannot be fixed, and others should be fixed. switch (n->Opcode()) { - // RangeCheckNode::Ideal looks up the chain for about 999 nodes - // (see "Range-Check scan limit"). So, it is possible that something - // is optimized in that input subgraph, and the RangeCheck was not - // added to the worklist because it would be too expensive to walk - // down the graph for 1000 nodes and put all on the worklist. - // - // Found with: - // java -XX:VerifyIterativeGVN=0100 -Xbatch --version - case Op_RangeCheck: - return; - - // IfNode::Ideal does: - // Node* prev_dom = search_identical(dist, igvn); - // which means we seach up the CFG, traversing at most up to a distance. - // If anything happens rather far away from the If, we may not put the If - // back on the worklist. - // - // Found with: - // java -XX:VerifyIterativeGVN=0100 -Xcomp --version - case Op_If: - return; - - // IfNode::simple_subsuming - // Looks for dominating test that subsumes the current test. - // Notification could be difficult because of larger distance. - // - // Found with: - // runtime/exceptionMsgs/ArrayIndexOutOfBoundsException/ArrayIndexOutOfBoundsExceptionTest.java#id1 - // -XX:VerifyIterativeGVN=1110 - case Op_CountedLoopEnd: - return; - - // LongCountedLoopEndNode::Ideal - // Probably same issue as above. - // - // Found with: - // compiler/predicates/assertion/TestAssertionPredicates.java#NoLoopPredicationXbatch - // -XX:StressLongCountedLoop=2000000 -XX:+IgnoreUnrecognizedVMOptions -XX:VerifyIterativeGVN=1110 - case Op_LongCountedLoopEnd: - return; - // RegionNode::Ideal does "Skip around the useless IF diamond". // 245 IfTrue === 244 // 258 If === 245 257 @@ -1757,22 +1835,6 @@ void PhaseIterGVN::verify_Ideal_for(Node* n, bool can_reshape) { return; } - if (n->is_Load()) { - // LoadNode::Ideal uses tries to find an earlier memory state, and - // checks can_see_stored_value for it. - // - // Investigate why this was not already done during IGVN. - // A similar issue happens with Identity. - // - // There seem to be other cases where loads go up some steps, like - // LoadNode::Ideal going up 10x steps to find dominating load. - // - // Found with: - // test/hotspot/jtreg/compiler/arraycopy/TestCloneAccess.java - // -XX:VerifyIterativeGVN=1110 - return; - } - if (n->is_Store()) { // StoreNode::Ideal can do this: // // Capture an unaliased, unconditional, simple store into an initializer. @@ -1857,8 +1919,16 @@ void PhaseIterGVN::verify_Ideal_for(Node* n, bool can_reshape) { return; } - // The number of nodes shoud not increase. - uint old_unique = C->unique(); + // Ideal should not make progress if it returns nullptr. + // We use made_progress() rather than unique() or live_nodes() because some + // Ideal implementations speculatively create nodes and kill them before + // returning nullptr (e.g. split_if clones a Cmp to check is_canonical). + // unique() is a high-water mark that is not decremented by remove_dead_node, + // so it would cause false-positives. live_nodes() accounts for dead nodes but can + // decrease when Ideal removes existing nodes as side effects. + // made_progress() precisely tracks meaningful transforms, and speculative + // work killed via NodeOrigin::Speculative does not increment it. + uint old_progress = made_progress(); // The hash of a node should not change, this would indicate different inputs uint old_hash = n->hash(); // Remove 'n' from hash table in case it gets modified. We want to avoid @@ -1870,14 +1940,15 @@ void PhaseIterGVN::verify_Ideal_for(Node* n, bool can_reshape) { Node* i = n->Ideal(this, can_reshape); // If there was no new Idealization, we are probably happy. if (i == nullptr) { - if (old_unique < C->unique()) { + uint progress = made_progress() - old_progress; + if (progress != 0) { stringStream ss; // Print as a block without tty lock. ss.cr(); - ss.print_cr("Ideal optimization did not make progress but created new unused nodes."); - ss.print_cr(" old_unique = %d, unique = %d", old_unique, C->unique()); + ss.print_cr("Ideal optimization did not make progress but had side effects."); + ss.print_cr(" %u transforms made progress", progress); n->dump_bfs(1, nullptr, "", &ss); tty->print_cr("%s", ss.as_string()); - assert(false, "Unexpected new unused nodes from applying Ideal optimization on %s", n->Name()); + assert(false, "Unexpected side effects from applying Ideal optimization on %s", n->Name()); } if (old_hash != n->hash()) { @@ -2152,6 +2223,9 @@ Node *PhaseIterGVN::transform_old(Node* n) { #endif DEBUG_ONLY(uint loop_count = 1;) + if (i != nullptr) { + set_progress(); + } while (i != nullptr) { #ifdef ASSERT if (loop_count >= K + C->live_nodes()) { @@ -2197,10 +2271,8 @@ Node *PhaseIterGVN::transform_old(Node* n) { // cache Value. Later requests for the local phase->type of this Node can // use the cached Value instead of suffering with 'bottom_type'. if (type_or_null(k) != t) { -#ifndef PRODUCT - inc_new_values(); + NOT_PRODUCT(inc_new_values();) set_progress(); -#endif set_type(k, t); // If k is a TypeNode, capture any more-precise type permanently into Node k->raise_bottom_type(t); @@ -2209,7 +2281,7 @@ Node *PhaseIterGVN::transform_old(Node* n) { } // If 'k' computes a constant, replace it with a constant if (t->singleton() && !k->is_Con()) { - NOT_PRODUCT(set_progress();) + set_progress(); Node* con = makecon(t); // Make a constant add_users_to_worklist(k); subsume_node(k, con); // Everybody using k now uses con @@ -2219,7 +2291,7 @@ Node *PhaseIterGVN::transform_old(Node* n) { // Now check for Identities i = k->Identity(this); // Look for a nearby replacement if (i != k) { // Found? Return replacement! - NOT_PRODUCT(set_progress();) + set_progress(); add_users_to_worklist(k); subsume_node(k, i); // Everybody using k now uses i return i; @@ -2229,7 +2301,7 @@ Node *PhaseIterGVN::transform_old(Node* n) { i = hash_find_insert(k); // Check for pre-existing node if (i && (i != k)) { // Return the pre-existing node if it isn't dead - NOT_PRODUCT(set_progress();) + set_progress(); add_users_to_worklist(k); subsume_node(k, i); // Everybody using k now uses i return i; @@ -2248,7 +2320,7 @@ const Type* PhaseIterGVN::saturate(const Type* new_type, const Type* old_type, //------------------------------remove_globally_dead_node---------------------- // Kill a globally dead Node. All uses are also globally dead and are // aggressively trimmed. -void PhaseIterGVN::remove_globally_dead_node( Node *dead ) { +void PhaseIterGVN::remove_globally_dead_node(Node* dead, NodeOrigin origin) { enum DeleteProgress { PROCESS_INPUTS, PROCESS_OUTPUTS @@ -2265,11 +2337,13 @@ void PhaseIterGVN::remove_globally_dead_node( Node *dead ) { uint progress_state = stack.index(); assert(dead != C->root(), "killing root, eh?"); assert(!dead->is_top(), "add check for top when pushing"); - NOT_PRODUCT( set_progress(); ) if (progress_state == PROCESS_INPUTS) { // After following inputs, continue to outputs stack.set_index(PROCESS_OUTPUTS); if (!dead->is_Con()) { // Don't kill cons but uses + if (origin != NodeOrigin::Speculative) { + set_progress(); + } bool recurse = false; // Remove from hash table _table.hash_delete( dead ); @@ -2379,7 +2453,7 @@ void PhaseIterGVN::subsume_node( Node *old, Node *nn ) { // Smash all inputs to 'old', isolating him completely Node *temp = new Node(1); temp->init_req(0,nn); // Add a use to nn to prevent him from dying - remove_dead_node( old ); + remove_dead_node(old, NodeOrigin::Graph); temp->del_req(0); // Yank bogus edge if (nn != nullptr && nn->outcnt() == 0) { _worklist.push(nn); diff --git a/src/hotspot/share/opto/phaseX.hpp b/src/hotspot/share/opto/phaseX.hpp index 94890c250c4..cef273ff3df 100644 --- a/src/hotspot/share/opto/phaseX.hpp +++ b/src/hotspot/share/opto/phaseX.hpp @@ -187,8 +187,8 @@ public: class PhaseTransform : public Phase { public: PhaseTransform(PhaseNumber pnum) : Phase(pnum) { -#ifndef PRODUCT clear_progress(); +#ifndef PRODUCT clear_transforms(); set_allow_progress(true); #endif @@ -201,12 +201,31 @@ public: // true if CFG node d dominates CFG node n virtual bool is_dominator(Node *d, Node *n) { fatal("unimplemented for this pass"); return false; }; -#ifndef PRODUCT - uint _count_progress; // For profiling, count transforms that make progress - void set_progress() { ++_count_progress; assert( allow_progress(),"No progress allowed during verification"); } - void clear_progress() { _count_progress = 0; } - uint made_progress() const { return _count_progress; } + uint64_t _count_progress; // Count transforms that make progress + void set_progress() { ++_count_progress; assert(allow_progress(), "No progress allowed during verification"); } + void clear_progress() { _count_progress = 0; } + uint64_t made_progress() const { return _count_progress; } + // RAII guard for speculative transforms. Restores _count_progress in the destructor + // unless commit() is called, so that abandoned speculative work does not count as progress. + // In case multiple nodes are created and only some are speculative, commit() should still be called. + class SpeculativeProgressGuard { + PhaseTransform* _phase; + uint64_t _saved_progress; + bool _committed; + public: + SpeculativeProgressGuard(PhaseTransform* phase) : + _phase(phase), _saved_progress(phase->made_progress()), _committed(false) {} + ~SpeculativeProgressGuard() { + if (!_committed) { + _phase->_count_progress = _saved_progress; + } + } + + void commit() { _committed = true; } + }; + +#ifndef PRODUCT uint _count_transforms; // For profiling, count transforms performed void set_transforms() { ++_count_transforms; } void clear_transforms() { _count_transforms = 0; } @@ -446,10 +465,30 @@ class PhaseIterGVN : public PhaseGVN { private: bool _delay_transform; // When true simply register the node when calling transform // instead of actually optimizing it + DEBUG_ONLY(uint _num_processed;) // Running count for trace_PhaseIterGVN_verbose // Idealize old Node 'n' with respect to its inputs and its value virtual Node *transform_old( Node *a_node ); + // Drain the IGVN worklist: process nodes until the worklist is empty. + // Returns true if compilation was aborted (node limit or infinite loop), + // false on normal completion. + bool drain_worklist(); + + // Walk all live nodes and push deep-inspection candidates to _worklist. + void push_deep_revisit_candidates(); + + // After the main worklist drains, re-process deep-inspection nodes to + // catch optimization opportunities from far-away changes. Repeats until + // convergence (no progress made) or max rounds reached. + // Returns true if converged. + bool deep_revisit(); + + // Returns true for nodes that inspect the graph beyond their direct + // inputs, and therefore may miss optimization opportunities when + // changes happen far away. + bool needs_deep_revisit(const Node* n) const; + // Subsume users of node 'old' into node 'nn' void subsume_node( Node *old, Node *nn ); @@ -493,11 +532,16 @@ public: // Given def-use info and an initial worklist, apply Node::Ideal, // Node::Value, Node::Identity, hash-based value numbering, Node::Ideal_DU // and dominator info to a fixed point. - void optimize(); + // When deep is true, after the main worklist drains, re-process + // nodes that inspect the graph deeply (Load, CmpP, If, RangeCheck, + // CountedLoopEnd, LongCountedLoopEnd) to catch optimization opportunities + // from changes far away that the normal notification mechanism misses. + void optimize(bool deep = false); + #ifdef ASSERT - void verify_optimize(); + void verify_optimize(bool deep_revisit_converged); void verify_Value_for(const Node* n, bool strict = false); - void verify_Ideal_for(Node* n, bool can_reshape); + void verify_Ideal_for(Node* n, bool can_reshape, bool deep_revisit_converged); void verify_Identity_for(Node* n); void verify_node_invariants_for(const Node* n); void verify_empty_worklist(Node* n); @@ -506,7 +550,7 @@ public: #ifndef PRODUCT void trace_PhaseIterGVN(Node* n, Node* nn, const Type* old_type); void init_verifyPhaseIterGVN(); - void verify_PhaseIterGVN(); + void verify_PhaseIterGVN(bool deep_revisit_converged); #endif #ifdef ASSERT @@ -522,15 +566,21 @@ public: // It is significant only for debugging and profiling. Node* register_new_node_with_optimizer(Node* n, Node* orig = nullptr); - // Kill a globally dead Node. All uses are also globally dead and are + // Origin of a dead node, describing why it is dying. + // Speculative: a temporarily created node that was never part of the graph + // (e.g., a speculative clone in split_if to test constant foldability). + // Its death does not count as progress for convergence tracking. + enum class NodeOrigin { Graph, Speculative }; + + // Kill a globally dead Node. All uses are also globally dead and are // aggressively trimmed. - void remove_globally_dead_node( Node *dead ); + void remove_globally_dead_node(Node* dead, NodeOrigin origin); // Kill all inputs to a dead node, recursively making more dead nodes. // The Node must be dead locally, i.e., have no uses. - void remove_dead_node( Node *dead ) { + void remove_dead_node(Node* dead, NodeOrigin origin) { assert(dead->outcnt() == 0 && !dead->is_top(), "node must be dead"); - remove_globally_dead_node(dead); + remove_globally_dead_node(dead, origin); } // Add users of 'n' to worklist diff --git a/src/hotspot/share/opto/split_if.cpp b/src/hotspot/share/opto/split_if.cpp index 91595c57a10..c1303f0d0db 100644 --- a/src/hotspot/share/opto/split_if.cpp +++ b/src/hotspot/share/opto/split_if.cpp @@ -85,7 +85,7 @@ bool PhaseIdealLoop::split_up( Node *n, Node *blk1, Node *blk2 ) { if( split_up( n->in(i), blk1, blk2 ) ) { // Got split recursively and self went dead? if (n->outcnt() == 0) - _igvn.remove_dead_node(n); + _igvn.remove_dead_node(n, PhaseIterGVN::NodeOrigin::Graph); return true; } } @@ -273,7 +273,7 @@ void PhaseIdealLoop::clone_loadklass_nodes_at_cmp_index(const Node* n, Node* cmp _igvn.replace_input_of(decode_clone, 1, loadklass_clone); _igvn.replace_input_of(loadklass_clone, MemNode::Address, addp_clone); if (decode->outcnt() == 0) { - _igvn.remove_dead_node(decode); + _igvn.remove_dead_node(decode, PhaseIterGVN::NodeOrigin::Graph); } } } @@ -290,7 +290,7 @@ void PhaseIdealLoop::clone_loadklass_nodes_at_cmp_index(const Node* n, Node* cmp _igvn.replace_input_of(cmp, i, loadklass_clone); _igvn.replace_input_of(loadklass_clone, MemNode::Address, addp_clone); if (loadklass->outcnt() == 0) { - _igvn.remove_dead_node(loadklass); + _igvn.remove_dead_node(loadklass, PhaseIterGVN::NodeOrigin::Graph); } } } @@ -369,7 +369,7 @@ bool PhaseIdealLoop::clone_cmp_down(Node* n, const Node* blk1, const Node* blk2) _igvn.replace_input_of(x2, 1, x1); _igvn.replace_input_of(iff, 1, x2); } - _igvn.remove_dead_node(u); + _igvn.remove_dead_node(u, PhaseIterGVN::NodeOrigin::Graph); --j; } else { // We might see an Opaque1 from a loop limit check here @@ -385,7 +385,7 @@ bool PhaseIdealLoop::clone_cmp_down(Node* n, const Node* blk1, const Node* blk2) --j; } } - _igvn.remove_dead_node(bol); + _igvn.remove_dead_node(bol, PhaseIterGVN::NodeOrigin::Graph); --i; } } @@ -403,7 +403,7 @@ bool PhaseIdealLoop::clone_cmp_down(Node* n, const Node* blk1, const Node* blk2) register_new_node(x, ctrl_or_self(use)); _igvn.replace_input_of(use, pos, x); } - _igvn.remove_dead_node(n); + _igvn.remove_dead_node(n, PhaseIterGVN::NodeOrigin::Graph); return true; } @@ -517,7 +517,7 @@ Node *PhaseIdealLoop::spinup( Node *iff_dom, Node *new_false, Node *new_true, No Node *t = _igvn.hash_find_insert(phi_post); if( t ) { // See if we already have this one // phi_post will not be used, so kill it - _igvn.remove_dead_node(phi_post); + _igvn.remove_dead_node(phi_post, PhaseIterGVN::NodeOrigin::Speculative); phi_post->destruct(&_igvn); phi_post = t; } else { @@ -647,7 +647,7 @@ void PhaseIdealLoop::do_split_if(Node* iff, RegionNode** new_false_region, Regio Node* m = n->out(j); // If m is dead, throw it away, and declare progress if (_loop_or_ctrl[m->_idx] == nullptr) { - _igvn.remove_dead_node(m); + _igvn.remove_dead_node(m, PhaseIterGVN::NodeOrigin::Graph); // fall through } else if (m != iff && split_up(m, region, iff)) { @@ -704,7 +704,7 @@ void PhaseIdealLoop::do_split_if(Node* iff, RegionNode** new_false_region, Regio new_true = ifpx; } } - _igvn.remove_dead_node(new_iff); + _igvn.remove_dead_node(new_iff, PhaseIterGVN::NodeOrigin::Speculative); // Lazy replace IDOM info with the region's dominator replace_node_and_forward_ctrl(iff, region_dom); // Break the self-cycle. Required for forward_ctrl to work on region. @@ -720,7 +720,7 @@ void PhaseIdealLoop::do_split_if(Node* iff, RegionNode** new_false_region, Regio for (DUIterator k = region->outs(); region->has_out(k); k++) { Node* phi = region->out(k); if (!phi->in(0)) { // Dead phi? Remove it - _igvn.remove_dead_node(phi); + _igvn.remove_dead_node(phi, PhaseIterGVN::NodeOrigin::Graph); } else if (phi == region) { // Found the self-reference continue; // No roll-back of DUIterator } else if (phi->is_Phi()) { // Expected common case: Phi hanging off of Region @@ -739,7 +739,7 @@ void PhaseIdealLoop::do_split_if(Node* iff, RegionNode** new_false_region, Regio handle_use(use, phi, &phi_cache, region_dom, new_false, new_true, old_false, old_true); } // End of while phi has uses // Remove the dead Phi - _igvn.remove_dead_node( phi ); + _igvn.remove_dead_node(phi, PhaseIterGVN::NodeOrigin::Graph); } else { assert(phi->in(0) == region, "Inconsistent graph"); // Random memory op guarded by Region. Compute new DEF for USE. @@ -752,7 +752,7 @@ void PhaseIdealLoop::do_split_if(Node* iff, RegionNode** new_false_region, Regio --k; } // End of while merge point has phis - _igvn.remove_dead_node(region); + _igvn.remove_dead_node(region, PhaseIterGVN::NodeOrigin::Graph); // Control is updated here to a region, which is not a test, so any node that // depends_only_on_test must be pinned diff --git a/test/hotspot/jtreg/compiler/arraycopy/TestCloneAccess.java b/test/hotspot/jtreg/compiler/arraycopy/TestCloneAccess.java index a0da0741cad..22bf1f88ae7 100644 --- a/test/hotspot/jtreg/compiler/arraycopy/TestCloneAccess.java +++ b/test/hotspot/jtreg/compiler/arraycopy/TestCloneAccess.java @@ -23,16 +23,18 @@ /* * @test - * @bug 8248791 + * @bug 8248791 8375442 * @summary Test cloning with more than 8 (=ArrayCopyLoadStoreMaxElem) where loads are wrongly replaced by zero. * @requires vm.compiler2.enabled | vm.graal.enabled * * @run main/othervm -XX:-ReduceBulkZeroing - * -XX:CompileCommand=dontinline,compiler.arraycopy.TestCloneAccess::* - * compiler.arraycopy.TestCloneAccess + * -XX:CompileCommand=dontinline,${test.main.class}::* + * ${test.main.class} * @run main/othervm -XX:-ReduceBulkZeroing -XX:-ReduceInitialCardMarks - * -XX:CompileCommand=dontinline,compiler.arraycopy.TestCloneAccess::* - * compiler.arraycopy.TestCloneAccess + * -XX:CompileCommand=dontinline,${test.main.class}::* + * ${test.main.class} + * @run main/othervm -XX:-ReduceBulkZeroing -XX:+IgnoreUnrecognizedVMOptions -XX:VerifyIterativeGVN=1110 + * ${test.main.class} */ package compiler.arraycopy; diff --git a/test/hotspot/jtreg/compiler/c2/igvn/TestDeepIGVNRevisit.java b/test/hotspot/jtreg/compiler/c2/igvn/TestDeepIGVNRevisit.java new file mode 100644 index 00000000000..228357f953d --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/igvn/TestDeepIGVNRevisit.java @@ -0,0 +1,83 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package compiler.c2.igvn; + +import compiler.lib.ir_framework.*; + +/* + * @test + * @bug 8375442 + * @summary Test deep IGVN revisit for RangeCheck elimination. Other deep-revisit node types + * (If, Load, CmpP, CountedLoopEnd, LongCountedLoopEnd) benefit in large methods + * but require graph complexity beyond this test. + * @library /test/lib / + * @run driver ${test.main.class} + */ +public class TestDeepIGVNRevisit { + static boolean c1, c2, c3, c4; + static volatile int volatileField; + + public static void main(String[] args) { + TestFramework tf = new TestFramework(); + tf.setDefaultWarmup(0); + tf.addFlags("-XX:+IgnoreUnrecognizedVMOptions", + "-XX:+AlwaysIncrementalInline", + "-XX:-PartialPeelLoop", + "-XX:-LoopUnswitching"); + tf.addScenarios( + new Scenario(1, "-XX:-StressIGVN", "-XX:+UseDeepIGVNRevisit"), + new Scenario(2, "-XX:+StressIGVN", "-XX:+UseDeepIGVNRevisit"), + new Scenario(3, "-XX:-StressIGVN", "-XX:-UseDeepIGVNRevisit"), + new Scenario(4, "-XX:+StressIGVN", "-XX:-UseDeepIGVNRevisit")); + tf.start(); + } + + static void lateInline() {} + + // Deferred calls create separate LoadRange nodes for the two arr[idx] + // accesses. After inlining, LoadRanges CSE but RangeCheck#2 is already + // processed. Deep revisit re-processes it with matching range pointers. + @Setup + static Object[] setupRangeCheck() { + return new Object[] { new int[100], 42 }; + } + + @Test + @Arguments(setup = "setupRangeCheck") + @IR(phase = CompilePhase.ITER_GVN2, + applyIf = {"UseDeepIGVNRevisit", "true"}, + counts = {IRNode.RANGE_CHECK, "1"}) + @IR(phase = CompilePhase.ITER_GVN2, + applyIf = {"UseDeepIGVNRevisit", "false"}, + counts = {IRNode.RANGE_CHECK, "2"}) + static int testRangeCheck(int[] arr, int idx) { + int r = arr[idx]; // RangeCheck #1 + if (c1) { lateInline(); } + if (c2) { lateInline(); } + if (c3) { lateInline(); } + if (c4) { lateInline(); } + volatileField = r; + r += arr[idx]; // RangeCheck #2 + return r; + } +} diff --git a/test/hotspot/jtreg/compiler/igvn/TestFoldComparesCleanup.java b/test/hotspot/jtreg/compiler/igvn/TestFoldComparesCleanup.java new file mode 100644 index 00000000000..bcc3b9541ba --- /dev/null +++ b/test/hotspot/jtreg/compiler/igvn/TestFoldComparesCleanup.java @@ -0,0 +1,56 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8375442 + * @summary fold_compares_helper must clean up speculative lo node when bailing out with deep revisit + * @library /test/lib / + * @run main/othervm -XX:-TieredCompilation -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:VerifyIterativeGVN=1110 + * -XX:CompileCommand=compileonly,${test.main.class}::test + * ${test.main.class} + * + * @run main ${test.main.class} + */ +package compiler.igvn; + +import jdk.test.lib.Asserts; + +public class TestFoldComparesCleanup { + // Constants chosen so that fold_compares_helper computes adjusted_lim which overflows negative. + static final int A = -2_000_000_000; + static final int B = 2_000_000_000; + + static int test(int z) { + int sum = 0; + if (z > A) sum += 1; + if (z < B) sum += 2; + return sum; + } + + public static void main(String[] args) { + for (int i = 0; i < 50_000; i++) { + Asserts.assertEquals(3, test(i)); + } + } +} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java index 0753a0b04bc..0e1accf8a50 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java @@ -1776,6 +1776,11 @@ public class IRNode { trapNodes(PREDICATE_TRAP, "predicate"); } + public static final String RANGE_CHECK = PREFIX + "RANGE_CHECK" + POSTFIX; + static { + beforeMatchingNameRegex(RANGE_CHECK, "RangeCheck"); + } + public static final String RANGE_CHECK_TRAP = PREFIX + "RANGE_CHECK_TRAP" + POSTFIX; static { trapNodes(RANGE_CHECK_TRAP, "range_check"); From c76381996a9f2c90213ed8d5f84526c82fe07a67 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Wed, 1 Apr 2026 00:29:44 +0000 Subject: [PATCH 132/359] 8381384: jpackage: add test coverage to WiX discovery Reviewed-by: almatvee --- .../internal/EnvironmentProvider.java | 45 ++ .../jdk/jpackage/internal/Globals.java | 8 + .../jdk/jpackage/internal/util/PathUtils.java | 33 +- .../jdk/jpackage/internal/WixTool.java | 284 +++---- .../jdk/jpackage/internal/WixToolset.java | 29 +- .../resources/WinResources.properties | 5 +- .../test/mock/MockingToolProvider.java | 2 +- .../test/stdmock/EnvironmentProviderMock.java | 64 ++ .../jpackage/test/stdmock/WixToolMock.java | 173 ++++ .../jpackage/internal/util/PathUtilsTest.java | 213 +++++ .../jdk/jpackage/internal/WixToolTest.java | 754 ++++++++++++++++++ .../tools/jpackage/junit/windows/junit.java | 12 + 12 files changed, 1459 insertions(+), 163 deletions(-) create mode 100644 src/jdk.jpackage/share/classes/jdk/jpackage/internal/EnvironmentProvider.java create mode 100644 test/jdk/tools/jpackage/helpers/jdk/jpackage/test/stdmock/EnvironmentProviderMock.java create mode 100644 test/jdk/tools/jpackage/helpers/jdk/jpackage/test/stdmock/WixToolMock.java create mode 100644 test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/PathUtilsTest.java create mode 100644 test/jdk/tools/jpackage/junit/windows/jdk.jpackage/jdk/jpackage/internal/WixToolTest.java diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/EnvironmentProvider.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/EnvironmentProvider.java new file mode 100644 index 00000000000..de364129256 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/EnvironmentProvider.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal; + +public interface EnvironmentProvider { + + String getProperty(String propertyName); + + String getenv(String envVarName); + + public static EnvironmentProvider DEFAULT = new EnvironmentProvider() { + + @Override + public String getenv(String envVarName) { + return System.getenv(envVarName); + } + + @Override + public String getProperty(String propertyName) { + return System.getProperty(propertyName); + } + }; +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Globals.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Globals.java index 0128d050c25..2fc0046fad5 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Globals.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Globals.java @@ -65,6 +65,14 @@ public final class Globals { return this; } + public EnvironmentProvider system() { + return this.findProperty(EnvironmentProvider.class).orElse(EnvironmentProvider.DEFAULT); + } + + public Globals system(EnvironmentProvider v) { + return setProperty(EnvironmentProvider.class, v); + } + Log.Logger logger() { return logger; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathUtils.java index a8944a67ae0..707dd2784ce 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathUtils.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PathUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ */ package jdk.jpackage.internal.util; +import java.nio.file.InvalidPathException; import java.nio.file.Path; import java.util.Objects; import java.util.Optional; @@ -31,18 +32,26 @@ import java.util.function.UnaryOperator; public final class PathUtils { + private PathUtils() { + } + public static String getSuffix(Path path) { String filename = replaceSuffix(path.getFileName(), null).toString(); return path.getFileName().toString().substring(filename.length()); } public static Path addSuffix(Path path, String suffix) { + Objects.requireNonNull(path); + Objects.requireNonNull(suffix); + Path parent = path.getParent(); String filename = path.getFileName().toString() + suffix; return parent != null ? parent.resolve(filename) : Path.of(filename); } public static Path replaceSuffix(Path path, String suffix) { + Objects.requireNonNull(path); + Path parent = path.getParent(); String filename = path.getFileName().toString().replaceAll("\\.[^.]*$", "") + Optional.ofNullable(suffix).orElse(""); @@ -59,18 +68,22 @@ public final class PathUtils { } public static Path normalizedAbsolutePath(Path path) { - if (path != null) { + return mapNullablePath(_ -> { return path.normalize().toAbsolutePath(); - } else { - return null; - } + }, path); } public static String normalizedAbsolutePathString(Path path) { - if (path != null) { - return normalizedAbsolutePath(path).toString(); - } else { - return null; - } + return Optional.ofNullable(normalizedAbsolutePath(path)).map(Path::toString).orElse(null); + } + + public static Optional asPath(String value) { + return Optional.ofNullable(value).map(v -> { + try { + return Path.of(v); + } catch (InvalidPathException ex) { + return null; + } + }); } } 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 c4f8610312a..d0c5e6ca3b0 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixTool.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixTool.java @@ -23,14 +23,14 @@ * questions. */ package jdk.jpackage.internal; +import static java.util.stream.Collectors.groupingBy; +import static java.util.stream.Collectors.toMap; +import static java.util.stream.Collectors.toSet; import java.io.IOException; import java.nio.file.FileSystems; import java.nio.file.Files; -import java.nio.file.InvalidPathException; import java.nio.file.Path; -import java.nio.file.PathMatcher; -import java.text.MessageFormat; import java.util.Comparator; import java.util.List; import java.util.Map; @@ -38,12 +38,13 @@ import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.function.Function; -import java.util.stream.Collectors; +import java.util.function.Supplier; import java.util.stream.Stream; import jdk.jpackage.internal.WixToolset.WixToolsetType; import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.DottedVersion; import jdk.jpackage.internal.util.PathUtils; +import jdk.jpackage.internal.util.Slot; /** * WiX tool. @@ -58,16 +59,20 @@ public enum WixTool { this.minimalVersion = minimalVersion; } - interface ToolInfo { + Path fileName() { + return toolFileName; + } + + sealed interface ToolInfo { Path path(); DottedVersion version(); } - interface CandleInfo extends ToolInfo { + sealed interface CandleInfo extends ToolInfo { boolean fips(); } - private record DefaultToolInfo(Path path, DottedVersion version) implements ToolInfo { + record DefaultToolInfo(Path path, DottedVersion version) implements ToolInfo { DefaultToolInfo { Objects.requireNonNull(path); Objects.requireNonNull(version); @@ -76,9 +81,14 @@ public enum WixTool { DefaultToolInfo(Path path, String version) { this(path, DottedVersion.lazy(version)); } + + @Override + public String toString() { + return String.format("%s|ver=%s", path, version); + } } - private record DefaultCandleInfo(Path path, DottedVersion version, boolean fips) implements CandleInfo { + record DefaultCandleInfo(Path path, DottedVersion version, boolean fips) implements CandleInfo { DefaultCandleInfo { Objects.requireNonNull(path); Objects.requireNonNull(version); @@ -87,25 +97,42 @@ public enum WixTool { DefaultCandleInfo(ToolInfo info, boolean fips) { this(info.path(), info.version(), fips); } + + @Override + public String toString() { + var sb = new StringBuffer(); + sb.append(path); + if (fips) { + sb.append("|fips"); + } + sb.append("|ver=").append(version); + return sb.toString(); + } } static WixToolset createToolset() { + return createToolset(WixTool::findWixInstallDirs, true); + } + + static WixToolset createToolset(Supplier> wixInstallDirs, boolean searchInPath) { + Function, Map> conv = lookupResults -> { - return lookupResults.stream().filter(ToolLookupResult::isValid).collect(Collectors. - groupingBy(lookupResult -> { + return lookupResults.stream().filter(ToolLookupResult::isValid).collect(groupingBy(lookupResult -> { return lookupResult.info().version().toString(); })).values().stream().filter(sameVersionLookupResults -> { - Set sameVersionTools = sameVersionLookupResults.stream().map( - ToolLookupResult::tool).collect(Collectors.toSet()); - if (sameVersionTools.equals(Set.of(Candle3)) || sameVersionTools.equals(Set.of( - Light3))) { + var sameVersionTools = sameVersionLookupResults.stream() + .map(ToolLookupResult::tool) + .collect(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. return false; } else { return true; } - }).flatMap(List::stream).collect(Collectors.toMap(ToolLookupResult::tool, - ToolLookupResult::info, (ToolInfo x, ToolInfo y) -> { + }).flatMap(List::stream).collect(toMap( + ToolLookupResult::tool, + ToolLookupResult::info, + (ToolInfo x, ToolInfo y) -> { return Stream.of(x, y).sorted(Comparator.comparing((ToolInfo toolInfo) -> { return toolInfo.version().toComponentsString(); }).reversed()).findFirst().get(); @@ -115,58 +142,53 @@ public enum WixTool { Function, Optional> createToolset = lookupResults -> { var tools = conv.apply(lookupResults); // Try to build a toolset found in the PATH and in known locations. - return Stream.of(WixToolsetType.values()).map(toolsetType -> { - return WixToolset.create(toolsetType.getTools(), tools); - }).filter(Objects::nonNull).findFirst(); + return Stream.of(WixToolsetType.values()).flatMap(toolsetType -> { + return WixToolset.create(toolsetType, tools).stream(); + }).findFirst(); }; - var toolsInPath = Stream.of(values()).map(tool -> { - return ToolLookupResult.lookup(tool, Optional.empty()); - }).filter(Optional::isPresent).map(Optional::get).toList(); + final List toolsInPath; + if (searchInPath) { + toolsInPath = Stream.of(values()).flatMap(tool -> { + return ToolLookupResult.lookup(tool, Optional.empty()).stream(); + }).toList(); + } else { + toolsInPath = List.of(); + } // Try to build a toolset from tools in the PATH first. - var toolset = createToolset.apply(toolsInPath); - if (toolset.isPresent()) { - return toolset.get(); - } + var toolset = createToolset.apply(toolsInPath).orElseGet(() -> { + // Look up for WiX tools in known locations. + var toolsInKnownWiXDirs = wixInstallDirs.get().stream().flatMap(dir -> { + return Stream.of(values()).flatMap(tool -> { + return ToolLookupResult.lookup(tool, Optional.of(dir)).stream(); + }); + }).toList(); - // Look up for WiX tools in known locations. - var toolsInKnownWiXDirs = findWixInstallDirs().stream().map(dir -> { - return Stream.of(values()).map(tool -> { - return ToolLookupResult.lookup(tool, Optional.of(dir)); + // Build a toolset found in the PATH and in known locations. + var allValidFoundTools = Stream.of(toolsInPath, toolsInKnownWiXDirs) + .flatMap(List::stream) + .filter(ToolLookupResult::isValid) + .toList(); + + return createToolset.apply(allValidFoundTools).orElseThrow(() -> { + return new ConfigException( + I18N.getString("error.no-wix-tools"), + I18N.getString("error.no-wix-tools.advice")); }); - }).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( - ToolLookupResult::isValid).toList(); - toolset = createToolset.apply(allFoundTools); - if (toolset.isPresent()) { - return toolset.get(); - } else if (allFoundTools.isEmpty()) { - throw new ConfigException(I18N.getString("error.no-wix-tools"), I18N.getString( - "error.no-wix-tools.advice")); - } else { - var toolOldVerErr = allFoundTools.stream().map(lookupResult -> { - if (lookupResult.versionTooOld) { - return new ConfigException(MessageFormat.format(I18N.getString( - "message.wrong-tool-version"), lookupResult.info().path(), - lookupResult.info().version(), lookupResult.tool().minimalVersion), - I18N.getString("error.no-wix-tools.advice")); - } else { - return null; - } - }).filter(Objects::nonNull).findAny(); - if (toolOldVerErr.isPresent()) { - throw toolOldVerErr.get(); - } else { - throw new ConfigException(I18N.getString("error.no-wix-tools"), I18N.getString( - "error.no-wix-tools.advice")); - } - } + return toolset; } - private record ToolLookupResult(WixTool tool, ToolInfo info, boolean versionTooOld) { + static List findWixInstallDirs() { + return Stream.of( + findWixCurrentInstallDirs(), + findWix3InstallDirs() + ).flatMap(List::stream).toList(); + } + + private record ToolLookupResult(WixTool tool, ToolInfo info) { ToolLookupResult { Objects.requireNonNull(tool); @@ -177,58 +199,59 @@ public enum WixTool { Objects.requireNonNull(tool); Objects.requireNonNull(lookupDir); - final Path toolPath = lookupDir.map(p -> p.resolve( - tool.toolFileName)).orElse(tool.toolFileName); + final Path toolPath = lookupDir.map(p -> { + return p.resolve(tool.toolFileName); + }).orElse(tool.toolFileName); - final boolean[] tooOld = new boolean[1]; - final String[] parsedVersion = new String[1]; + final var validator = new ToolValidator(toolPath).setMinimalVersion(tool.minimalVersion); - final var validator = new ToolValidator(toolPath) - .setMinimalVersion(tool.minimalVersion) - .setToolOldVersionErrorHandler((name, version) -> { - tooOld[0] = true; - return null; - }); - - final Function, String> versionParser; - - if (Set.of(Candle3, Light3).contains(tool)) { - final String printVersionArg; - if (tool == Candle3) { + final var printVersionArg = switch (tool) { + case 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 = "-?"; + yield "-fips"; } - validator.setCommandLine(printVersionArg); - versionParser = output -> { - String firstLineOfOutput = output.findFirst().orElse(""); - int separatorIdx = firstLineOfOutput.lastIndexOf(' '); - if (separatorIdx == -1) { - return null; - } - return firstLineOfOutput.substring(separatorIdx + 1); - }; - } else { - validator.setCommandLine("--version"); - versionParser = output -> { - return output.findFirst().orElse(""); - }; - } + case Light3 -> { + yield "-?"; + } + default -> { + yield "--version"; + } + }; + validator.setCommandLine(printVersionArg); + final Function, Optional> versionParser = switch (tool) { + case Candle3, Light3 -> { + yield output -> { + return output.findFirst().map(firstLineOfOutput -> { + int separatorIdx = firstLineOfOutput.lastIndexOf(' '); + if (separatorIdx == -1) { + return null; + } + return firstLineOfOutput.substring(separatorIdx + 1); + }); + }; + } + default -> { + yield output -> { + return output.findFirst(); + }; + } + }; + + final var parsedVersion = Slot.createEmpty(); validator.setVersionParser(output -> { - parsedVersion[0] = versionParser.apply(output); - return parsedVersion[0]; + versionParser.apply(output).ifPresent(parsedVersion::set); + return parsedVersion.find().orElse(null); }); if (validator.validate() == null) { // Tool found - ToolInfo info = new DefaultToolInfo(toolPath, parsedVersion[0]); + ToolInfo info = new DefaultToolInfo(toolPath, parsedVersion.get()); if (tool == Candle3) { // Detect FIPS mode var fips = false; @@ -242,63 +265,52 @@ public enum WixTool { } } } catch (IOException ex) { - Log.verbose(ex); } info = new DefaultCandleInfo(info, fips); } - return Optional.of(new ToolLookupResult(tool, info, tooOld[0])); + + return Optional.of(new ToolLookupResult(tool, info)); } else { return Optional.empty(); } } + boolean versionTooOld() { + return DottedVersion.compareComponents(info.version(), tool.minimalVersion) < 0; + } + boolean isValid() { - return !versionTooOld; + return !versionTooOld(); } } - private static Path getSystemDir(String envVar, String knownDir) { - return Optional - .ofNullable(getEnvVariableAsPath(envVar)) - .orElseGet(() -> Optional - .ofNullable(getEnvVariableAsPath("SystemDrive")) - .orElseGet(() -> Path.of("C:")).resolve(knownDir)); + private static Path getSystemDir(String envVar, Path knownDir) { + return getEnvVariableAsPath(envVar).orElseGet(() -> { + return getEnvVariableAsPath("SystemDrive").orElseGet(() -> { + return Path.of("C:"); + }).resolve(knownDir); + }); } - private static Path getEnvVariableAsPath(String envVar) { - String path = System.getenv(envVar); - if (path != null) { - try { - return Path.of(path); - } catch (InvalidPathException ex) { - Log.error(MessageFormat.format(I18N.getString( - "error.invalid-envvar"), envVar)); - } - } - return null; - } - - private static List findWixInstallDirs() { - return Stream.of(findWixCurrentInstallDirs(), findWix3InstallDirs()). - flatMap(List::stream).toList(); + private static Optional getEnvVariableAsPath(String envVar) { + Objects.requireNonNull(envVar); + return Optional.ofNullable(Globals.instance().system().getenv(envVar)).flatMap(PathUtils::asPath); } private static List findWixCurrentInstallDirs() { - return Stream.of(getEnvVariableAsPath("USERPROFILE"), Optional.ofNullable(System. - getProperty("user.home")).map(Path::of).orElse(null)).filter(Objects::nonNull).map( - path -> { - return path.resolve(".dotnet/tools"); - }).filter(Files::isDirectory).distinct().toList(); + return Stream.of( + getEnvVariableAsPath("USERPROFILE"), + Optional.ofNullable(Globals.instance().system().getProperty("user.home")).flatMap(PathUtils::asPath) + ).flatMap(Optional::stream).map(path -> { + return path.resolve(".dotnet/tools"); + }).filter(Files::isDirectory).distinct().toList(); } private static List findWix3InstallDirs() { - PathMatcher wixInstallDirMatcher = FileSystems.getDefault(). - getPathMatcher( - "glob:WiX Toolset v*"); + var wixInstallDirMatcher = FileSystems.getDefault().getPathMatcher("glob:WiX Toolset v*"); - Path programFiles = getSystemDir("ProgramFiles", "\\Program Files"); - Path programFilesX86 = getSystemDir("ProgramFiles(x86)", - "\\Program Files (x86)"); + var programFiles = getSystemDir("ProgramFiles", Path.of("Program Files")); + var programFilesX86 = getSystemDir("ProgramFiles(x86)", Path.of("Program Files (x86)")); // Returns list of WiX install directories ordered by WiX version number. // Newer versions go first. @@ -306,13 +318,11 @@ public enum WixTool { try (var paths = Files.walk(path, 1)) { return paths.toList(); } catch (IOException ex) { - Log.verbose(ex); - List empty = List.of(); - return empty; + return List.of(); } }).flatMap(List::stream) - .filter(path -> wixInstallDirMatcher.matches(path.getFileName())). - sorted(Comparator.comparing(Path::getFileName).reversed()) + .filter(path -> wixInstallDirMatcher.matches(path.getFileName())) + .sorted(Comparator.comparing(Path::getFileName).reversed()) .map(path -> path.resolve("bin")) .toList(); } 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 e7bdbede368..1694503a8c8 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, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,14 +26,20 @@ package jdk.jpackage.internal; import java.nio.file.Path; import java.util.Map; +import java.util.Objects; +import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; import jdk.jpackage.internal.model.DottedVersion; -final class WixToolset { +record WixToolset(Map tools) { - static enum WixToolsetType { + WixToolset { + tools = Map.copyOf(tools); + } + + enum WixToolsetType { // Wix v4+ Wix4(WixTool.Wix4), // Wix v3+ @@ -50,10 +56,6 @@ final class WixToolset { private final Set tools; } - private WixToolset(Map tools) { - this.tools = tools; - } - WixToolsetType getType() { return Stream.of(WixToolsetType.values()).filter(toolsetType -> { return toolsetType.getTools().equals(tools.keySet()); @@ -75,16 +77,19 @@ final class WixToolset { .anyMatch(WixTool.CandleInfo::fips); } - static WixToolset create(Set requiredTools, Map allTools) { + static Optional create(WixToolsetType type, Map allTools) { + Objects.requireNonNull(type); + Objects.requireNonNull(allTools); + + var requiredTools = type.getTools(); + var filteredTools = allTools.entrySet().stream().filter(e -> { return requiredTools.contains(e.getKey()); }).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); if (filteredTools.keySet().equals(requiredTools)) { - return new WixToolset(filteredTools); + return Optional.of(new WixToolset(filteredTools)); } else { - return null; + return Optional.empty(); } } - - private final Map tools; } 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 0f3dcab8260..a11a8a6b41e 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 @@ -36,8 +36,8 @@ 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. +error.no-wix-tools=No usable WiX Toolset installation found +error.no-wix-tools.advice=Install the latest WiX v3 from https://github.com/wixtoolset/wix3/releases or WiX v4+ from https://github.com/wixtoolset/wix/releases error.version-string-wrong-format.advice=Set value of --app-version parameter to a valid Windows Installer ProductVersion. error.msi-product-version-components=Version string [{0}] must have between 2 and 4 components. error.msi-product-version-major-out-of-range=Major version must be in the range [0, 255] @@ -56,7 +56,6 @@ error.missing-service-installer.advice=Add 'service-installer.exe' service insta message.icon-not-ico=The specified icon "{0}" is not an ICO file and will not be used. The default icon will be used in it's place. message.tool-version=Detected [{0}] version [{1}]. -message.wrong-tool-version=Detected [{0}] version {1} but version {2} is required. message.product-code=MSI ProductCode: {0}. message.upgrade-code=MSI UpgradeCode: {0}. message.preparing-msi-config=Preparing MSI config: {0}. diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/mock/MockingToolProvider.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/mock/MockingToolProvider.java index f8c04cc3927..2c46d02e7ce 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/mock/MockingToolProvider.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/mock/MockingToolProvider.java @@ -160,5 +160,5 @@ abstract sealed class MockingToolProvider implements ToolProviderCommandMock { private final String name; private final Iterator actionIter; - static ToolProviderCommandMock UNREACHABLE = new MockingToolProvider.NonCompletable("", List.of()); + static final ToolProviderCommandMock UNREACHABLE = new MockingToolProvider.NonCompletable("", List.of()); } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/stdmock/EnvironmentProviderMock.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/stdmock/EnvironmentProviderMock.java new file mode 100644 index 00000000000..1e12078ec66 --- /dev/null +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/stdmock/EnvironmentProviderMock.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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.stdmock; + +import jdk.jpackage.internal.EnvironmentProvider; +import java.util.ArrayList; +import java.util.Map; +import java.util.Objects; + +public record EnvironmentProviderMock( + Map envVariables, + Map systemProperties) implements EnvironmentProvider { + + public EnvironmentProviderMock { + envVariables.keySet().forEach(Objects::requireNonNull); + envVariables.values().forEach(Objects::requireNonNull); + + systemProperties.keySet().forEach(Objects::requireNonNull); + systemProperties.values().forEach(Objects::requireNonNull); + } + + @Override + public String getenv(String envVarName) { + return envVariables.get(Objects.requireNonNull(envVarName)); + } + + @Override + public String getProperty(String propertyName) { + return systemProperties.get(Objects.requireNonNull(propertyName)); + } + + @Override + public String toString() { + var tokens = new ArrayList(); + if (!envVariables.isEmpty()) { + tokens.add(String.format("env=%s", envVariables)); + } + if (!systemProperties.isEmpty()) { + tokens.add(String.format("props=%s", systemProperties)); + } + return String.join(", ", tokens); + } +} diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/stdmock/WixToolMock.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/stdmock/WixToolMock.java new file mode 100644 index 00000000000..9cd00f61082 --- /dev/null +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/stdmock/WixToolMock.java @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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.stdmock; + +import java.nio.file.Path; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import jdk.jpackage.internal.util.PathUtils; +import jdk.jpackage.test.mock.CommandActionSpec; +import jdk.jpackage.test.mock.CommandActionSpecs; +import jdk.jpackage.test.mock.CommandMockSpec; + +public final class WixToolMock { + + public CommandMockSpec create() { + Objects.requireNonNull(type); + Objects.requireNonNull(version); + + CommandActionSpec action = switch (type) { + case CANDLE3 -> { + yield candleAction(fips, version); + } + case LIGHT3 -> { + yield lightAction(version); + } + case WIX4 -> { + yield wixAction(version); + } + }; + + var toolPath = Optional.ofNullable(dir).map(d -> { + return d.resolve(type.fileName); + }).orElse(type.fileName); + var mockName = PathUtils.replaceSuffix(toolPath, ""); + + return new CommandMockSpec(toolPath, mockName, CommandActionSpecs.build().action(action).create()); + } + + public WixToolMock fips(Boolean v) { + fips = v; + return this; + } + + public WixToolMock fips() { + return fips(true); + } + + public WixToolMock dir(Path v) { + dir = v; + return this; + } + + public WixToolMock version(String v) { + version = v; + return this; + } + + public WixToolMock candle(String version) { + return type(WixTool.CANDLE3).version(version); + } + + public WixToolMock light(String version) { + return type(WixTool.LIGHT3).version(version); + } + + public WixToolMock wix(String version) { + return type(WixTool.WIX4).version(version); + } + + private WixToolMock type(WixTool v) { + type = v; + return this; + } + + private static CommandActionSpec candleAction(boolean fips, String version) { + Objects.requireNonNull(version); + var sb = new StringBuilder(); + sb.append(version); + if (fips) { + sb.append("; fips"); + } + return CommandActionSpec.create(sb.toString(), context -> { + if (List.of("-?").equals(context.args())) { + if (fips) { + context.err().println("error CNDL0308 : The Federal Information Processing Standard (FIPS) appears to be enabled on the machine"); + return Optional.of(308); + } + } else if (!List.of("-fips").equals(context.args())) { + throw context.unexpectedArguments(); + } + + var out = context.out(); + List.of( + "Windows Installer XML Toolset Compiler version " + version, + "Copyright (c) .NET Foundation and contributors. All rights reserved.", + "", + " usage: candle.exe [-?] [-nologo] [-out outputFile] sourceFile [sourceFile ...] [@responseFile]" + ).forEach(out::println); + + return Optional.of(0); + }); + } + + private static CommandActionSpec lightAction(String version) { + Objects.requireNonNull(version); + return CommandActionSpec.create(version, context -> { + if (List.of("-?").equals(context.args())) { + var out = context.out(); + List.of( + "Windows Installer XML Toolset Linker version " + version, + "Copyright (c) .NET Foundation and contributors. All rights reserved.", + "", + " usage: light.exe [-?] [-b bindPath] [-nologo] [-out outputFile] objectFile [objectFile ...] [@responseFile]" + ).forEach(out::println); + return Optional.of(0); + } else { + throw context.unexpectedArguments(); + } + }); + } + + private static CommandActionSpec wixAction(String version) { + Objects.requireNonNull(version); + return CommandActionSpec.create(version, context -> { + if (List.of("--version").equals(context.args())) { + context.out().println(version); + return Optional.of(0); + } else { + throw context.unexpectedArguments(); + } + }); + } + + private enum WixTool { + CANDLE3("candle"), + LIGHT3("light"), + WIX4("wix"), + ; + + WixTool(String name) { + this.fileName = Path.of(Objects.requireNonNull(name) + ".exe"); + } + + final Path fileName; + } + + private Path dir; + private WixTool type; + private String version; + private boolean fips; +} diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/PathUtilsTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/PathUtilsTest.java new file mode 100644 index 00000000000..7ed679ea3b5 --- /dev/null +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/PathUtilsTest.java @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal.util; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrowsExactly; + +import java.nio.file.Path; +import java.util.Optional; +import java.util.function.UnaryOperator; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + + +class PathUtilsTest { + + @ParameterizedTest + @CsvSource({ + "foo,''", + "foo.bar,.bar", + "foo..bar,.bar", + ".bar,.bar", + "foo.bar.buz,.buz", + ".,.", + "...,.", + "..,.", + }) + void test_getSuffix(Path path, String expected) { + + var suffix = PathUtils.getSuffix(path); + + assertEquals(expected, suffix); + } + + @Test + void test_getSuffix_null() { + assertThrowsExactly(NullPointerException.class, () -> { + PathUtils.getSuffix(null); + }); + } + + @ParameterizedTest + @CsvSource({ + "foo,'',foo", + "a/b/foo.exe,.ico,a/b/foo.exe.ico", + "foo,bar,foobar", + "'',bar,bar", + ".,bar,.bar", + }) + void test_addSuffix(Path path, String suffix, Path expected) { + + var newPath = PathUtils.addSuffix(path, suffix); + + assertEquals(expected, newPath); + } + + @Test + void test_addSuffix_null() { + assertThrowsExactly(NullPointerException.class, () -> { + PathUtils.addSuffix(null, "foo"); + }); + assertThrowsExactly(NullPointerException.class, () -> { + PathUtils.addSuffix(Path.of("foo"), null); + }); + } + + @ParameterizedTest + @CsvSource({ + "foo.exe,.ico,foo.ico", + "foo.exe,,foo", + "foo.exe,'',foo", + "a/b/foo.exe,.ico,a/b/foo.ico", + "foo,'',foo", + "foo,bar,foobar", + "'',bar,bar", + ".,bar,bar", + ".,.bar,.bar", + }) + void test_replaceSuffix(Path path, String newSuffix, Path expected) { + + var newPath = PathUtils.replaceSuffix(path, newSuffix); + + assertEquals(expected, newPath); + } + + @Test + void test_replaceSuffix_null() { + assertThrowsExactly(NullPointerException.class, () -> { + PathUtils.replaceSuffix(null, "foo"); + }); + + assertEquals(Path.of("foo"), PathUtils.replaceSuffix(Path.of("foo.a"), null)); + } + + @ParameterizedTest + @CsvSource({ + "IDENTITY,a,a", + "IDENTITY,,", + "RETURN_NULL,a,", + "RETURN_NULL,,", + "FOO,a,foo", + "FOO,,", + }) + void test_mapNullablePath(PathMapper mapper, Path path, Path expected) { + + var newPath = PathUtils.mapNullablePath(mapper, path); + + assertEquals(expected, newPath); + } + + @Test + void test_mapNullablePath_null() { + assertThrowsExactly(NullPointerException.class, () -> { + PathUtils.mapNullablePath(null, Path.of("")); + }); + } + + @ParameterizedTest + @CsvSource(nullValues = {"N/A"}, value = { + "foo.exe", + "N/A", + }) + void test_normalizedAbsolutePath(Path path) { + + var newPath = PathUtils.normalizedAbsolutePath(path); + + var expected = Optional.ofNullable(path).map(v -> { + return v.normalize().toAbsolutePath(); + }).orElse(null); + + assertEquals(expected, newPath); + } + + @ParameterizedTest + @CsvSource(nullValues = {"N/A"}, value = { + "foo.exe", + "N/A", + }) + void test_normalizedAbsolutePathString(Path path) { + + var newPath = PathUtils.normalizedAbsolutePathString(path); + + var expected = Optional.ofNullable(path).map(v -> { + return v.normalize().toAbsolutePath().toString(); + }).orElse(null); + + assertEquals(expected, newPath); + } + + @ParameterizedTest + @CsvSource(nullValues = {"N/A"}, value = { + "N/A", + "foo", + "*", + ":", + }) + void test_asPath(String str) { + + var path = PathUtils.asPath(str); + + var expected = Optional.ofNullable(str).flatMap(v -> { + return Result.of(() -> { + return Path.of(v); + }).value(); + }); + + assertEquals(expected, path); + } + + enum PathMapper implements UnaryOperator { + IDENTITY { + @Override + public Path apply(Path path) { + return path; + } + }, + RETURN_NULL { + @Override + public Path apply(Path path) { + return null; + } + }, + FOO { + @Override + public Path apply(Path path) { + return Path.of("foo"); + } + }, + ; + } +} diff --git a/test/jdk/tools/jpackage/junit/windows/jdk.jpackage/jdk/jpackage/internal/WixToolTest.java b/test/jdk/tools/jpackage/junit/windows/jdk.jpackage/jdk/jpackage/internal/WixToolTest.java new file mode 100644 index 00000000000..d4881069844 --- /dev/null +++ b/test/jdk/tools/jpackage/junit/windows/jdk.jpackage/jdk/jpackage/internal/WixToolTest.java @@ -0,0 +1,754 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal; + +import static java.util.stream.Collectors.toMap; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +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 jdk.jpackage.internal.WixTool.ToolInfo; +import jdk.jpackage.internal.WixToolset.WixToolsetType; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.util.TokenReplace; +import jdk.jpackage.test.CannedFormattedString; +import jdk.jpackage.test.JPackageStringBundle; +import jdk.jpackage.test.mock.CommandActionSpecs; +import jdk.jpackage.test.mock.CommandMock; +import jdk.jpackage.test.mock.CommandMockSpec; +import jdk.jpackage.test.mock.Script; +import jdk.jpackage.test.stdmock.EnvironmentProviderMock; +import jdk.jpackage.test.stdmock.JPackageMockUtils; +import jdk.jpackage.test.stdmock.WixToolMock; +import org.junit.jupiter.api.io.TempDir; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + + +class WixToolTest { + + @ParameterizedTest + @MethodSource + void testLookup(TestSpec spec, @TempDir Path workDir) throws IOException { + spec.run(workDir); + } + + @ParameterizedTest + @MethodSource + void testLookupDirs(EnvironmentTestSpec spec, @TempDir Path workDir) throws IOException { + spec.run(workDir); + } + + private static Collection testLookup() { + + List testCases = new ArrayList<>(); + + Consumer appendTestCases = builder -> { + testCases.add(builder.create()); + }; + + Stream.of( + // Simple WiX3 of a minimal acceptable version + TestSpec.build() + .expect(toolset().version("3.0").put(WixToolsetType.Wix3, "foo")) + .tool(tool("foo").candle("3.0")) + .tool(tool("foo").light("3.0")), + // Simple WiX3 with FIPS + TestSpec.build() + .expect(toolset().version("3.14.1.8722").put(WixToolsetType.Wix3, "foo").fips()) + .tool(tool("foo").candle("3.14.1.8722").fips()) + .tool(tool("foo").light("3.14.1.8722")), + // Simple WiX4+ of a minimal acceptable version + TestSpec.build() + .expect(toolset().version("4.0.4").put(WixToolsetType.Wix4, "foo")) + .tool(tool("foo").wix("4.0.4")), + // WiX3 with light and candle from different directories and non-existent directory + TestSpec.build() + .expect(toolset().version("3.11.2").put(WixTool.Candle3, "foo").put(WixTool.Light3, "bar")) + .lookupDir("buz") + .tool(tool("foo").candle("3.11.2")) + .tool(tool("bar").light("3.11.2")) + .tool(tool("bar").candle("3.11.1")) + .tool(tool("foo").light("3.11.1")), + // WiX3, WiX4+ same directory + TestSpec.build() + .expect(toolset().version("5.0.2+aa65968c").put(WixToolsetType.Wix4, "foo")) + .tool(tool("foo").candle("3.14.1.8722")) + .tool(tool("foo").light("3.14.1.8722")) + .tool(tool("foo").wix("5.0.2+aa65968c")), + // WiX3 (good), WiX4+ (bad version) + TestSpec.build() + .expect(toolset().version("3.14.1.8722").put(WixToolsetType.Wix3, "foo")) + .tool(tool("foo").candle("3.14.1.8722")) + .tool(tool("foo").light("3.14.1.8722")) + .tool(tool("foo").wix("Blah-blah-blah")), + // WiX3 (incomplete), WiX4+ (good) + TestSpec.build() + .expect(toolset().version("5.0").put(WixToolsetType.Wix4, "foo")) + .tool(tool("foo").candle("3.14.1.8722")) + .tool(tool("foo").wix("5.0")), + // WiX5 in the PATH and in the directory, same version; PATH always wins + TestSpec.build() + .expect(toolset().version("5.0").put(WixToolsetType.Wix4)) + .tool(tool().wix("5.0")) + .tool(tool("foo").wix("5.0")), + // WiX5 in the PATH and in the directory; the one in the directory is newer; PATH always wins + TestSpec.build() + .expect(toolset().version("5.0").put(WixToolsetType.Wix4)) + .tool(tool().wix("5.0")) + .tool(tool("foo").wix("5.1")), + // WiX5 in the PATH and in the directory; the one in the PATH is newer; PATH always wins + TestSpec.build() + .expect(toolset().version("5.1").put(WixToolsetType.Wix4)) + .tool(tool().wix("5.1")) + .tool(tool("foo").wix("5.0")), + // WiX3 in the PATH, WiX3 in the directory; PATH always wins + TestSpec.build() + .expect(toolset().version("3.20").put(WixToolsetType.Wix3)) + .tool(tool().candle("3.20")) + .tool(tool().light("3.20")) + .tool(tool("foo").wix("5.0")), + // Old WiX3 in the PATH, WiX3 in the directory + TestSpec.build() + .expect(toolset().version("3.20").put(WixToolsetType.Wix3, "foo")) + .tool(tool().candle("2.9")) + .tool(tool().light("2.9")) + .tool(tool("foo").candle("3.20")) + .tool(tool("foo").light("3.20")) + ).forEach(appendTestCases); + + for (var oldLightStatus : ToolStatus.values()) { + for (var oldCandleStatus : ToolStatus.values()) { + for (var newLightStatus : ToolStatus.values()) { + for (var newCandleStatus : ToolStatus.values()) { + boolean newGood = ToolStatus.isAllGood(newLightStatus, newCandleStatus); + if (!ToolStatus.isAllGood(oldLightStatus, oldCandleStatus) && !newGood) { + continue; + } + + var builder = TestSpec.build(); + if (newGood) { + builder.expect(toolset().version("3.14").put(WixToolsetType.Wix3, "new")); + } else { + builder.expect(toolset().version("3.11").put(WixToolsetType.Wix3, "old")); + } + + oldCandleStatus.map(tool("old").candle("3.11")).ifPresent(builder::tool); + oldLightStatus.map(tool("old").light("3.11")).ifPresent(builder::tool); + + newCandleStatus.map(tool("new").candle("3.14")).ifPresent(builder::tool); + newLightStatus.map(tool("new").light("3.14")).ifPresent(builder::tool); + + appendTestCases.accept(builder); + } + } + } + } + + Stream.of( + // No WiX tools + TestSpec.build(), + TestSpec.build() + .lookupDir("foo"), + TestSpec.build() + .lookupDir(LOOKUP_IN_PATH), + // Incomplete WiX3: missing candle.exe + TestSpec.build() + .tool(tool("foo").light("3.14.1.8722")), + // Incomplete WiX3: missing light.exe + TestSpec.build() + .tool(tool("foo").candle("3.14.1.8722")), + // Incomplete WiX3: version mismatch of light.exe and candle.exe + TestSpec.build() + .tool(tool("foo").candle("3.14")) + .tool(tool("foo").light("3.15")), + // WiX3 too old + TestSpec.build() + .tool(tool("foo").candle("2.9")) + .tool(tool("foo").light("2.9")), + // WiX4+ too old + TestSpec.build() + .tool(tool("foo").wix("4.0.3")) + ).forEach(appendTestCases); + + return testCases; + } + + private static Collection testLookupDirs() { + + List testCases = new ArrayList<>(); + + Stream.of( + EnvironmentTestSpec.build() + .env(EnvironmentVariable.USERPROFILE, "@@/foo") + .expect("@USERPROFILE@/.dotnet/tools"), + EnvironmentTestSpec.build() + .env(SystemProperty.USER_HOME, "@@/bar") + .expect("@user.home@/.dotnet/tools"), + // "USERPROFILE" environment variable and "user.home" system property set to different values, + // the order should be "USERPROFILE" followed by "user.home". + EnvironmentTestSpec.build() + .env(EnvironmentVariable.USERPROFILE, "@@/foo") + .env(SystemProperty.USER_HOME, "@@/bar") + .expect("@USERPROFILE@/.dotnet/tools") + .expect("@user.home@/.dotnet/tools"), + // "USERPROFILE" environment variable and "user.home" system property set to the same value. + EnvironmentTestSpec.build() + .env(EnvironmentVariable.USERPROFILE, "@@/buz") + .env(SystemProperty.USER_HOME, "@@/buz") + .expect("@USERPROFILE@/.dotnet/tools"), + // WiX3: newer versions first; 32bit after 64bit + EnvironmentTestSpec.build() + .standardEnv(EnvironmentVariable.PROGRAM_FILES_X86) + .standardEnv(EnvironmentVariable.PROGRAM_FILES) + .expect(String.format("@%s@/WiX Toolset v3.11/bin", EnvironmentVariable.PROGRAM_FILES_X86.variableName())) + .expect(String.format("@%s@/WiX Toolset v3.10/bin", EnvironmentVariable.PROGRAM_FILES.variableName())) + .expect(String.format("@%s@/WiX Toolset v3.10/bin", EnvironmentVariable.PROGRAM_FILES_X86.variableName())), + // Malformed installation directory should be accepted + EnvironmentTestSpec.build() + .standardEnv(EnvironmentVariable.PROGRAM_FILES_X86) + .expect(String.format("@%s@/WiX Toolset vb/bin", EnvironmentVariable.PROGRAM_FILES_X86.variableName())) + .expect(String.format("@%s@/WiX Toolset va/bin", EnvironmentVariable.PROGRAM_FILES_X86.variableName())) + .expect(String.format("@%s@/WiX Toolset v/bin", EnvironmentVariable.PROGRAM_FILES_X86.variableName())), + // No directories + EnvironmentTestSpec.build() + ).map(EnvironmentTestSpec.Builder::create).forEach(testCases::add); + + return testCases; + } + + private enum ToolStatus { + GOOD, + MISSING, + UNEXPECTED_STDOUT, + ; + + static boolean isAllGood(ToolStatus... status) { + return Stream.of(status).allMatch(Predicate.isEqual(GOOD)); + } + + Optional map(WixToolMock builder) { + return switch (this) { + case MISSING -> { + yield Optional.empty(); + } + case UNEXPECTED_STDOUT -> { + var mock = builder.create(); + yield Optional.of(new CommandMockSpec( + mock.name(), + mock.mockName(), + CommandActionSpecs.build().stdout("Blah-Blah-Blah").exit().create())); + } + case GOOD -> { + yield Optional.of(builder.create()); + } + }; + } + } + + record TestSpec( + Optional expected, + List lookupDirs, + boolean lookupInPATH, + Collection mocks, + List expectedErrors) { + + TestSpec { + Objects.requireNonNull(expected); + lookupDirs.forEach(Objects::requireNonNull); + mocks.forEach(Objects::requireNonNull); + expectedErrors.forEach(Objects::requireNonNull); + + if (expected.isEmpty() == expectedErrors.isEmpty()) { + // It should be either toolset or errors, not both or non both. + throw new IllegalArgumentException(); + } + + lookupDirs.forEach(WixToolTest::assertIsRelative); + + lookupDirs.forEach(path -> { + assertNotEquals(LOOKUP_IN_PATH, path); + }); + + // Ensure tool paths are unique. + mocks.stream().map(CommandMockSpec::name).collect(toMap(x -> x, x -> x)); + } + + @Override + public String toString() { + var tokens = new ArrayList(); + expected.map(Object::toString).ifPresent(tokens::add); + if (!expectedErrors.isEmpty()) { + tokens.add(String.format("errors=%s", expectedErrors)); + } + + List lookupPaths; + if (lookupInPATH) { + lookupPaths = new ArrayList<>(); + lookupPaths.add(Path.of("${PATH}")); + lookupPaths.addAll(lookupDirs); + } else { + lookupPaths = lookupDirs; + } + + if (!lookupPaths.isEmpty()) { + tokens.add(String.format("lookup-dirs=%s", lookupPaths)); + } + if (!mocks.isEmpty()) { + tokens.add(mocks.toString()); + } + return String.join(", ", tokens); + } + + void run(Path workDir) { + var scriptBuilder = Script.build().commandMockBuilderMutator(CommandMock.Builder::repeatInfinitely); + mocks.stream().map(mockSpec -> { + Path toolPath = mockSpec.name(); + if (toolPath.getNameCount() > 1) { + toolPath = workDir.resolve(toolPath); + } + return new CommandMockSpec(toolPath, mockSpec.mockName(), mockSpec.actions()); + }).forEach(scriptBuilder::map); + + scriptBuilder.map(_ -> true, CommandMock.ioerror("non-existent")); + + var script = scriptBuilder.createLoop(); + + Supplier createToolset = () -> { + return WixTool.createToolset(() -> { + return lookupDirs.stream().map(workDir::resolve).toList(); + }, lookupInPATH()); + }; + + Globals.main(() -> { + JPackageMockUtils.buildJPackage() + .script(script) + .listener(System.out::println) + .applyToGlobals(); + + expected.ifPresentOrElse(expectedToolset -> { + var toolset = createToolset.get(); + assertEquals(resolveAt(expectedToolset, workDir), toolset); + }, () -> { + var ex = assertThrows(RuntimeException.class, createToolset::get); + assertEquals(expectedErrors.getFirst().getValue(), ex.getMessage()); + if (ex instanceof ConfigException cfgEx) { + assertEquals(expectedErrors.getLast().getValue(), cfgEx.getAdvice()); + assertEquals(2, expectedErrors.size()); + } else { + assertEquals(1, expectedErrors.size()); + } + }); + + return 0; + }); + } + + static Builder build() { + return new Builder(); + } + + static final class Builder { + + TestSpec create() { + if (expected == null && expectedErrors.isEmpty()) { + return copy() + .expect("error.no-wix-tools") + .expect("error.no-wix-tools.advice") + .create(); + } else { + var allLookupDirs = Stream.concat( + lookupDirs.stream(), + tools.stream().map(CommandMockSpec::name).map(toolPath -> { + if (toolPath.getNameCount() == 1) { + return LOOKUP_IN_PATH; + } else { + return toolPath.getParent(); + } + }) + ).distinct().collect(Collectors.toCollection(ArrayList::new)); + + var lookupInPATH = allLookupDirs.contains(LOOKUP_IN_PATH); + if (lookupInPATH) { + allLookupDirs.remove(LOOKUP_IN_PATH); + } + + return new TestSpec( + Optional.ofNullable(expected), + Collections.unmodifiableList(allLookupDirs), + lookupInPATH, + List.copyOf(tools), + List.copyOf(expectedErrors)); + } + } + + Builder copy() { + return new Builder(this); + } + + private Builder() { + expectedErrors = new ArrayList<>(); + lookupDirs = new ArrayList<>(); + tools = new ArrayList<>(); + } + + private Builder(Builder other) { + expected = other.expected; + expectedErrors = new ArrayList<>(other.expectedErrors); + lookupDirs = new ArrayList<>(other.lookupDirs); + tools = new ArrayList<>(other.tools); + } + + Builder expect(WixToolset v) { + expected = v; + return this; + } + + Builder expect(String formatKey, Object ... args) { + expectedErrors.add(JPackageStringBundle.MAIN.cannedFormattedString(formatKey, args)); + return this; + } + + Builder expect(WixToolsetBuilder builder) { + return expect(builder.create()); + } + + Builder lookupDir(String v) { + return lookupDir(Path.of(v)); + } + + Builder lookupDir(Path v) { + lookupDirs.add(Objects.requireNonNull(v)); + return this; + } + + Builder tool(CommandMockSpec v) { + tools.add(Objects.requireNonNull(v)); + return this; + } + + Builder tool(WixToolMock v) { + return tool(v.create()); + } + + private WixToolset expected; + private final List expectedErrors; + private final List lookupDirs; + private final List tools; + } + } + + private static final class WixToolsetBuilder { + + WixToolset create() { + return new WixToolset(tools.entrySet().stream().collect(toMap(Map.Entry::getKey, e -> { + ToolInfo toolInfo = new WixTool.DefaultToolInfo(e.getValue(), version); + if (e.getKey() == WixTool.Candle3) { + toolInfo = new WixTool.DefaultCandleInfo(toolInfo, fips); + } + return toolInfo; + }))); + } + + WixToolsetBuilder version(String v) { + version = v; + return this; + } + + WixToolsetBuilder put(WixTool tool, String path) { + return put(tool, Path.of(path)); + } + + WixToolsetBuilder put(WixTool tool, Path path) { + tools.put(Objects.requireNonNull(tool), path.resolve(tool.fileName())); + return this; + } + + WixToolsetBuilder put(WixTool tool) { + return put(tool, LOOKUP_IN_PATH); + } + + WixToolsetBuilder put(WixToolsetType type, Path path) { + type.getTools().forEach(tool -> { + put(tool, path); + }); + return this; + } + + WixToolsetBuilder put(WixToolsetType type, String path) { + return put(type, Path.of(path)); + } + + WixToolsetBuilder put(WixToolsetType type) { + return put(type, LOOKUP_IN_PATH); + } + + WixToolsetBuilder fips(boolean v) { + fips = true; + return this; + } + + WixToolsetBuilder fips() { + return fips(true); + } + + private Map tools = new HashMap<>(); + private boolean fips; + private String version; + } + + enum EnvironmentVariable { + USERPROFILE("USERPROFILE"), + PROGRAM_FILES("ProgramFiles"), + PROGRAM_FILES_X86("ProgramFiles(x86)"), + SYSTEM_DRIVE("SystemDrive"), + ; + + EnvironmentVariable(String variableName) { + this.variableName = Objects.requireNonNull(variableName); + } + + String variableName() { + return variableName; + } + + private final String variableName; + } + + enum SystemProperty { + USER_HOME("user.home"), + ; + + SystemProperty(String propertyName) { + this.propertyName = Objects.requireNonNull(propertyName); + } + + String propertyName() { + return propertyName; + } + + private final String propertyName; + } + + record EnvironmentTestSpec(EnvironmentProviderMock env, List expectedDirs) { + + EnvironmentTestSpec { + Objects.requireNonNull(env); + expectedDirs.forEach(dir -> { + if (dir.isAbsolute()) { + throw new IllegalArgumentException(); + } + }); + } + + @Override + public String toString() { + var tokens = new ArrayList(); + tokens.add(String.format("expect=%s", expectedDirs)); + tokens.add(env.toString()); + return String.join(", ", tokens); + } + + void run(Path workDir) throws IOException { + var allResolved = resolve(workDir, Stream.of( + env.envVariables().entrySet().stream(), + env.systemProperties().entrySet().stream(), + expectedDirs.stream().map(Path::toString).map(dir -> { + return Map.entry(dir, dir); + }) + ).flatMap(x -> x).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue))); + + Function>, Map> filterAllResolved = filterSupplier -> { + var filter = filterSupplier.get(); + return allResolved.entrySet().stream().filter(e -> { + return filter.containsKey(e.getKey()); + }).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + }; + + var resolvedEnv = new EnvironmentProviderMock( + filterAllResolved.apply(env::envVariables), + filterAllResolved.apply(env::systemProperties)); + + var resolvedDirs = expectedDirs.stream().map(Path::toString).map(allResolved::get).map(Path::of).toList(); + + for (var dir : resolvedDirs) { + Files.createDirectories(dir); + } + + Globals.main(() -> { + Globals.instance().system(resolvedEnv); + assertEquals(resolvedDirs, WixTool.findWixInstallDirs()); + return 0; + }); + } + + static Builder build() { + return new Builder(); + } + + static final class Builder { + + EnvironmentTestSpec create() { + var env = envVariables.entrySet().stream().collect(Collectors.toMap(e -> { + return e.getKey().variableName(); + }, Map.Entry::getValue)); + + var props = systemProperties.entrySet().stream().collect(Collectors.toMap(e -> { + return e.getKey().propertyName(); + }, Map.Entry::getValue)); + + return new EnvironmentTestSpec(new EnvironmentProviderMock(env, props), List.copyOf(expectedDirs)); + } + + Builder expect(List dirs) { + expectedDirs.addAll(dirs); + return this; + } + + Builder expect(Path... dirs) { + return expect(List.of(dirs)); + } + + Builder expect(String... dirs) { + return expect(List.of(dirs).stream().map(Path::of).toList()); + } + + Builder env(SystemProperty k, String v) { + systemProperties.put(Objects.requireNonNull(k), Objects.requireNonNull(v)); + return this; + } + + Builder env(EnvironmentVariable k, String v) { + envVariables.put(Objects.requireNonNull(k), Objects.requireNonNull(v)); + return this; + } + + Builder standardEnv(EnvironmentVariable k) { + var value = switch (k) { + case PROGRAM_FILES -> "Program Files"; + case PROGRAM_FILES_X86 -> "Program Files(x86)"; + default -> { + throw new IllegalArgumentException(); + } + }; + return env(k, "@@/" + value); + } + + private final Map envVariables = new HashMap<>(); + private final Map systemProperties = new HashMap<>(); + private final List expectedDirs = new ArrayList<>(); + } + + private static Map resolve(Path workDir, Map props) { + + var tokens = new ArrayList(); + + Stream.of( + Stream.of(EnvironmentVariable.values()).map(EnvironmentVariable::variableName), + Stream.of(SystemProperty.values()).map(SystemProperty::propertyName) + ).flatMap(x -> x).map(str -> { + return String.format("@%s@", str); + }).forEach(tokens::add); + + tokens.add(TOKEN_WORKDIR); + + var tokenReplace = new TokenReplace(tokens.toArray(String[]::new)); + + return props.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> { + return tokenReplace.recursiveApplyTo(e.getValue(), token -> { + if (token.equals(TOKEN_WORKDIR)) { + return workDir; + } else { + return Objects.requireNonNull(props.get(token.substring(1, token.length() - 1)), () -> { + return String.format("Unrecognized token: [%s]", token); + }); + } + }); + })); + } + + static final String TOKEN_WORKDIR = "@@"; + } + + private static WixToolsetBuilder toolset() { + return new WixToolsetBuilder(); + } + + private static WixToolMock tool() { + return new WixToolMock(); + } + + private static WixToolMock tool(Path dir) { + return tool().dir(dir); + } + + private static WixToolMock tool(String dir) { + return tool(Path.of(dir)); + } + + private static WixToolset resolveAt(WixToolset toolset, Path root) { + return new WixToolset(toolset.tools().entrySet().stream().collect(toMap(Map.Entry::getKey, e -> { + var toolInfo = e.getValue(); + + assertIsRelative(toolInfo.path()); + + if (toolInfo.path().getNameCount() == 1) { + // The tool is picked from the PATH. + return toolInfo; + } + + ToolInfo newToolInfo = new WixTool.DefaultToolInfo(root.resolve(toolInfo.path()), toolInfo.version()); + if (toolInfo instanceof WixTool.CandleInfo candleInfo) { + newToolInfo = new WixTool.DefaultCandleInfo(newToolInfo, candleInfo.fips()); + } + return newToolInfo; + }))); + } + + private static void assertIsRelative(Path path) { + if (path.isAbsolute()) { + throw new IllegalArgumentException(); + } + } + + static final Path LOOKUP_IN_PATH = Path.of(""); +} + diff --git a/test/jdk/tools/jpackage/junit/windows/junit.java b/test/jdk/tools/jpackage/junit/windows/junit.java index 1a1d0d58f7e..8c290c2c87f 100644 --- a/test/jdk/tools/jpackage/junit/windows/junit.java +++ b/test/jdk/tools/jpackage/junit/windows/junit.java @@ -45,3 +45,15 @@ * jdk/jpackage/internal/wixui/UISpecTest.java * @run junit jdk.jpackage/jdk.jpackage.internal.wixui.UISpecTest */ + +/* @test + * @summary Test WiX Toolset lookup algorithm + * @requires (os.family == "windows") + * @library /test/jdk/tools/jpackage/helpers + * @build jdk.jpackage.test.* + * @build jdk.jpackage.test.mock.* + * @build jdk.jpackage.test.stdmock.* + * @compile/module=jdk.jpackage -Xlint:all -Werror + * jdk/jpackage/internal/WixToolTest.java + * @run junit jdk.jpackage/jdk.jpackage.internal.WixToolTest + */ From 52fd46d3a614106df6ee4ca35b322dcec37329f2 Mon Sep 17 00:00:00 2001 From: Dhamoder Nalla Date: Wed, 1 Apr 2026 01:42:33 +0000 Subject: [PATCH 133/359] 8371651: [AArch64] Populate CPU _features flag on Windows Reviewed-by: dholmes, bstafford, aph --- .../windows_aarch64/sve_windows_aarch64.S | 42 +++++++++++++++++++ .../vm_version_windows_aarch64.cpp | 35 ++++++++++++---- 2 files changed, 70 insertions(+), 7 deletions(-) create mode 100644 src/hotspot/os_cpu/windows_aarch64/sve_windows_aarch64.S diff --git a/src/hotspot/os_cpu/windows_aarch64/sve_windows_aarch64.S b/src/hotspot/os_cpu/windows_aarch64/sve_windows_aarch64.S new file mode 100644 index 00000000000..e0c85830bd4 --- /dev/null +++ b/src/hotspot/os_cpu/windows_aarch64/sve_windows_aarch64.S @@ -0,0 +1,42 @@ +; +; Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. +; DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +; +; This code is free software; you can redistribute it and/or modify it +; under the terms of the GNU General Public License version 2 only, as +; published by the Free Software Foundation. +; +; This code is distributed in the hope that it will be useful, but WITHOUT +; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +; version 2 for more details (a copy is included in the LICENSE file that +; accompanied this code). +; +; You should have received a copy of the GNU General Public License version +; 2 along with this work; if not, write to the Free Software Foundation, +; Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +; +; Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +; or visit www.oracle.com if you need additional information or have any +; questions. +; + + ; Support for int get_sve_vector_length(); + ; + ; Returns the current SVE vector length in bytes. + ; This function uses the INCB instruction which increments a register + ; by the number of bytes in an SVE vector register. + ; + ; Note: This function will fault if SVE is not available or enabled. + ; The caller must ensure SVE support is detected before calling. + + ALIGN 4 + EXPORT get_sve_vector_length + AREA sve_text, CODE + +get_sve_vector_length + mov x0, #0 + incb x0 + ret + + END diff --git a/src/hotspot/os_cpu/windows_aarch64/vm_version_windows_aarch64.cpp b/src/hotspot/os_cpu/windows_aarch64/vm_version_windows_aarch64.cpp index 93beb549366..e78a37b4178 100644 --- a/src/hotspot/os_cpu/windows_aarch64/vm_version_windows_aarch64.cpp +++ b/src/hotspot/os_cpu/windows_aarch64/vm_version_windows_aarch64.cpp @@ -26,16 +26,19 @@ #include "runtime/os.hpp" #include "runtime/vm_version.hpp" +// Assembly function to get SVE vector length using INCB instruction +extern "C" int get_sve_vector_length(); + int VM_Version::get_current_sve_vector_length() { assert(VM_Version::supports_sve(), "should not call this"); - ShouldNotReachHere(); - return 0; + // Use assembly instruction to get the actual SVE vector length + return VM_Version::supports_sve() ? get_sve_vector_length() : 0; // This value is in bytes } int VM_Version::set_and_get_current_sve_vector_length(int length) { assert(VM_Version::supports_sve(), "should not call this"); - ShouldNotReachHere(); - return 0; + // Use assembly instruction to get the SVE vector length + return VM_Version::supports_sve() ? get_sve_vector_length() : 0; // This value is in bytes } void VM_Version::get_os_cpu_info() { @@ -47,11 +50,29 @@ void VM_Version::get_os_cpu_info() { set_feature(CPU_AES); set_feature(CPU_SHA1); set_feature(CPU_SHA2); + set_feature(CPU_PMULL); } if (IsProcessorFeaturePresent(PF_ARM_VFP_32_REGISTERS_AVAILABLE)) { set_feature(CPU_ASIMD); } - // No check for CPU_PMULL, CPU_SVE, CPU_SVE2 + if (IsProcessorFeaturePresent(PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE)) { + set_feature(CPU_LSE); + } + if (IsProcessorFeaturePresent(PF_ARM_SVE_INSTRUCTIONS_AVAILABLE)) { + set_feature(CPU_SVE); + } + if (IsProcessorFeaturePresent(PF_ARM_SVE2_INSTRUCTIONS_AVAILABLE)) { + set_feature(CPU_SVE2); + } + if (IsProcessorFeaturePresent(PF_ARM_SVE_BITPERM_INSTRUCTIONS_AVAILABLE)) { + set_feature(CPU_SVEBITPERM); + } + if (IsProcessorFeaturePresent(PF_ARM_SHA3_INSTRUCTIONS_AVAILABLE)) { + set_feature(CPU_SHA3); + } + if (IsProcessorFeaturePresent(PF_ARM_SHA512_INSTRUCTIONS_AVAILABLE)) { + set_feature(CPU_SHA512); + } __int64 dczid_el0 = _ReadStatusReg(0x5807 /* ARM64_DCZID_EL0 */); @@ -102,8 +123,8 @@ void VM_Version::get_os_cpu_info() { SYSTEM_INFO si; GetSystemInfo(&si); _model = si.wProcessorLevel; - _variant = si.wProcessorRevision / 0xFF; - _revision = si.wProcessorRevision & 0xFF; + _variant = (si.wProcessorRevision >> 8) & 0xFF; // Variant is the upper byte of wProcessorRevision + _revision = si.wProcessorRevision & 0xFF; // Revision is the lower byte of wProcessorRevision } } } From 2e0ce34d3cbb2abca4efbf8d5598cdc679b72e90 Mon Sep 17 00:00:00 2001 From: Guanqiang Han Date: Wed, 1 Apr 2026 06:20:26 +0000 Subject: [PATCH 134/359] 8380579: C2: Intermittent fastdebug assert in Parse::sharpen_type_after_if: missing type check info Reviewed-by: rcastanedalo, vlivanov --- src/hotspot/share/opto/parse2.cpp | 6 ++ ...harpenTypeAfterIfMissingTypeCheckInfo.java | 57 +++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 test/hotspot/jtreg/compiler/reflection/TestSharpenTypeAfterIfMissingTypeCheckInfo.java diff --git a/src/hotspot/share/opto/parse2.cpp b/src/hotspot/share/opto/parse2.cpp index 7f41870ccea..a7c5398171b 100644 --- a/src/hotspot/share/opto/parse2.cpp +++ b/src/hotspot/share/opto/parse2.cpp @@ -1757,6 +1757,12 @@ static bool match_type_check(PhaseGVN& gvn, // Bool(CmpP(LoadKlass(obj._klass), ConP(Foo.klass)), [eq]) // or the narrowOop equivalent. (*obj) = extract_obj_from_klass_load(&gvn, val); + // Some klass comparisons are not directly in the form + // Bool(CmpP(LoadKlass(obj._klass), ConP(Foo.klass)), [eq]), + // e.g. Bool(CmpP(CastPP(LoadKlass(...)), ConP(klass)), [eq]). + // These patterns with nullable klasses arise from example from + // load_array_klass_from_mirror. + if (*obj == nullptr) { return false; } (*cast_type) = tcon->isa_klassptr()->as_instance_type(); return true; // found } diff --git a/test/hotspot/jtreg/compiler/reflection/TestSharpenTypeAfterIfMissingTypeCheckInfo.java b/test/hotspot/jtreg/compiler/reflection/TestSharpenTypeAfterIfMissingTypeCheckInfo.java new file mode 100644 index 00000000000..7199ad74717 --- /dev/null +++ b/test/hotspot/jtreg/compiler/reflection/TestSharpenTypeAfterIfMissingTypeCheckInfo.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8380579 + * @summary Test that C2 match_type_check handles Bool(CmpP(CastPP(LoadKlass(...)), ConP(klass)), eq) + * @run main/othervm + * -XX:-TieredCompilation + * -Xcomp + * -XX:CompileCommand=compileonly,${test.main.class}::test + * ${test.main.class} + */ + +package compiler.reflection; + +import java.lang.reflect.Array; + +public class TestSharpenTypeAfterIfMissingTypeCheckInfo { + + public static void main(String[] args) { + for (int i = 0; i < 20_000; i++) { + test(i); + } + } + + static boolean test(int i) { + Class componentType; + if (i % 2 == 0) { + componentType = Object.class; + } else { + componentType = Integer.class; + } + Object array = Array.newInstance(componentType, 1); + return array.getClass() == Object[].class; + } +} \ No newline at end of file From 3dcf2a3bac491ba4344bde9701628c41b8b46749 Mon Sep 17 00:00:00 2001 From: Quan Anh Mai Date: Wed, 1 Apr 2026 06:59:27 +0000 Subject: [PATCH 135/359] 8379790: MemNode::can_see_stored_value incorrectly walks past barriers Reviewed-by: chagedorn, dfenacci --- src/hotspot/share/opto/memnode.cpp | 67 +++++++++++++++++------------- src/hotspot/share/opto/memnode.hpp | 1 + 2 files changed, 39 insertions(+), 29 deletions(-) diff --git a/src/hotspot/share/opto/memnode.cpp b/src/hotspot/share/opto/memnode.cpp index c8723d6ec0f..9ec3402c701 100644 --- a/src/hotspot/share/opto/memnode.cpp +++ b/src/hotspot/share/opto/memnode.cpp @@ -1156,40 +1156,38 @@ Node* LoadNode::can_see_arraycopy_value(Node* st, PhaseGVN* phase) const { return nullptr; } - -//---------------------------can_see_stored_value------------------------------ // This routine exists to make sure this set of tests is done the same // everywhere. We need to make a coordinated change: first LoadNode::Ideal // will change the graph shape in a way which makes memory alive twice at the // same time (uses the Oracle model of aliasing), then some // LoadXNode::Identity will fold things back to the equivalence-class model // of aliasing. -Node* MemNode::can_see_stored_value(Node* st, PhaseValues* phase) const { +Node* LoadNode::can_see_stored_value_through_membars(Node* st, PhaseValues* phase) const { Node* ld_adr = in(MemNode::Address); - intptr_t ld_off = 0; - Node* ld_base = AddPNode::Ideal_base_and_offset(ld_adr, phase, ld_off); - Node* ld_alloc = AllocateNode::Ideal_allocation(ld_base); const TypeInstPtr* tp = phase->type(ld_adr)->isa_instptr(); Compile::AliasType* atp = (tp != nullptr) ? phase->C->alias_type(tp) : nullptr; - // This is more general than load from boxing objects. + if (skip_through_membars(atp, tp, phase->C->eliminate_boxing())) { uint alias_idx = atp->index(); Node* result = nullptr; Node* current = st; - // Skip through chains of MemBarNodes checking the MergeMems for - // new states for the slice of this load. Stop once any other - // kind of node is encountered. Loads from final memory can skip - // through any kind of MemBar but normal loads shouldn't skip - // through MemBarAcquire since the could allow them to move out of - // a synchronized region. It is not safe to step over MemBarCPUOrder, - // because alias info above them may be inaccurate (e.g., due to - // mixed/mismatched unsafe accesses). + // Skip through chains of MemBarNodes checking the MergeMems for new states for the slice of + // this load. Stop once any other kind of node is encountered. + // + // In principle, folding a load is moving it up until it meets a matching store. + // + // store(ptr, v); store(ptr, v); store(ptr, v); + // membar1; -> membar1; -> load(ptr); + // membar2; load(ptr); membar1; + // load(ptr); membar2; membar2; + // + // So, we can decide which kinds of barriers we can walk past. It is not safe to step over + // MemBarCPUOrder, even if the memory is not rewritable, because alias info above them may be + // inaccurate (e.g., due to mixed/mismatched unsafe accesses). bool is_final_mem = !atp->is_rewritable(); while (current->is_Proj()) { int opc = current->in(0)->Opcode(); - if ((is_final_mem && (opc == Op_MemBarAcquire || - opc == Op_MemBarAcquireLock || - opc == Op_LoadFence)) || + if ((is_final_mem && (opc == Op_MemBarAcquire || opc == Op_MemBarAcquireLock || opc == Op_LoadFence)) || opc == Op_MemBarRelease || opc == Op_StoreFence || opc == Op_MemBarReleaseLock || @@ -1216,6 +1214,17 @@ Node* MemNode::can_see_stored_value(Node* st, PhaseValues* phase) const { } } + return can_see_stored_value(st, phase); +} + +// If st is a store to the same location as this, return the stored value +Node* MemNode::can_see_stored_value(Node* st, PhaseValues* phase) const { + Node* ld_adr = in(MemNode::Address); + intptr_t ld_off = 0; + Node* ld_base = AddPNode::Ideal_base_and_offset(ld_adr, phase, ld_off); + Node* ld_alloc = AllocateNode::Ideal_allocation(ld_base); + const TypeInstPtr* tp = phase->type(ld_adr)->isa_instptr(); + // Loop around twice in the case Load -> Initialize -> Store. // (See PhaseIterGVN::add_users_to_worklist, which knows about this case.) for (int trip = 0; trip <= 1; trip++) { @@ -1344,7 +1353,7 @@ Node* LoadNode::Identity(PhaseGVN* phase) { // If the previous store-maker is the right kind of Store, and the store is // to the same address, then we are equal to the value stored. Node* mem = in(Memory); - Node* value = can_see_stored_value(mem, phase); + Node* value = can_see_stored_value_through_membars(mem, phase); if( value ) { // byte, short & char stores truncate naturally. // A load has to load the truncated value which requires @@ -2042,7 +2051,7 @@ Node *LoadNode::Ideal(PhaseGVN *phase, bool can_reshape) { // (c) See if we can fold up on the spot, but don't fold up here. // Fold-up might require truncation (for LoadB/LoadS/LoadUS) or // just return a prior value, which is done by Identity calls. - if (can_see_stored_value(prev_mem, phase)) { + if (can_see_stored_value_through_membars(prev_mem, phase)) { // Make ready for step (d): set_req_X(MemNode::Memory, prev_mem, phase); return this; @@ -2099,7 +2108,7 @@ const Type* LoadNode::Value(PhaseGVN* phase) const { Compile* C = phase->C; // If load can see a previous constant store, use that. - Node* value = can_see_stored_value(mem, phase); + Node* value = can_see_stored_value_through_membars(mem, phase); if (value != nullptr && value->is_Con()) { assert(value->bottom_type()->higher_equal(_type), "sanity"); return value->bottom_type(); @@ -2350,7 +2359,7 @@ uint LoadNode::match_edge(uint idx) const { // Node* LoadBNode::Ideal(PhaseGVN* phase, bool can_reshape) { Node* mem = in(MemNode::Memory); - Node* value = can_see_stored_value(mem,phase); + Node* value = can_see_stored_value_through_membars(mem, phase); if (value != nullptr) { Node* narrow = Compile::narrow_value(T_BYTE, value, _type, phase, false); if (narrow != value) { @@ -2363,7 +2372,7 @@ Node* LoadBNode::Ideal(PhaseGVN* phase, bool can_reshape) { const Type* LoadBNode::Value(PhaseGVN* phase) const { Node* mem = in(MemNode::Memory); - Node* value = can_see_stored_value(mem,phase); + Node* value = can_see_stored_value_through_membars(mem, phase); if (value != nullptr && value->is_Con() && !value->bottom_type()->higher_equal(_type)) { // If the input to the store does not fit with the load's result type, @@ -2384,7 +2393,7 @@ const Type* LoadBNode::Value(PhaseGVN* phase) const { // Node* LoadUBNode::Ideal(PhaseGVN* phase, bool can_reshape) { Node* mem = in(MemNode::Memory); - Node* value = can_see_stored_value(mem, phase); + Node* value = can_see_stored_value_through_membars(mem, phase); if (value != nullptr) { Node* narrow = Compile::narrow_value(T_BOOLEAN, value, _type, phase, false); if (narrow != value) { @@ -2397,7 +2406,7 @@ Node* LoadUBNode::Ideal(PhaseGVN* phase, bool can_reshape) { const Type* LoadUBNode::Value(PhaseGVN* phase) const { Node* mem = in(MemNode::Memory); - Node* value = can_see_stored_value(mem,phase); + Node* value = can_see_stored_value_through_membars(mem, phase); if (value != nullptr && value->is_Con() && !value->bottom_type()->higher_equal(_type)) { // If the input to the store does not fit with the load's result type, @@ -2418,7 +2427,7 @@ const Type* LoadUBNode::Value(PhaseGVN* phase) const { // Node* LoadUSNode::Ideal(PhaseGVN* phase, bool can_reshape) { Node* mem = in(MemNode::Memory); - Node* value = can_see_stored_value(mem,phase); + Node* value = can_see_stored_value_through_membars(mem, phase); if (value != nullptr) { Node* narrow = Compile::narrow_value(T_CHAR, value, _type, phase, false); if (narrow != value) { @@ -2431,7 +2440,7 @@ Node* LoadUSNode::Ideal(PhaseGVN* phase, bool can_reshape) { const Type* LoadUSNode::Value(PhaseGVN* phase) const { Node* mem = in(MemNode::Memory); - Node* value = can_see_stored_value(mem,phase); + Node* value = can_see_stored_value_through_membars(mem, phase); if (value != nullptr && value->is_Con() && !value->bottom_type()->higher_equal(_type)) { // If the input to the store does not fit with the load's result type, @@ -2452,7 +2461,7 @@ const Type* LoadUSNode::Value(PhaseGVN* phase) const { // Node* LoadSNode::Ideal(PhaseGVN* phase, bool can_reshape) { Node* mem = in(MemNode::Memory); - Node* value = can_see_stored_value(mem,phase); + Node* value = can_see_stored_value_through_membars(mem, phase); if (value != nullptr) { Node* narrow = Compile::narrow_value(T_SHORT, value, _type, phase, false); if (narrow != value) { @@ -2465,7 +2474,7 @@ Node* LoadSNode::Ideal(PhaseGVN* phase, bool can_reshape) { const Type* LoadSNode::Value(PhaseGVN* phase) const { Node* mem = in(MemNode::Memory); - Node* value = can_see_stored_value(mem,phase); + Node* value = can_see_stored_value_through_membars(mem, phase); if (value != nullptr && value->is_Con() && !value->bottom_type()->higher_equal(_type)) { // If the input to the store does not fit with the load's result type, diff --git a/src/hotspot/share/opto/memnode.hpp b/src/hotspot/share/opto/memnode.hpp index 7fa238f574d..8efb5521e7c 100644 --- a/src/hotspot/share/opto/memnode.hpp +++ b/src/hotspot/share/opto/memnode.hpp @@ -266,6 +266,7 @@ protected: const Type* const _type; // What kind of value is loaded? virtual Node* find_previous_arraycopy(PhaseValues* phase, Node* ld_alloc, Node*& mem, bool can_see_stored_value) const; + Node* can_see_stored_value_through_membars(Node* st, PhaseValues* phase) const; public: LoadNode(Node *c, Node *mem, Node *adr, const TypePtr* at, const Type *rt, MemOrd mo, ControlDependency control_dependency) From 32e8aa45828a7dbaf5ed558efd5870c9c5a149de Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Wed, 1 Apr 2026 07:47:17 +0000 Subject: [PATCH 136/359] 8379811: Disable AOTCodeCache if Assembly intrinsics use differs from Production use Reviewed-by: kvn, asmehra --- src/hotspot/share/code/aotCodeCache.cpp | 312 ++++++++++++++++++++++-- src/hotspot/share/code/aotCodeCache.hpp | 94 ++++++- 2 files changed, 384 insertions(+), 22 deletions(-) diff --git a/src/hotspot/share/code/aotCodeCache.cpp b/src/hotspot/share/code/aotCodeCache.cpp index 030e2684bfc..938cf4eaa41 100644 --- a/src/hotspot/share/code/aotCodeCache.cpp +++ b/src/hotspot/share/code/aotCodeCache.cpp @@ -380,37 +380,110 @@ void AOTCodeCache::init_early_c1_table() { } } +// macro to record which flags are set -- flag_type selects the +// relevant accessor e.g. set_flag, set_x86_flag, set_x86_use_flag. +// n.b. flag_enum_name and global_flag_name are both needed because we +// don't have consistent conventions for naming global flags e.g. +// EnableContended vs UseMulAddIntrinsic vs UseCRC32Intrinsics + +#define RECORD_FLAG(flag_type, flag_enum_name, global_flag_name) \ + if (global_flag_name) { \ + set_ ## flag_type ## flag(flag_enum_name); \ + } + void AOTCodeCache::Config::record(uint cpu_features_offset) { _flags = 0; #ifdef ASSERT - _flags |= debugVM; + set_flag(debugVM); #endif - if (UseCompressedOops) { - _flags |= compressedOops; - } - if (UseTLAB) { - _flags |= useTLAB; - } + RECORD_FLAG(, compressedOops, UseCompressedOops); + RECORD_FLAG(, useTLAB, UseTLAB); if (JavaAssertions::systemClassDefault()) { - _flags |= systemClassAssertions; + set_flag(systemClassAssertions); } if (JavaAssertions::userClassDefault()) { - _flags |= userClassAssertions; - } - if (EnableContended) { - _flags |= enableContendedPadding; - } - if (RestrictContended) { - _flags |= restrictContendedPadding; + set_flag(userClassAssertions); } + RECORD_FLAG(, enableContendedPadding, EnableContended); + RECORD_FLAG(, restrictContendedPadding, RestrictContended); + _compressedOopShift = CompressedOops::shift(); _compressedOopBase = CompressedOops::base(); _compressedKlassShift = CompressedKlassPointers::shift(); _contendedPaddingWidth = ContendedPaddingWidth; _gc = (uint)Universe::heap()->kind(); + _optoLoopAlignment = (uint)OptoLoopAlignment; + _codeEntryAlignment = (uint)CodeEntryAlignment; + _allocatePrefetchLines = (uint)AllocatePrefetchLines; + _allocateInstancePrefetchLines = (uint)AllocateInstancePrefetchLines; + _allocatePrefetchDistance = (uint)AllocatePrefetchDistance; + _allocatePrefetchStepSize = (uint)AllocatePrefetchStepSize; + _use_intrinsics_flags = 0; + RECORD_FLAG(use_, useCRC32, UseCRC32Intrinsics); + RECORD_FLAG(use_, useCRC32C, UseCRC32CIntrinsics); +#ifdef COMPILER2 + _maxVectorSize = (uint)MaxVectorSize; + _arrayOperationPartialInlineSize = (uint)ArrayOperationPartialInlineSize; + RECORD_FLAG(use_, useMultiplyToLen, UseMultiplyToLenIntrinsic); + RECORD_FLAG(use_, useSquareToLen, UseSquareToLenIntrinsic); + RECORD_FLAG(use_, useMulAdd, UseMulAddIntrinsic); + RECORD_FLAG(use_, useMontgomeryMultiply, UseMontgomeryMultiplyIntrinsic); + RECORD_FLAG(use_, useMontgomerySquare, UseMontgomerySquareIntrinsic); +#endif // COMPILER2 + RECORD_FLAG(use_, useChaCha20, UseChaCha20Intrinsics); + RECORD_FLAG(use_, useDilithium, UseDilithiumIntrinsics); + RECORD_FLAG(use_, useKyber, UseKyberIntrinsics); + RECORD_FLAG(use_, useBASE64, UseBASE64Intrinsics); + RECORD_FLAG(use_, useAdler32, UseAdler32Intrinsics); + RECORD_FLAG(use_, useAES, UseAESIntrinsics); + RECORD_FLAG(use_, useAESCTR, UseAESCTRIntrinsics); + RECORD_FLAG(use_, useGHASH, UseGHASHIntrinsics); + RECORD_FLAG(use_, useMD5, UseMD5Intrinsics); + RECORD_FLAG(use_, useSHA1, UseSHA1Intrinsics); + RECORD_FLAG(use_, useSHA256, UseSHA256Intrinsics); + RECORD_FLAG(use_, useSHA512, UseSHA512Intrinsics); + RECORD_FLAG(use_, useSHA3, UseSHA3Intrinsics); + RECORD_FLAG(use_, usePoly1305, UsePoly1305Intrinsics); + RECORD_FLAG(use_, useVectorizedMismatch,UseVectorizedMismatchIntrinsic ); + RECORD_FLAG(use_, useSecondarySupersTable, UseSecondarySupersTable); +#if defined(X86) && !defined(ZERO) + _avx3threshold = (uint)AVX3Threshold; + _useAVX = (uint)UseAVX; + _x86_flags = 0; + RECORD_FLAG(x86_, x86_enableX86ECoreOpts, EnableX86ECoreOpts); + RECORD_FLAG(x86_, x86_useUnalignedLoadStores, UseUnalignedLoadStores); + RECORD_FLAG(x86_, x86_useAPX, UseAPX); + + _x86_use_intrinsics_flags = 0; + RECORD_FLAG(x86_use_, x86_useLibm, UseLibmIntrinsic); + RECORD_FLAG(x86_use_, x86_useIntPoly, UseIntPolyIntrinsics); +#endif // defined(X86) && !defined(ZERO) +#if defined(AARCH64) && !defined(ZERO) + _prefetchCopyIntervalInBytes = (uint)PrefetchCopyIntervalInBytes; + _blockZeroingLowLimit = (uint)BlockZeroingLowLimit; + _softwarePrefetchHintDistance = (uint)SoftwarePrefetchHintDistance; + _useSVE = (uint)UseSVE; + _aarch64_flags = 0; + RECORD_FLAG(aarch64_, aarch64_avoidUnalignedAccesses, AvoidUnalignedAccesses); + RECORD_FLAG(aarch64_, aarch64_useSIMDForMemoryOps, UseSIMDForMemoryOps); + RECORD_FLAG(aarch64_, aarch64_useSIMDForArrayEquals, UseSIMDForArrayEquals); + RECORD_FLAG(aarch64_, aarch64_useSIMDForSHA3, UseSIMDForSHA3Intrinsic); + RECORD_FLAG(aarch64_, aarch64_useLSE, UseLSE); + + _aarch64_use_intrinsics_flags = 0; + RECORD_FLAG(aarch64_use_, aarch64_useBlockZeroing, UseBlockZeroing); + RECORD_FLAG(aarch64_use_, aarch64_useSIMDForBigIntegerShift, UseSIMDForBigIntegerShiftIntrinsics); + RECORD_FLAG(aarch64_use_, aarch64_useSimpleArrayEquals, UseSimpleArrayEquals); + RECORD_FLAG(aarch64_use_, aarch64_useSecondarySupersCache, UseSecondarySupersCache); +#endif // defined(AARCH64) && !defined(ZERO) +#if INCLUDE_JVMCI + _enableJVMCI = (uint)EnableJVMCI; +#endif _cpu_features_offset = cpu_features_offset; } +#undef RECORD_FLAG + bool AOTCodeCache::Config::verify_cpu_features(AOTCodeCache* cache) const { LogStreamHandle(Debug, aot, codecache, init) log; uint offset = _cpu_features_offset; @@ -451,15 +524,27 @@ bool AOTCodeCache::Config::verify_cpu_features(AOTCodeCache* cache) const { return true; } +// macro to do *standard* flag eq checks -- flag_type selects the +// relevant accessor e.g. test_flag, test_x86_flag, test_x86_use_flag. +// n.b. flag_enum_name and global_flag_name are both needed because we +// don't have consistent conventions for naming global flags e.g. +// EnableContended vs UseMulAddIntrinsic vs UseCRC32Intrinsics + +#define CHECK_FLAG(flag_type, flag_enum_name, global_flag_name) \ + if (test_ ## flag_type ## flag(flag_enum_name) != global_flag_name) { \ + log_debug(aot, codecache, init)("AOT Code Cache disabled: it was created with " # global_flag_name " = %s vs current %s" , (global_flag_name ? "false" : "true"), (global_flag_name ? "true" : "false")); \ + return false; \ + } + bool AOTCodeCache::Config::verify(AOTCodeCache* cache) const { // First checks affect all cached AOT code #ifdef ASSERT - if ((_flags & debugVM) == 0) { + if (!test_flag(debugVM)) { log_debug(aot, codecache, init)("AOT Code Cache disabled: it was created by product VM, it can't be used by debug VM"); return false; } #else - if ((_flags & debugVM) != 0) { + if (test_flag(debugVM)) { log_debug(aot, codecache, init)("AOT Code Cache disabled: it was created by debug VM, it can't be used by product VM"); return false; } @@ -476,9 +561,195 @@ bool AOTCodeCache::Config::verify(AOTCodeCache* cache) const { return false; } + // check CPU features before checking flags that may be + // auto-configured in response to them + if (!verify_cpu_features(cache)) { + return false; + } + + // change to EnableContended can affect validity of nmethods + CHECK_FLAG(, enableContendedPadding, EnableContended); + // change to RestrictContended can affect validity of nmethods + CHECK_FLAG(, restrictContendedPadding, RestrictContended); + + // Tests for config options which might affect validity of adapters, + // stubs or nmethods. Currently we take a pessemistic stand and + // drop the whole cache if any of these are changed. + + // change to opto alignment can affect performance of array copy + // stubs and nmethods + if (_optoLoopAlignment != (uint)OptoLoopAlignment) { + log_debug(aot, codecache, init)("AOT Code Cache disabled: it was created with OptoLoopAlignment = %d vs current %d", (int)_optoLoopAlignment, (int)OptoLoopAlignment); + return false; + } + + // change to CodeEntryAlignment can affect performance of array + // copy stubs and nmethods + if (_codeEntryAlignment != CodeEntryAlignment) { + log_debug(aot, codecache, init)("AOT Code Cache disabled: it was created with CodeEntryAlignment = %d vs current %d", _codeEntryAlignment, CodeEntryAlignment); + return false; + } + + // changing Prefetch configuration can affect validity of nmethods + // and stubs + if (_allocatePrefetchLines != (uint)AllocatePrefetchLines) { + log_debug(aot, codecache, init)("AOT Code Cache disabled: it was created with = %d vs current %d", (int)_allocatePrefetchLines, (int)AllocatePrefetchLines); + return false; + } + if (_allocateInstancePrefetchLines != (uint)AllocateInstancePrefetchLines) { + log_debug(aot, codecache, init)("AOT Code Cache disabled: it was created with = %d vs current %d", (int)_allocateInstancePrefetchLines, (int)AllocateInstancePrefetchLines); + return false; + } + if (_allocatePrefetchDistance != (uint)AllocatePrefetchDistance) { + log_debug(aot, codecache, init)("AOT Code Cache disabled: it was created with = %d vs current %d", (int)_allocatePrefetchDistance, (int)AllocatePrefetchDistance); + return false; + } + if (_allocatePrefetchStepSize != (uint)AllocatePrefetchStepSize) { + log_debug(aot, codecache, init)("AOT Code Cache disabled: it was created with = %d vs current %d", (int)_allocatePrefetchStepSize, (int)AllocatePrefetchStepSize); + return false; + } + + // check intrinsic use settings are compatible + + CHECK_FLAG(use_, useCRC32, UseCRC32Intrinsics); + CHECK_FLAG(use_, useCRC32C, UseCRC32CIntrinsics); + +#ifdef COMPILER2 + // change to MaxVectorSize can affect validity of array copy/fill + // stubs + if (_maxVectorSize != (uint)MaxVectorSize) { + log_debug(aot, codecache, init)("AOT Code Cache disabled: it was created with MaxVectorSize = %d vs current %d", (int)_maxVectorSize, (int)MaxVectorSize); + return false; + } + + // changing ArrayOperationPartialInlineSize can affect validity of + // nmethods and stubs + if (_arrayOperationPartialInlineSize != (uint)ArrayOperationPartialInlineSize) { + log_debug(aot, codecache, init)("AOT Code Cache disabled: it was created with ArrayOperationPartialInlineSize = %d vs current %d", (int)_arrayOperationPartialInlineSize, (int)ArrayOperationPartialInlineSize); + return false; + } + CHECK_FLAG(use_, useMultiplyToLen, UseMultiplyToLenIntrinsic); + CHECK_FLAG(use_, useSquareToLen, UseSquareToLenIntrinsic); + CHECK_FLAG(use_, useMulAdd, UseMulAddIntrinsic); + CHECK_FLAG(use_, useMontgomeryMultiply,UseMontgomeryMultiplyIntrinsic); + CHECK_FLAG(use_, useMontgomerySquare, UseMontgomerySquareIntrinsic); +#endif // COMPILER2 + CHECK_FLAG(use_, useChaCha20, UseChaCha20Intrinsics); + CHECK_FLAG(use_, useDilithium, UseDilithiumIntrinsics); + CHECK_FLAG(use_, useKyber, UseKyberIntrinsics); + CHECK_FLAG(use_, useBASE64, UseBASE64Intrinsics); + CHECK_FLAG(use_, useAES, UseAESIntrinsics); + CHECK_FLAG(use_, useAESCTR, UseAESCTRIntrinsics); + CHECK_FLAG(use_, useGHASH, UseGHASHIntrinsics); + CHECK_FLAG(use_, useMD5, UseMD5Intrinsics); + CHECK_FLAG(use_, useSHA1, UseSHA1Intrinsics); + CHECK_FLAG(use_, useSHA256, UseSHA256Intrinsics); + CHECK_FLAG(use_, useSHA512, UseSHA512Intrinsics); + CHECK_FLAG(use_, useSHA3, UseSHA3Intrinsics); + CHECK_FLAG(use_, usePoly1305, UsePoly1305Intrinsics); + CHECK_FLAG(use_, useVectorizedMismatch, UseVectorizedMismatchIntrinsic); + CHECK_FLAG(use_, useSecondarySupersTable, UseSecondarySupersTable); + +#if defined(X86) && !defined(ZERO) + // change to AVX3Threshold may affect validity of array copy stubs + // and nmethods + if (_avx3threshold != (uint)AVX3Threshold) { + log_debug(aot, codecache, init)("AOT Code Cache disabled: it was created with AVX3Threshold = %d vs current %d", (int)_avx3threshold, AVX3Threshold); + return false; + } + + // change to UseAVX may affect validity of array copy stubs and + // nmethods + if (_useAVX != (uint)UseAVX) { + log_debug(aot, codecache, init)("AOT Code Cache disabled: it was created with useAVX = %d vs current %d", (int)_useAVX, UseAVX); + return false; + } + + // change to EnableX86ECoreOpts may affect validity of nmethods + CHECK_FLAG(x86_, x86_enableX86ECoreOpts, EnableX86ECoreOpts); + + // switching off UseUnalignedLoadStores can affect validity of fill + // stubs + if (test_x86_flag(x86_useUnalignedLoadStores) && !UseUnalignedLoadStores) { + log_debug(aot, codecache, init)("AOT Code Cache disabled: it was created with UseUnalignedLoadStores = true vs current = false"); + return false; + } + + // change to UseAPX can affect validity of nmethods and stubs + CHECK_FLAG(x86_, x86_useAPX, UseAPX); + + // check x86-specific intrinsic use settings are compatible + + CHECK_FLAG(x86_use_, x86_useLibm, UseLibmIntrinsic); + CHECK_FLAG(x86_use_, x86_useIntPoly, UseIntPolyIntrinsics); +#endif // defined(X86) && !defined(ZERO) + +#if defined(AARCH64) && !defined(ZERO) + // change to PrefetchCopyIntervalInBytes may affect validity of + // array copy stubs + if (_prefetchCopyIntervalInBytes != (uint)PrefetchCopyIntervalInBytes) { + log_debug(aot, codecache, init)("AOT Code Cache disabled: it was created with PrefetchCopyIntervalInBytes = %d vs current %d", (int)_prefetchCopyIntervalInBytes, (int)PrefetchCopyIntervalInBytes); + return false; + } + + // change to BlockZeroingLowLimit may affect validity of array fill + // stubs + if (_blockZeroingLowLimit != (uint)BlockZeroingLowLimit) { + log_debug(aot, codecache, init)("AOT Code Cache disabled: it was created with BlockZeroingLowLimit = %d vs current %d", (int)_blockZeroingLowLimit, (int)BlockZeroingLowLimit); + return false; + } + + // change to SoftwarePrefetchHintDistance may affect validity of array fill + // stubs + if (_softwarePrefetchHintDistance != (uint)SoftwarePrefetchHintDistance) { + log_debug(aot, codecache, init)("AOT Code Cache disabled: it was created with SoftwarePrefetchHintDistance = %d vs current %d", (int)_softwarePrefetchHintDistance, (int)SoftwarePrefetchHintDistance); + return false; + } + + // change to UseSVE may affect validity of stubs and nmethods + if (_useSVE != (uint)UseSVE) { + log_debug(aot, codecache, init)("AOT Code Cache disabled: it was created with UseSVE = %d vs current %d",(int)_useSVE, UseSVE); + return false; + } + + // switching on AvoidUnalignedAccesses may affect validity of array + // copy stubs and nmethods + if (!test_aarch64_flag(aarch64_avoidUnalignedAccesses) && AvoidUnalignedAccesses) { + log_debug(aot, codecache, init)("AOT Code Cache disabled: it was created with AvoidUnalignedAccesses = false vs current = true"); + return false; + } + + // change to UseSIMDForMemoryOps may affect validity of array + // copy stubs and nmethods + CHECK_FLAG(aarch64_, aarch64_useSIMDForMemoryOps, UseSIMDForMemoryOps); + // change to UseSIMDForArrayEquals may affect validity of array + // copy stubs and nmethods + CHECK_FLAG(aarch64_, aarch64_useSIMDForArrayEquals, UseSIMDForArrayEquals); + // change to useSIMDForSHA3 may affect validity of SHA3 stubs + CHECK_FLAG(aarch64_, aarch64_useSIMDForSHA3, UseSIMDForSHA3Intrinsic); + // change to UseLSE may affect validity of stubs and nmethods + CHECK_FLAG(aarch64_, aarch64_useLSE, UseLSE); + + // check aarch64-specific intrinsic use settings are compatible + + CHECK_FLAG(aarch64_use_, aarch64_useBlockZeroing, UseBlockZeroing); + CHECK_FLAG(aarch64_use_, aarch64_useSIMDForBigIntegerShift, UseSIMDForBigIntegerShiftIntrinsics); + CHECK_FLAG(aarch64_use_, aarch64_useSimpleArrayEquals, UseSimpleArrayEquals); + CHECK_FLAG(aarch64_use_, aarch64_useSecondarySupersCache, UseSecondarySupersCache); +#endif // defined(AARCH64) && !defined(ZERO) + +#if INCLUDE_JVMCI + // change to EnableJVMCI will affect validity of adapters and + // nmethods + if (_enableJVMCI != (uint)EnableJVMCI) { + log_debug(aot, codecache, init)("AOT Code Cache disabled: it was created with EnableJVMCI = %s vs current %s", (_enableJVMCI ? "true" : "false"), (EnableJVMCI ? "true" : "false")); + return false; + } +#endif // INCLUDE_JVMCI + // The following checks do not affect AOT adapters caching - if (((_flags & compressedOops) != 0) != UseCompressedOops) { + if (test_flag(compressedOops) != UseCompressedOops) { log_debug(aot, codecache, init)("AOT Code Cache disabled: it was created with UseCompressedOops = %s", UseCompressedOops ? "false" : "true"); AOTStubCaching = false; } @@ -493,12 +764,11 @@ bool AOTCodeCache::Config::verify(AOTCodeCache* cache) const { AOTStubCaching = false; } - if (!verify_cpu_features(cache)) { - return false; - } return true; } +#undef TEST_FLAG + bool AOTCodeCache::Header::verify(uint load_size) const { if (_version != AOT_CODE_VERSION) { log_debug(aot, codecache, init)("AOT Code Cache disabled: different AOT Code version %d vs %d recorded in AOT Code header", AOT_CODE_VERSION, _version); diff --git a/src/hotspot/share/code/aotCodeCache.hpp b/src/hotspot/share/code/aotCodeCache.hpp index b0d39ff3e08..52b0adfba48 100644 --- a/src/hotspot/share/code/aotCodeCache.hpp +++ b/src/hotspot/share/code/aotCodeCache.hpp @@ -173,6 +173,16 @@ protected: uint _compressedKlassShift; uint _contendedPaddingWidth; uint _gc; + uint _optoLoopAlignment; + uint _codeEntryAlignment; + uint _allocatePrefetchLines; + uint _allocateInstancePrefetchLines; + uint _allocatePrefetchDistance; + uint _allocatePrefetchStepSize; +#ifdef COMPILER2 + uint _maxVectorSize; + uint _arrayOperationPartialInlineSize; +#endif // COMPILER2 enum Flags { none = 0, debugVM = 1, @@ -184,8 +194,90 @@ protected: restrictContendedPadding = 64 }; uint _flags; + enum IntrinsicsUseFlags { + use_none = 0, + useCRC32 = 1 << 0, + useCRC32C = 1 << 1, + useMultiplyToLen = 1 << 2, + useSquareToLen = 1 << 3, + useMulAdd = 1 << 4, + useMontgomeryMultiply = 1 << 5, + useMontgomerySquare = 1 << 6, + useChaCha20 = 1 << 7, + useDilithium = 1 << 8, + useKyber = 1 << 9, + useBASE64 = 1 << 10, + useAdler32 = 1 << 11, + useAES = 1 << 12, + useAESCTR = 1 << 13, + useGHASH = 1 << 14, + useMD5 = 1 << 15, + useSHA1 = 1 << 16, + useSHA256 = 1 << 17, + useSHA512 = 1 << 18, + useSHA3 = 1 << 19, + usePoly1305 = 1 << 20, + useVectorizedMismatch = 1 << 21, + useSecondarySupersTable = 1 << 22, + }; + uint _use_intrinsics_flags; + bool test_flag(enum Flags flag) const { return (_flags & flag) != 0; } + bool test_use_flag(enum IntrinsicsUseFlags flag) const { return (_use_intrinsics_flags & flag) != 0; } + void set_flag(enum Flags flag) { _flags |= flag; } + void set_use_flag(enum IntrinsicsUseFlags flag) { _use_intrinsics_flags |= flag; } +#if defined(X86) && !defined(ZERO) + uint _avx3threshold; + uint _useAVX; + enum X86Flags { + x86_none = 0, + x86_enableX86ECoreOpts = 1, + x86_useUnalignedLoadStores = 2, + x86_useAPX = 4 + }; + uint _x86_flags; + enum X86IntrinsicsUseFlags { + x86_use_none = 0, + x86_useLibm = 1 << 1, + x86_useIntPoly = 1 << 2, + }; + uint _x86_use_intrinsics_flags; + bool test_x86_flag(enum X86Flags flag) const { return (_x86_flags & flag) != 0; } + bool test_x86_use_flag(enum X86IntrinsicsUseFlags flag) const { return (_x86_use_intrinsics_flags & flag) != 0; } + void set_x86_flag(enum X86Flags flag) { _x86_flags |= flag; } + void set_x86_use_flag(enum X86IntrinsicsUseFlags flag) { _x86_use_intrinsics_flags |= flag; } +#endif // defined(X86) && !defined(ZERO) +#if defined(AARCH64) && !defined(ZERO) + // this is global but x86 does not use it and aarch64 does + uint _prefetchCopyIntervalInBytes; + uint _blockZeroingLowLimit; + uint _softwarePrefetchHintDistance; + uint _useSVE; + enum AArch64Flags { + aarch64_none = 0, + aarch64_avoidUnalignedAccesses = 1, + aarch64_useSIMDForMemoryOps = 2, + aarch64_useSIMDForArrayEquals = 4, + aarch64_useSIMDForSHA3 = 8, + aarch64_useLSE = 16, + }; + uint _aarch64_flags; + enum AArch64IntrinsicsUseFlags { + aarch64_use_none = 0, + aarch64_useBlockZeroing = 1 << 0, + aarch64_useSIMDForBigIntegerShift = 1 << 1, + aarch64_useSimpleArrayEquals = 1 << 2, + aarch64_useSecondarySupersCache = 1 << 3, + }; + uint _aarch64_use_intrinsics_flags; + bool test_aarch64_flag(enum AArch64Flags flag) const { return (_aarch64_flags & flag) != 0; } + bool test_aarch64_use_flag(enum AArch64IntrinsicsUseFlags flag) const { return (_aarch64_use_intrinsics_flags & flag) != 0; } + void set_aarch64_flag(enum AArch64Flags flag) { _aarch64_flags |= flag; } + void set_aarch64_use_flag(enum AArch64IntrinsicsUseFlags flag) { _aarch64_use_intrinsics_flags |= flag; } +#endif // defined(AARCH64) && !defined(ZERO) +#if INCLUDE_JVMCI + uint _enableJVMCI; +#endif // INCLUDE_JVMCI uint _cpu_features_offset; // offset in the cache where cpu features are stored - public: void record(uint cpu_features_offset); bool verify_cpu_features(AOTCodeCache* cache) const; From b58d1ad1ee9aa30d97286b3b78054488e083c351 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Wed, 1 Apr 2026 08:14:59 +0000 Subject: [PATCH 137/359] 8372016: G1: Root scanning not yielding to safepoints causes crashes Reviewed-by: iwalulya, ayang --- src/hotspot/share/gc/g1/g1CollectedHeap.cpp | 1 + src/hotspot/share/gc/g1/g1ConcurrentMark.cpp | 212 +++++++++--------- src/hotspot/share/gc/g1/g1ConcurrentMark.hpp | 71 +++--- .../share/gc/g1/g1ConcurrentMarkThread.cpp | 7 +- src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp | 6 +- src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp | 10 +- src/hotspot/share/gc/g1/g1VMOperations.cpp | 5 +- src/hotspot/share/gc/g1/g1YoungCollector.cpp | 18 +- src/hotspot/share/gc/g1/g1YoungCollector.hpp | 2 +- src/hotspot/share/runtime/mutexLocker.cpp | 2 - src/hotspot/share/runtime/mutexLocker.hpp | 1 - 11 files changed, 165 insertions(+), 170 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index e6dd91df84b..fe286793ae7 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -1652,6 +1652,7 @@ jint G1CollectedHeap::initialize() { } void G1CollectedHeap::stop() { + assert_not_at_safepoint(); // Stop all concurrent threads. We do this to make sure these threads // do not continue to execute and access resources (e.g. logging) // that are destroyed during shutdown. diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp index 1caa8dbdd06..84a0b7588ef 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp @@ -372,63 +372,56 @@ void G1CMMarkStack::set_empty() { G1CMRootMemRegions::G1CMRootMemRegions(uint const max_regions) : _root_regions(MemRegion::create_array(max_regions, mtGC)), _max_regions(max_regions), - _num_root_regions(0), - _claimed_root_regions(0), - _scan_in_progress(false), - _should_abort(false) { } + _num_regions(0), + _num_claimed_regions(0) { } G1CMRootMemRegions::~G1CMRootMemRegions() { MemRegion::destroy_array(_root_regions, _max_regions); } void G1CMRootMemRegions::reset() { - _num_root_regions.store_relaxed(0); + assert_at_safepoint(); + assert(G1CollectedHeap::heap()->collector_state()->is_in_concurrent_start_gc(), "must be"); + + _num_regions.store_relaxed(0); + _num_claimed_regions.store_relaxed(0); } void G1CMRootMemRegions::add(HeapWord* start, HeapWord* end) { assert_at_safepoint(); - size_t idx = _num_root_regions.fetch_then_add(1u); - assert(idx < _max_regions, "Trying to add more root MemRegions than there is space %zu", _max_regions); + uint idx = _num_regions.fetch_then_add(1u); + assert(idx < _max_regions, "Trying to add more root MemRegions than there is space %u", _max_regions); assert(start != nullptr && end != nullptr && start <= end, "Start (" PTR_FORMAT ") should be less or equal to " "end (" PTR_FORMAT ")", p2i(start), p2i(end)); _root_regions[idx].set_start(start); _root_regions[idx].set_end(end); } -void G1CMRootMemRegions::prepare_for_scan() { - assert(!scan_in_progress(), "pre-condition"); - - _scan_in_progress.store_relaxed(num_root_regions() > 0); - - _claimed_root_regions.store_relaxed(0); - _should_abort.store_relaxed(false); -} - const MemRegion* G1CMRootMemRegions::claim_next() { - if (_should_abort.load_relaxed()) { - // If someone has set the should_abort flag, we return null to - // force the caller to bail out of their loop. + uint local_num_regions = num_regions(); + if (num_claimed_regions() >= local_num_regions) { return nullptr; } - uint local_num_root_regions = num_root_regions(); - if (_claimed_root_regions.load_relaxed() >= local_num_root_regions) { - return nullptr; - } - - size_t claimed_index = _claimed_root_regions.fetch_then_add(1u); - if (claimed_index < local_num_root_regions) { + uint claimed_index = _num_claimed_regions.fetch_then_add(1u); + if (claimed_index < local_num_regions) { return &_root_regions[claimed_index]; } return nullptr; } -uint G1CMRootMemRegions::num_root_regions() const { - return (uint)_num_root_regions.load_relaxed(); +bool G1CMRootMemRegions::work_completed() const { + return num_remaining_regions() == 0; +} + +uint G1CMRootMemRegions::num_remaining_regions() const { + uint total = num_regions(); + uint claimed = num_claimed_regions(); + return (total > claimed) ? total - claimed : 0; } bool G1CMRootMemRegions::contains(const MemRegion mr) const { - uint local_num_root_regions = num_root_regions(); + uint local_num_root_regions = num_regions(); for (uint i = 0; i < local_num_root_regions; i++) { if (_root_regions[i].equals(mr)) { return true; @@ -437,42 +430,6 @@ bool G1CMRootMemRegions::contains(const MemRegion mr) const { return false; } -void G1CMRootMemRegions::notify_scan_done() { - MutexLocker x(G1RootRegionScan_lock, Mutex::_no_safepoint_check_flag); - _scan_in_progress.store_relaxed(false); - G1RootRegionScan_lock->notify_all(); -} - -void G1CMRootMemRegions::cancel_scan() { - notify_scan_done(); -} - -void G1CMRootMemRegions::scan_finished() { - assert(scan_in_progress(), "pre-condition"); - - if (!_should_abort.load_relaxed()) { - assert(_claimed_root_regions.load_relaxed() >= num_root_regions(), - "we should have claimed all root regions, claimed %zu, length = %u", - _claimed_root_regions.load_relaxed(), num_root_regions()); - } - - notify_scan_done(); -} - -bool G1CMRootMemRegions::wait_until_scan_finished() { - if (!scan_in_progress()) { - return false; - } - - { - MonitorLocker ml(G1RootRegionScan_lock, Mutex::_no_safepoint_check_flag); - while (scan_in_progress()) { - ml.wait(); - } - } - return true; -} - G1ConcurrentMark::G1ConcurrentMark(G1CollectedHeap* g1h, G1RegionToSpaceMapper* bitmap_storage) : _cm_thread(nullptr), @@ -483,6 +440,7 @@ G1ConcurrentMark::G1ConcurrentMark(G1CollectedHeap* g1h, _heap(_g1h->reserved()), _root_regions(_g1h->max_num_regions()), + _root_region_scan_aborted(false), _global_mark_stack(), @@ -614,6 +572,7 @@ void G1ConcurrentMark::reset() { _region_mark_stats[i].clear(); } + _root_region_scan_aborted.store_relaxed(false); _root_regions.reset(); } @@ -970,8 +929,6 @@ void G1ConcurrentMark::start_full_concurrent_cycle() { satb_mq_set.set_active_all_threads(true, /* new active value */ false /* expected_active */); - _root_regions.prepare_for_scan(); - // update_g1_committed() will be called at the end of an evac pause // when marking is on. So, it's also called at the end of the // concurrent start pause to update the heap end, if the heap expands @@ -982,7 +939,11 @@ void G1ConcurrentMark::start_full_concurrent_cycle() { } void G1ConcurrentMark::start_undo_concurrent_cycle() { - root_regions()->cancel_scan(); + assert_at_safepoint_on_vm_thread(); + // At this time this GC is not a concurrent start gc any more, can only check for young only gc/phase. + assert(_g1h->collector_state()->is_in_young_only_phase(), "must be"); + + abort_root_region_scan_at_safepoint(); // Signal the thread to start work. cm_thread()->start_undo_cycle(); @@ -1094,6 +1055,16 @@ uint G1ConcurrentMark::calc_active_marking_workers() { return result; } +bool G1ConcurrentMark::has_root_region_scan_aborted() const { + return _root_region_scan_aborted.load_relaxed(); +} + +#ifndef PRODUCT +void G1ConcurrentMark::assert_root_region_scan_completed_or_aborted() { + assert(root_regions()->work_completed() || has_root_region_scan_aborted(), "must be"); +} +#endif + void G1ConcurrentMark::scan_root_region(const MemRegion* region, uint worker_id) { #ifdef ASSERT HeapWord* last = region->last(); @@ -1120,45 +1091,76 @@ void G1ConcurrentMark::scan_root_region(const MemRegion* region, uint worker_id) class G1CMRootRegionScanTask : public WorkerTask { G1ConcurrentMark* _cm; + bool _should_yield; + public: - G1CMRootRegionScanTask(G1ConcurrentMark* cm) : - WorkerTask("G1 Root Region Scan"), _cm(cm) { } + G1CMRootRegionScanTask(G1ConcurrentMark* cm, bool should_yield) : + WorkerTask("G1 Root Region Scan"), _cm(cm), _should_yield(should_yield) { } void work(uint worker_id) { - G1CMRootMemRegions* root_regions = _cm->root_regions(); - const MemRegion* region = root_regions->claim_next(); - while (region != nullptr) { + SuspendibleThreadSetJoiner sts_join(_should_yield); + + while (true) { + if (_cm->has_root_region_scan_aborted()) { + return; + } + G1CMRootMemRegions* root_regions = _cm->root_regions(); + const MemRegion* region = root_regions->claim_next(); + if (region == nullptr) { + return; + } _cm->scan_root_region(region, worker_id); - region = root_regions->claim_next(); + if (_should_yield) { + SuspendibleThreadSet::yield(); + // If we yielded, a GC may have processed all root regions, + // so this loop will naturally exit on the next claim_next() call. + // Same if a Full GC signalled abort of the concurrent mark. + } } } }; -void G1ConcurrentMark::scan_root_regions() { - // scan_in_progress() will have been set to true only if there was - // at least one root region to scan. So, if it's false, we - // should not attempt to do any further work. - if (root_regions()->scan_in_progress()) { - assert(!has_aborted(), "Aborting before root region scanning is finished not supported."); - +bool G1ConcurrentMark::scan_root_regions(WorkerThreads* workers, bool concurrent) { + // We first check whether there is any work to do as we might have already aborted + // the concurrent cycle, or ran into a GC that did the actual work when we reach here. + // We want to avoid spinning up the worker threads if that happened. + // (Note that due to races reading the abort-flag, we might spin up the threads anyway). + // + // Abort happens if a Full GC occurs right after starting the concurrent cycle or + // a young gc doing the work. + // + // Concurrent gc threads enter an STS when starting the task, so they stop, then + // continue after that safepoint. + bool do_scan = !root_regions()->work_completed() && !has_root_region_scan_aborted(); + if (do_scan) { // Assign one worker to each root-region but subject to the max constraint. - const uint num_workers = MIN2(root_regions()->num_root_regions(), + // The constraint is also important to avoid accesses beyond the allocated per-worker + // marking helper data structures. We might get passed different WorkerThreads with + // different number of threads (potential worker ids) than helper data structures when + // completing this work during GC. + const uint num_workers = MIN2(root_regions()->num_remaining_regions(), _max_concurrent_workers); + assert(num_workers > 0, "no more remaining root regions to process"); - G1CMRootRegionScanTask task(this); + G1CMRootRegionScanTask task(this, concurrent); log_debug(gc, ergo)("Running %s using %u workers for %u work units.", - task.name(), num_workers, root_regions()->num_root_regions()); - _concurrent_workers->run_task(&task, num_workers); - - // It's possible that has_aborted() is true here without actually - // aborting the survivor scan earlier. This is OK as it's - // mainly used for sanity checking. - root_regions()->scan_finished(); + task.name(), num_workers, root_regions()->num_remaining_regions()); + workers->run_task(&task, num_workers); } + + assert_root_region_scan_completed_or_aborted(); + + return do_scan; } -bool G1ConcurrentMark::wait_until_root_region_scan_finished() { - return root_regions()->wait_until_scan_finished(); +void G1ConcurrentMark::scan_root_regions_concurrently() { + assert(Thread::current() == cm_thread(), "must be on Concurrent Mark Thread"); + scan_root_regions(_concurrent_workers, true /* concurrent */); +} + +bool G1ConcurrentMark::complete_root_regions_scan_in_safepoint() { + assert_at_safepoint_on_vm_thread(); + return scan_root_regions(_g1h->workers(), false /* concurrent */); } void G1ConcurrentMark::add_root_region(G1HeapRegion* r) { @@ -1169,9 +1171,16 @@ bool G1ConcurrentMark::is_root_region(G1HeapRegion* r) { return root_regions()->contains(MemRegion(top_at_mark_start(r), r->top())); } -void G1ConcurrentMark::root_region_scan_abort_and_wait() { - root_regions()->abort(); - root_regions()->wait_until_scan_finished(); +void G1ConcurrentMark::abort_root_region_scan() { + assert_not_at_safepoint(); + + _root_region_scan_aborted.store_relaxed(true); +} + +void G1ConcurrentMark::abort_root_region_scan_at_safepoint() { + assert_at_safepoint_on_vm_thread(); + + _root_region_scan_aborted.store_relaxed(true); } void G1ConcurrentMark::concurrent_cycle_start() { @@ -1948,12 +1957,15 @@ void G1ConcurrentMark::print_stats() { } bool G1ConcurrentMark::concurrent_cycle_abort() { + assert_at_safepoint_on_vm_thread(); + assert(_g1h->collector_state()->is_in_full_gc(), "must be"); + // If we start the compaction before the CM threads finish // scanning the root regions we might trip them over as we'll - // be moving objects / updating references. So let's wait until - // they are done. By telling them to abort, they should complete - // early. - root_region_scan_abort_and_wait(); + // be moving objects / updating references. Since the root region + // scan synchronized with the safepoint, just tell it to abort. + // It will notice when the threads start up again later. + abort_root_region_scan_at_safepoint(); // We haven't started a concurrent cycle no need to do anything; we might have // aborted the marking because of shutting down though. In this case the marking @@ -1983,7 +1995,7 @@ bool G1ConcurrentMark::concurrent_cycle_abort() { } void G1ConcurrentMark::abort_marking_threads() { - assert(!_root_regions.scan_in_progress(), "still doing root region scan"); + assert_root_region_scan_completed_or_aborted(); _has_aborted.store_relaxed(true); _first_overflow_barrier_sync.abort(); _second_overflow_barrier_sync.abort(); diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp index de97179d210..7aa93947204 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp @@ -288,57 +288,36 @@ private: class G1CMRootMemRegions { // The set of root MemRegions. MemRegion* _root_regions; - size_t const _max_regions; + uint const _max_regions; - Atomic _num_root_regions; // Actual number of root regions. + Atomic _num_regions; // Actual number of root regions. + Atomic _num_claimed_regions; // Number of root regions currently claimed. - Atomic _claimed_root_regions; // Number of root regions currently claimed. - - Atomic _scan_in_progress; - Atomic _should_abort; - - void notify_scan_done(); + uint num_regions() const { return _num_regions.load_relaxed(); } + uint num_claimed_regions() const { return _num_claimed_regions.load_relaxed(); } public: G1CMRootMemRegions(uint const max_regions); ~G1CMRootMemRegions(); - // Reset the data structure to allow addition of new root regions. - void reset(); - void add(HeapWord* start, HeapWord* end); - // Reset the claiming / scanning of the root regions. - void prepare_for_scan(); - - // Forces get_next() to return null so that the iteration aborts early. - void abort() { _should_abort.store_relaxed(true); } - - // Return true if the CM thread are actively scanning root regions, - // false otherwise. - bool scan_in_progress() { return _scan_in_progress.load_relaxed(); } + // Reset data structure to initial state. + void reset(); // Claim the next root MemRegion to scan atomically, or return null if // all have been claimed. const MemRegion* claim_next(); - // The number of root regions to scan. - uint num_root_regions() const; + // Number of root regions to still process. + uint num_remaining_regions() const; + + // Returns whether all root regions have been processed or the processing been aborted. + bool work_completed() const; // Is the given memregion contained in the root regions; the MemRegion must // match exactly. bool contains(const MemRegion mr) const; - - void cancel_scan(); - - // Flag that we're done with root region scanning and notify anyone - // who's waiting on it. If aborted is false, assume that all regions - // have been claimed. - void scan_finished(); - - // If CM threads are still scanning root regions, wait until they - // are done. Return true if we had to wait, false otherwise. - bool wait_until_scan_finished(); }; // This class manages data structures and methods for doing liveness analysis in @@ -367,6 +346,7 @@ class G1ConcurrentMark : public CHeapObj { // Root region tracking and claiming G1CMRootMemRegions _root_regions; + Atomic _root_region_scan_aborted; // For grey objects G1CMMarkStack _global_mark_stack; // Grey objects behind global finger @@ -600,7 +580,7 @@ public: // Notifies marking threads to abort. This is a best-effort notification. Does not // guarantee or update any state after the call. Root region scan must not be - // running. + // running or being aborted. void abort_marking_threads(); // Total cpu time spent in mark worker threads in seconds. @@ -651,17 +631,30 @@ public: // Stop active components/the concurrent mark thread. void stop(); - // Scan all the root regions and mark everything reachable from - // them. - void scan_root_regions(); - bool wait_until_root_region_scan_finished(); void add_root_region(G1HeapRegion* r); bool is_root_region(G1HeapRegion* r); - void root_region_scan_abort_and_wait(); + + // Scan all the root regions concurrently and mark everything reachable from + // them. + void scan_root_regions_concurrently(); + // Complete root region scan work in the safepoint, return if we did some work. + bool complete_root_regions_scan_in_safepoint(); + + // Abort an active concurrent root region scan outside safepoint. + void abort_root_region_scan(); + + bool has_root_region_scan_aborted() const; private: + // Abort an active concurrent root region scan during safepoint. + void abort_root_region_scan_at_safepoint(); + + void assert_root_region_scan_completed_or_aborted() PRODUCT_RETURN; G1CMRootMemRegions* root_regions() { return &_root_regions; } + // Perform root region scan until all root regions have been processed, or + // the process has been aborted. Returns true if we did some work. + bool scan_root_regions(WorkerThreads* workers, bool concurrent); // Scan a single root MemRegion to mark everything reachable from it. void scan_root_region(const MemRegion* region, uint worker_id); diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMarkThread.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMarkThread.cpp index 31d61b8b388..b8c97acd1b0 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMarkThread.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMarkThread.cpp @@ -131,14 +131,11 @@ void G1ConcurrentMarkThread::run_service() { update_perf_counter_cpu_time(); } - _cm->root_regions()->cancel_scan(); } void G1ConcurrentMarkThread::stop_service() { if (is_in_progress()) { - // We are not allowed to abort the marking threads during root region scan. - // Needs to be done separately. - _cm->root_region_scan_abort_and_wait(); + _cm->abort_root_region_scan(); _cm->abort_marking_threads(); } @@ -164,7 +161,7 @@ bool G1ConcurrentMarkThread::phase_clear_cld_claimed_marks() { bool G1ConcurrentMarkThread::phase_scan_root_regions() { G1ConcPhaseTimer p(_cm, "Concurrent Scan Root Regions"); - _cm->scan_root_regions(); + _cm->scan_root_regions_concurrently(); update_perf_counter_cpu_time(); return _cm->has_aborted(); } diff --git a/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp b/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp index a5013ddbb40..023790a2422 100644 --- a/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp +++ b/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp @@ -180,7 +180,7 @@ void G1GCPhaseTimes::reset() { _cur_post_evacuate_cleanup_2_time_ms = 0.0; _cur_resize_heap_time_ms = 0.0; _cur_ref_proc_time_ms = 0.0; - _root_region_scan_wait_time_ms = 0.0; + _root_region_scan_time_ms = 0.0; _external_accounted_time_ms = 0.0; _recorded_prepare_heap_roots_time_ms = 0.0; _recorded_young_cset_choice_time_ms = 0.0; @@ -549,8 +549,8 @@ void G1GCPhaseTimes::print_other(double accounted_ms) const { // In addition, these are not included in G1GCPhaseTimes::_gc_pause_time_ms. // See G1YoungCollector::collect(). void G1GCPhaseTimes::print(bool evacuation_failed) { - if (_root_region_scan_wait_time_ms > 0.0) { - debug_time("Root Region Scan Waiting", _root_region_scan_wait_time_ms); + if (_root_region_scan_time_ms > 0.0) { + debug_time("Root Region Scan", _root_region_scan_time_ms); } // Check if some time has been recorded for verification and only then print diff --git a/src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp b/src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp index 8223148b791..b57bf0d617e 100644 --- a/src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp +++ b/src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp @@ -191,7 +191,7 @@ class G1GCPhaseTimes : public CHeapObj { double _cur_ref_proc_time_ms; // Not included in _gc_pause_time_ms - double _root_region_scan_wait_time_ms; + double _root_region_scan_time_ms; double _external_accounted_time_ms; @@ -325,8 +325,8 @@ class G1GCPhaseTimes : public CHeapObj { _cur_prepare_concurrent_task_time_ms = ms; } - void record_root_region_scan_wait_time(double time_ms) { - _root_region_scan_wait_time_ms = time_ms; + void record_root_region_scan_time(double time_ms) { + _root_region_scan_time_ms = time_ms; } void record_serial_free_cset_time_ms(double time_ms) { @@ -399,8 +399,8 @@ class G1GCPhaseTimes : public CHeapObj { return _cur_resize_heap_time_ms; } - double root_region_scan_wait_time_ms() { - return _root_region_scan_wait_time_ms; + double root_region_scan_time_ms() { + return _root_region_scan_time_ms; } double young_cset_choice_time_ms() { diff --git a/src/hotspot/share/gc/g1/g1VMOperations.cpp b/src/hotspot/share/gc/g1/g1VMOperations.cpp index b0c6b680b78..891432e20a7 100644 --- a/src/hotspot/share/gc/g1/g1VMOperations.cpp +++ b/src/hotspot/share/gc/g1/g1VMOperations.cpp @@ -152,8 +152,9 @@ bool VM_G1PauseConcurrent::doit_prologue() { G1CollectedHeap* g1h = G1CollectedHeap::heap(); if (g1h->is_shutting_down()) { Heap_lock->unlock(); - // JVM shutdown has started. This ensures that any further operations will be properly aborted - // and will not interfere with the shutdown process. + // JVM shutdown has started. Abort concurrent marking to ensure that any further + // concurrent VM operations will not try to start and interfere with the shutdown + // process. g1h->concurrent_mark()->abort_marking_threads(); return false; } diff --git a/src/hotspot/share/gc/g1/g1YoungCollector.cpp b/src/hotspot/share/gc/g1/g1YoungCollector.cpp index a4938416f25..9c12127c864 100644 --- a/src/hotspot/share/gc/g1/g1YoungCollector.cpp +++ b/src/hotspot/share/gc/g1/g1YoungCollector.cpp @@ -244,19 +244,13 @@ G1YoungGCAllocationFailureInjector* G1YoungCollector::allocation_failure_injecto return _g1h->allocation_failure_injector(); } - -void G1YoungCollector::wait_for_root_region_scanning() { +void G1YoungCollector::complete_root_region_scan() { Ticks start = Ticks::now(); - // We have to wait until the CM threads finish scanning the - // root regions as it's the only way to ensure that all the - // objects on them have been correctly scanned before we start - // moving them during the GC. - bool waited = concurrent_mark()->wait_until_root_region_scan_finished(); - Tickspan wait_time; - if (waited) { - wait_time = (Ticks::now() - start); + // We have to complete root region scan as it's the only way to ensure that all the + // objects on them have been correctly scanned before we start moving them during the GC. + if (concurrent_mark()->complete_root_regions_scan_in_safepoint()) { + phase_times()->record_root_region_scan_time((Ticks::now() - start).seconds() * MILLIUNITS); } - phase_times()->record_root_region_scan_wait_time(wait_time.seconds() * MILLIUNITS); } class G1PrintCollectionSetClosure : public G1HeapRegionClosure { @@ -1147,7 +1141,7 @@ void G1YoungCollector::collect() { // Wait for root region scan here to make sure that it is done before any // use of the STW workers to maximize cpu use (i.e. all cores are available // just to do that). - wait_for_root_region_scanning(); + complete_root_region_scan(); G1YoungGCVerifierMark vm(this); { diff --git a/src/hotspot/share/gc/g1/g1YoungCollector.hpp b/src/hotspot/share/gc/g1/g1YoungCollector.hpp index 76d443b1a9f..ab32ca770a4 100644 --- a/src/hotspot/share/gc/g1/g1YoungCollector.hpp +++ b/src/hotspot/share/gc/g1/g1YoungCollector.hpp @@ -89,7 +89,7 @@ class G1YoungCollector { // returning the total time taken. Tickspan run_task_timed(WorkerTask* task); - void wait_for_root_region_scanning(); + void complete_root_region_scan(); void calculate_collection_set(G1EvacInfo* evacuation_info, double target_pause_time_ms); diff --git a/src/hotspot/share/runtime/mutexLocker.cpp b/src/hotspot/share/runtime/mutexLocker.cpp index b102e6424f1..3dd61374d03 100644 --- a/src/hotspot/share/runtime/mutexLocker.cpp +++ b/src/hotspot/share/runtime/mutexLocker.cpp @@ -105,7 +105,6 @@ Mutex* G1MarkStackFreeList_lock = nullptr; Monitor* G1OldGCCount_lock = nullptr; Mutex* G1OldSets_lock = nullptr; Mutex* G1ReviseYoungLength_lock = nullptr; -Monitor* G1RootRegionScan_lock = nullptr; Mutex* G1RareEvent_lock = nullptr; Mutex* G1Uncommit_lock = nullptr; #endif @@ -216,7 +215,6 @@ void mutex_init() { MUTEX_DEFN(G1MarkStackChunkList_lock , PaddedMutex , nosafepoint); MUTEX_DEFN(G1MarkStackFreeList_lock , PaddedMutex , nosafepoint); MUTEX_DEFN(G1OldSets_lock , PaddedMutex , nosafepoint); - MUTEX_DEFN(G1RootRegionScan_lock , PaddedMonitor, nosafepoint-1); MUTEX_DEFN(G1Uncommit_lock , PaddedMutex , service-2); } #endif diff --git a/src/hotspot/share/runtime/mutexLocker.hpp b/src/hotspot/share/runtime/mutexLocker.hpp index f6c0a967718..682383de401 100644 --- a/src/hotspot/share/runtime/mutexLocker.hpp +++ b/src/hotspot/share/runtime/mutexLocker.hpp @@ -101,7 +101,6 @@ extern Monitor* G1OldGCCount_lock; // in support of "concurrent" f extern Mutex* G1OldSets_lock; // protects the G1 old region sets extern Mutex* G1RareEvent_lock; // Synchronizes (rare) parallel GC operations. extern Mutex* G1ReviseYoungLength_lock; // Protects access to young gen length revising operations. -extern Monitor* G1RootRegionScan_lock; // used to notify that the G1 CM threads have finished scanning the root regions extern Mutex* G1Uncommit_lock; // protects the G1 uncommit list when not at safepoints #endif From 9bf67a64f0a83a07dd292b679beaffd8b65b8c37 Mon Sep 17 00:00:00 2001 From: Anton Artemov Date: Wed, 1 Apr 2026 08:34:48 +0000 Subject: [PATCH 138/359] 8371596: Nits and typos found during review of fix for JDK-8366659 Reviewed-by: dholmes, dcubed, fbredberg --- src/hotspot/share/runtime/objectMonitor.cpp | 163 +++++++++++--------- 1 file changed, 94 insertions(+), 69 deletions(-) diff --git a/src/hotspot/share/runtime/objectMonitor.cpp b/src/hotspot/share/runtime/objectMonitor.cpp index 94399088464..9fc834f4b6b 100644 --- a/src/hotspot/share/runtime/objectMonitor.cpp +++ b/src/hotspot/share/runtime/objectMonitor.cpp @@ -155,7 +155,7 @@ static const jlong MAX_RECHECK_INTERVAL = 1000; // // Succession is provided for by a policy of competitive handoff. // The exiting thread does _not_ grant or pass ownership to the -// successor thread. (This is also referred to as "handoff succession"). +// successor thread. (This is also referred to as "handoff succession"). // Instead the exiting thread releases ownership and possibly wakes // a successor, so the successor can (re)compete for ownership of the lock. // @@ -189,7 +189,7 @@ static const jlong MAX_RECHECK_INTERVAL = 1000; // // Once we have formed a doubly linked list it's easy to find the // successor (A), wake it up, have it remove itself, and update the -// tail pointer, as seen in and 3) below. +// tail pointer, see 3) below. // // 3) entry_list ->F<=>E<=>D<=>C<=>B->null // entry_list_tail ------------------^ @@ -223,7 +223,7 @@ static const jlong MAX_RECHECK_INTERVAL = 1000; // remove itself) or update the tail. // // * The monitor entry list operations avoid locks, but strictly speaking -// they're not lock-free. Enter is lock-free, exit is not. +// they're not lock-free. Enter is lock-free, exit is not. // For a description of 'Methods and apparatus providing non-blocking access // to a resource,' see U.S. Pat. No. 7844973. // @@ -387,7 +387,7 @@ bool ObjectMonitor::try_lock_with_contention_mark(JavaThread* locking_thread, Ob prev_owner = try_set_owner_from(DEFLATER_MARKER, locking_thread); if (prev_owner == DEFLATER_MARKER) { // We successfully cancelled the in-progress async deflation by - // changing owner from DEFLATER_MARKER to current. We now extend + // changing owner from DEFLATER_MARKER to current. We now extend // the lifetime of the contention_mark (e.g. contentions++) here // to prevent the deflater thread from winning the last part of // the 2-part async deflation protocol after the regular @@ -633,14 +633,14 @@ void ObjectMonitor::enter_with_contention_mark(JavaThread* current, ObjectMonito // The thread -- now the owner -- is back in vm mode. // Report the glorious news via TI,DTrace and jvmstat. - // The probe effect is non-trivial. All the reportage occurs + // The probe effect is non-trivial. All the reportage occurs // while we hold the monitor, increasing the length of the critical - // section. Amdahl's parallel speedup law comes vividly into play. + // section. Amdahl's parallel speedup law comes vividly into play. // // Another option might be to aggregate the events (thread local or // per-monitor aggregation) and defer reporting until a more opportune // time -- such as next time some thread encounters contention but has - // yet to acquire the lock. While spinning that thread could + // yet to acquire the lock. While spinning that thread could // spinning we could increment JVMStat counters, etc. DTRACE_MONITOR_PROBE(contended__entered, this, object(), current); @@ -739,11 +739,11 @@ bool ObjectMonitor::try_lock_or_add_to_entry_list(JavaThread* current, ObjectWai return false; } - // Interference - the CAS failed because _entry_list changed. Before + // Interference - the CAS failed because _entry_list changed. Before // retrying the CAS retry taking the lock as it may now be free. if (try_lock(current) == TryLockResult::Success) { - assert(!has_successor(current), "invariant"); assert(has_owner(current), "invariant"); + assert(!has_successor(current), "invariant"); node->TState = ObjectWaiter::TS_RUN; return true; } @@ -953,8 +953,8 @@ bool ObjectMonitor::try_enter_fast(JavaThread* current, ObjectWaiter* current_no // Try the lock - TATAS if (try_lock(current) == TryLockResult::Success) { - assert(!has_successor(current), "invariant"); assert(has_owner(current), "invariant"); + assert(!has_successor(current), "invariant"); return true; } @@ -964,7 +964,7 @@ bool ObjectMonitor::try_enter_fast(JavaThread* current, ObjectWaiter* current_no // // If the _owner is ready but OFFPROC we could use a YieldTo() // operation to donate the remainder of this thread's quantum - // to the owner. This has subtle but beneficial affinity + // to the owner. This has subtle but beneficial affinity // effects. if (try_spin(current)) { @@ -974,15 +974,15 @@ bool ObjectMonitor::try_enter_fast(JavaThread* current, ObjectWaiter* current_no } // The Spin failed -- Enqueue and park the thread ... - assert(!has_successor(current), "invariant"); assert(!has_owner(current), "invariant"); + assert(!has_successor(current), "invariant"); // Enqueue "current" on ObjectMonitor's _entry_list. // // current_node acts as a proxy for current. // As an aside, if were to ever rewrite the synchronization code mostly // in Java, WaitNodes, ObjectMonitors, and Events would become 1st-class - // Java objects. This would avoid awkward lifecycle and liveness issues, + // Java objects. This would avoid awkward lifecycle and liveness issues, // as well as eliminate a subset of ABA issues. // TODO: eliminate ObjectWaiter and enqueue either Threads or Events. @@ -995,7 +995,7 @@ bool ObjectMonitor::try_enter_fast(JavaThread* current, ObjectWaiter* current_no // This thread is now added to the _entry_list. // The lock might have been released while this thread was occupied queueing - // itself onto _entry_list. To close the race and avoid "stranding" and + // itself onto _entry_list. To close the race and avoid "stranding" and // progress-liveness failure the caller must resample-retry _owner before parking. // Note the Dekker/Lamport duality: ST _entry_list; MEMBAR; LD Owner. // In this case the ST-MEMBAR is accomplished with CAS() in try_lock_or_add_to_entry_list. @@ -1051,13 +1051,13 @@ void ObjectMonitor::enter_internal(JavaThread* current, ObjectWaiter* current_no } // Try again, but just so we distinguish between futile wakeups and - // successful wakeups. The following test isn't algorithmically + // successful wakeups. The following test isn't algorithmically // necessary, but it helps us maintain sensible statistics. if (try_lock(current) == TryLockResult::Success) { break; } - // The lock is still contested. + // The lock is still contended. if (!reenter_path) { // Assuming this is not a spurious wakeup we'll normally find _succ == current. @@ -1070,9 +1070,9 @@ void ObjectMonitor::enter_internal(JavaThread* current, ObjectWaiter* current_no } // We can find that we were unpark()ed and redesignated _succ while - // we were spinning. That's harmless. If we iterate and call park(), + // we were spinning. That's harmless. If we iterate and call park(), // park() will consume the event and return immediately and we'll - // just spin again. This pattern can repeat, leaving _succ to simply + // just spin again. This pattern can repeat, leaving _succ to simply // spin on a CPU. if (has_successor(current)) { @@ -1092,9 +1092,9 @@ void ObjectMonitor::enter_internal(JavaThread* current, ObjectWaiter* current_no // Current has acquired the lock -- Unlink current from the _entry_list. unlink_after_acquire(current, current_node); if (has_successor(current)) { - clear_successor(); // Note that we don't need to do OrderAccess::fence() after clearing // _succ here, since we own the lock. + clear_successor(); } // We've acquired ownership with CAS(). @@ -1146,7 +1146,9 @@ bool ObjectMonitor::vthread_monitor_enter(JavaThread* current, ObjectWaiter* wai if (try_lock_or_add_to_entry_list(current, node)) { // We got the lock. - if (waiter == nullptr) delete node; // for Object.wait() don't delete yet + if (waiter == nullptr) { + delete node; // for Object.wait() don't delete yet + } dec_unmounted_vthreads(); return true; } @@ -1157,8 +1159,14 @@ bool ObjectMonitor::vthread_monitor_enter(JavaThread* current, ObjectWaiter* wai if (try_lock(current) == TryLockResult::Success) { assert(has_owner(current), "invariant"); unlink_after_acquire(current, node); - if (has_successor(current)) clear_successor(); - if (waiter == nullptr) delete node; // for Object.wait() don't delete yet + if (has_successor(current)) { + // Note that we don't need to do OrderAccess::fence() after clearing + // _succ here, since we own the lock. + clear_successor(); + } + if (waiter == nullptr) { + delete node; // for Object.wait() don't delete yet + } dec_unmounted_vthreads(); return true; } @@ -1182,7 +1190,9 @@ bool ObjectMonitor::resume_operation(JavaThread* current, ObjectWaiter* node, Co if (node->is_wait() && !node->at_reenter()) { bool acquired_monitor = vthread_wait_reenter(current, node, cont); - if (acquired_monitor) return true; + if (acquired_monitor) { + return true; + } } // Retry acquiring monitor... @@ -1196,7 +1206,9 @@ bool ObjectMonitor::resume_operation(JavaThread* current, ObjectWaiter* node, Co } oop vthread = current->vthread(); - if (has_successor(current)) clear_successor(); + if (has_successor(current)) { + clear_successor(); + } // Invariant: after clearing _succ a thread *must* retry acquiring the monitor. OrderAccess::fence(); @@ -1217,7 +1229,11 @@ void ObjectMonitor::vthread_epilog(JavaThread* current, ObjectWaiter* node) { add_to_contentions(-1); dec_unmounted_vthreads(); - if (has_successor(current)) clear_successor(); + if (has_successor(current)) { + // Note that we don't need to do OrderAccess::fence() after clearing + // _succ here, since we own the lock. + clear_successor(); + } guarantee(_recursions == 0, "invariant"); @@ -1419,7 +1435,7 @@ void ObjectMonitor::unlink_after_acquire(JavaThread* current, ObjectWaiter* curr // inopportune) reclamation of "this". // // We'd like to assert that: (THREAD->thread_state() != _thread_blocked) ; -// There's one exception to the claim above, however. enter_internal() can call +// There's one exception to the claim above, however. enter_internal() can call // exit() to drop a lock if the acquirer has been externally suspended. // In that case exit() is called with _thread_state == _thread_blocked, // but the monitor's _contentions field is > 0, which inhibits reclamation. @@ -1507,12 +1523,12 @@ void ObjectMonitor::exit(JavaThread* current, bool not_suspended) { w = entry_list_tail(current); // I'd like to write: guarantee (w->_thread != current). // But in practice an exiting thread may find itself on the entry_list. - // Let's say thread T1 calls O.wait(). Wait() enqueues T1 on O's waitset and - // then calls exit(). Exit release the lock by setting O._owner to null. - // Let's say T1 then stalls. T2 acquires O and calls O.notify(). The + // Let's say thread T1 calls O.wait(). Wait() enqueues T1 on O's waitset and + // then calls exit(). Exit releases the lock by setting O._owner to null. + // Let's say T1 then stalls. T2 acquires O and calls O.notify(). The // notify() operation moves T1 from O's waitset to O's entry_list. T2 then - // release the lock "O". T1 resumes immediately after the ST of null into - // _owner, above. T1 notices that the entry_list is populated, so it + // releases the lock "O". T1 resumes immediately after the ST of null into + // _owner, above. T1 notices that the entry_list is populated, so it // reacquires the lock and then finds itself on the entry_list. // Given all that, we have to tolerate the circumstance where "w" is // associated with current. @@ -1534,26 +1550,26 @@ void ObjectMonitor::exit(JavaThread* current, bool not_suspended) { // Normally the exiting thread is responsible for ensuring succession, // but if this thread observes other successors are ready or other // entering threads are spinning after it has stored null into _owner - // then it can exit without waking a successor. The existence of + // then it can exit without waking a successor. The existence of // spinners or ready successors guarantees proper succession (liveness). - // Responsibility passes to the ready or running successors. The exiting - // thread delegates the duty. More precisely, if a successor already + // Responsibility passes to the ready or running successors. The exiting + // thread delegates the duty. More precisely, if a successor already // exists this thread is absolved of the responsibility of waking // (unparking) one. // The _succ variable is critical to reducing futile wakeup frequency. // _succ identifies the "heir presumptive" thread that has been made - // ready (unparked) but that has not yet run. We need only one such + // ready (unparked) but that has not yet run. We need only one such // successor thread to guarantee progress. // See http://www.usenix.org/events/jvm01/full_papers/dice/dice.pdf // section 3.3 "Futile Wakeup Throttling" for details. // - // Note that spinners in Enter() also set _succ non-null. - // In the current implementation spinners opportunistically set + // Note that spinners in enter(), try_enter_fast() and enter_internal() also + // set _succ non-null. In the current implementation spinners opportunistically set // _succ so that exiting threads might avoid waking a successor. // Which means that the exiting thread could exit immediately without // waking a successor, if it observes a successor after it has dropped - // the lock. Note that the dropped lock needs to become visible to the + // the lock. Note that the dropped lock needs to become visible to the // spinner. if (_entry_list == nullptr || has_successor()) { @@ -1730,7 +1746,7 @@ void ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS) { if (JvmtiExport::should_post_monitor_wait()) { JvmtiExport::post_monitor_wait(current, object(), millis); } - // post monitor waited event. Note that this is past-tense, we are done waiting. + // post monitor waited event. Note that this is past-tense, we are done waiting. if (JvmtiExport::should_post_monitor_waited()) { // Note: 'false' parameter is passed here because the // wait was not timed out due to thread interrupt. @@ -1791,9 +1807,9 @@ void ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS) { // Enter the waiting queue, which is a circular doubly linked list in this case // but it could be a priority queue or any data structure. - // _wait_set_lock protects the wait queue. Normally the wait queue is accessed only + // _wait_set_lock protects the wait queue. Normally the wait queue is accessed only // by the owner of the monitor *except* in the case where park() - // returns because of a timeout of interrupt. Contention is exceptionally rare + // returns because of a timeout of interrupt. Contention is exceptionally rare // so we use a simple spin-lock instead of a heavier-weight blocking lock. { @@ -1850,7 +1866,7 @@ void ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS) { // written by the is thread. (perhaps the fetch might even be satisfied // by a look-aside into the processor's own store buffer, although given // the length of the code path between the prior ST and this load that's - // highly unlikely). If the following LD fetches a stale TS_WAIT value + // highly unlikely). If the following LD fetches a stale TS_WAIT value // then we'll acquire the lock and then re-fetch a fresh TState value. // That is, we fail toward safety. @@ -1868,7 +1884,12 @@ void ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS) { // No other threads will asynchronously modify TState. guarantee(node.TState != ObjectWaiter::TS_WAIT, "invariant"); OrderAccess::loadload(); - if (has_successor(current)) clear_successor(); + if (has_successor(current)) { + clear_successor(); + // Note that we do not need a fence here, as, regardless of the path taken, + // there is a fence either in ThreadBlockInVM's destructor or + // right after a call to post_monitor_wait_event(). + } // Reentry phase -- reacquire the monitor. // re-enter contended monitor after object.wait(). @@ -2046,11 +2067,11 @@ bool ObjectMonitor::notify_internal(JavaThread* current) { } } - // _wait_set_lock protects the wait queue, not the entry_list. We could + // _wait_set_lock protects the wait queue, not the entry_list. We could // move the add-to-entry_list operation, above, outside the critical section - // protected by _wait_set_lock. In practice that's not useful. With the + // protected by _wait_set_lock. In practice that's not useful. With the // exception of wait() timeouts and interrupts the monitor owner - // is the only thread that grabs _wait_set_lock. There's almost no contention + // is the only thread that grabs _wait_set_lock. There's almost no contention // on _wait_set_lock so it's not profitable to reduce the length of the // critical section. } @@ -2151,9 +2172,9 @@ void ObjectMonitor::vthread_wait(JavaThread* current, jlong millis, bool interru // Enter the waiting queue, which is a circular doubly linked list in this case // but it could be a priority queue or any data structure. - // _wait_set_lock protects the wait queue. Normally the wait queue is accessed only + // _wait_set_lock protects the wait queue. Normally the wait queue is accessed only // by the owner of the monitor *except* in the case where park() - // returns because of a timeout or interrupt. Contention is exceptionally rare + // returns because of a timeout or interrupt. Contention is exceptionally rare // so we use a simple spin-lock instead of a heavier-weight blocking lock. { @@ -2243,25 +2264,25 @@ bool ObjectMonitor::vthread_wait_reenter(JavaThread* current, ObjectWaiter* node // algorithm. // // Broadly, we can fix the spin frequency -- that is, the % of contended lock -// acquisition attempts where we opt to spin -- at 100% and vary the spin count +// acquisition attempts where we opt to spin -- at 100% and vary the spin count // (duration) or we can fix the count at approximately the duration of -// a context switch and vary the frequency. Of course we could also +// a context switch and vary the frequency. Of course we could also // vary both satisfying K == Frequency * Duration, where K is adaptive by monitor. // For a description of 'Adaptive spin-then-block mutual exclusion in // multi-threaded processing,' see U.S. Pat. No. 8046758. // // This implementation varies the duration "D", where D varies with // the success rate of recent spin attempts. (D is capped at approximately -// length of a round-trip context switch). The success rate for recent +// length of a round-trip context switch). The success rate for recent // spin attempts is a good predictor of the success rate of future spin -// attempts. The mechanism adapts automatically to varying critical +// attempts. The mechanism adapts automatically to varying critical // section length (lock modality), system load and degree of parallelism. // D is maintained per-monitor in _SpinDuration and is initialized -// optimistically. Spin frequency is fixed at 100%. +// optimistically. Spin frequency is fixed at 100%. // // Note that _SpinDuration is volatile, but we update it without locks -// or atomics. The code is designed so that _SpinDuration stays within -// a reasonable range even in the presence of races. The arithmetic +// or atomics. The code is designed so that _SpinDuration stays within +// a reasonable range even in the presence of races. The arithmetic // operations on _SpinDuration are closed over the domain of legal values, // so at worst a race will install and older but still legal value. // At the very worst this introduces some apparent non-determinism. @@ -2269,28 +2290,28 @@ bool ObjectMonitor::vthread_wait_reenter(JavaThread* current, ObjectWaiter* node // count are relatively short, even in the worst case, the effect is harmless. // // Care must be taken that a low "D" value does not become an -// an absorbing state. Transient spinning failures -- when spinning +// an absorbing state. Transient spinning failures -- when spinning // is overall profitable -- should not cause the system to converge -// on low "D" values. We want spinning to be stable and predictable +// on low "D" values. We want spinning to be stable and predictable // and fairly responsive to change and at the same time we don't want // it to oscillate, become metastable, be "too" non-deterministic, // or converge on or enter undesirable stable absorbing states. // // We implement a feedback-based control system -- using past behavior -// to predict future behavior. We face two issues: (a) if the +// to predict future behavior. We face two issues: (a) if the // input signal is random then the spin predictor won't provide optimal // results, and (b) if the signal frequency is too high then the control // system, which has some natural response lag, will "chase" the signal. -// (b) can arise from multimodal lock hold times. Transient preemption +// (b) can arise from multimodal lock hold times. Transient preemption // can also result in apparent bimodal lock hold times. // Although sub-optimal, neither condition is particularly harmful, as // in the worst-case we'll spin when we shouldn't or vice-versa. // The maximum spin duration is rather short so the failure modes aren't bad. // To be conservative, I've tuned the gain in system to bias toward -// _not spinning. Relatedly, the system can sometimes enter a mode where it -// "rings" or oscillates between spinning and not spinning. This happens +// _not spinning. Relatedly, the system can sometimes enter a mode where it +// "rings" or oscillates between spinning and not spinning. This happens // when spinning is just on the cusp of profitability, however, so the -// situation is not dire. The state is benign -- there's no need to add +// situation is not dire. The state is benign -- there's no need to add // hysteresis control to damp the transition rate between spinning and // not spinning. @@ -2322,7 +2343,9 @@ inline static int adjust_down(int spin_duration) { // Consider an AIMD scheme like: x -= (x >> 3) + 100 // This is globally sample and tends to damp the response. x -= Knob_Penalty; - if (x < 0) { x = 0; } + if (x < 0) { + x = 0; + } return x; } else { return spin_duration; @@ -2348,7 +2371,7 @@ bool ObjectMonitor::short_fixed_spin(JavaThread* current, int spin_count, bool a // Spinning: Fixed frequency (100%), vary duration bool ObjectMonitor::try_spin(JavaThread* current) { - // Dumb, brutal spin. Good for comparative measurements against adaptive spinning. + // Dumb, brutal spin. Good for comparative measurements against adaptive spinning. int knob_fixed_spin = Knob_FixedSpin; // 0 (don't spin: default), 2000 good test if (knob_fixed_spin > 0) { return short_fixed_spin(current, knob_fixed_spin, false); @@ -2357,7 +2380,7 @@ bool ObjectMonitor::try_spin(JavaThread* current) { // Admission control - verify preconditions for spinning // // We always spin a little bit, just to prevent _SpinDuration == 0 from - // becoming an absorbing state. Put another way, we spin briefly to + // becoming an absorbing state. Put another way, we spin briefly to // sample, just in case the system load, parallelism, contention, or lock // modality changed. @@ -2369,7 +2392,7 @@ bool ObjectMonitor::try_spin(JavaThread* current) { // // Consider the following alternative: // Periodically set _SpinDuration = _SpinLimit and try a long/full - // spin attempt. "Periodically" might mean after a tally of + // spin attempt. "Periodically" might mean after a tally of // the # of failed spin attempts (or iterations) reaches some threshold. // This takes us into the realm of 1-out-of-N spinning, where we // hold the duration constant but vary the frequency. @@ -2416,9 +2439,9 @@ bool ObjectMonitor::try_spin(JavaThread* current) { // If this thread observes the monitor transition or flicker // from locked to unlocked to locked, then the odds that this // thread will acquire the lock in this spin attempt go down - // considerably. The same argument applies if the CAS fails + // considerably. The same argument applies if the CAS fails // or if we observe _owner change from one non-null value to - // another non-null value. In such cases we might abort + // another non-null value. In such cases we might abort // the spin without prejudice or apply a "penalty" to the // spin count-down variable "ctr", reducing it by 100, say. @@ -2429,6 +2452,8 @@ bool ObjectMonitor::try_spin(JavaThread* current) { // The CAS succeeded -- this thread acquired ownership // Take care of some bookkeeping to exit spin state. if (has_successor(current)) { + // Note that we don't need to do OrderAccess::fence() after clearing + // _succ here, since we own the lock. clear_successor(); } @@ -2470,7 +2495,7 @@ bool ObjectMonitor::try_spin(JavaThread* current) { if (has_successor(current)) { clear_successor(); // Invariant: after setting succ=null a contending thread - // must recheck-retry _owner before parking. This usually happens + // must recheck-retry _owner before parking. This usually happens // in the normal usage of try_spin(), but it's safest // to make try_spin() as foolproof as possible. OrderAccess::fence(); From 0dfa22f27d71808c5a777c073a2a3acdd4c13945 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Wed, 1 Apr 2026 09:08:54 +0000 Subject: [PATCH 139/359] 8381397: G1: Inline initiate_conc_mark/record_conc_mark_init_end Reviewed-by: ayang, iwalulya --- src/hotspot/share/gc/g1/g1Policy.cpp | 21 +++++---------------- src/hotspot/share/gc/g1/g1Policy.hpp | 8 -------- 2 files changed, 5 insertions(+), 24 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1Policy.cpp b/src/hotspot/share/gc/g1/g1Policy.cpp index 24a82113d20..b1c9f3a5b6f 100644 --- a/src/hotspot/share/gc/g1/g1Policy.cpp +++ b/src/hotspot/share/gc/g1/g1Policy.cpp @@ -690,11 +690,6 @@ void G1Policy::record_young_collection_start() { assert(_g1h->collection_set()->verify_young_ages(), "region age verification failed"); } -void G1Policy::record_concurrent_mark_init_end() { - assert(!collector_state()->initiate_conc_mark_if_possible(), "we should have cleared it by now"); - collector_state()->set_in_normal_young_gc(); -} - void G1Policy::record_concurrent_mark_remark_end() { double end_time_sec = os::elapsedTime(); double start_time_sec = cur_pause_start_sec(); @@ -795,7 +790,8 @@ void G1Policy::record_young_collection_end(bool concurrent_operation_is_full_mar bool is_young_only_pause = G1CollectorState::is_young_only_pause(this_pause); if (G1CollectorState::is_concurrent_start_pause(this_pause)) { - record_concurrent_mark_init_end(); + assert(!collector_state()->initiate_conc_mark_if_possible(), "we should have cleared it by now"); + collector_state()->set_in_normal_young_gc(); } else { maybe_start_marking(allocation_word_size); } @@ -1245,10 +1241,6 @@ bool G1Policy::force_concurrent_start_if_outside_cycle(GCCause::Cause gc_cause) } } -void G1Policy::initiate_conc_mark() { - collector_state()->set_in_concurrent_start_gc(); -} - static const char* requester_for_mixed_abort(GCCause::Cause cause) { if (cause == GCCause::_wb_breakpoint) { return "run_to breakpoint"; @@ -1283,22 +1275,19 @@ void G1Policy::decide_on_concurrent_start_pause() { log_debug(gc, ergo)("Do not initiate concurrent cycle (whitebox controlled)"); } else if (!about_to_start_mixed_phase() && collector_state()->is_in_young_only_phase()) { // Initiate a new concurrent start if there is no marking or reclamation going on. - initiate_conc_mark(); + collector_state()->set_in_concurrent_start_gc(); log_debug(gc, ergo)("Initiate concurrent cycle (concurrent cycle initiation requested)"); } else if (_g1h->is_user_requested_concurrent_full_gc(cause) || GCCause::is_codecache_requested_gc(cause) || (cause == GCCause::_wb_breakpoint)) { - // Initiate a concurrent start. A concurrent start must be a young only - // GC, so the collector state must be updated to reflect this. - collector_state()->set_in_normal_young_gc(); - + // Force concurrent start. + collector_state()->set_in_concurrent_start_gc(); // We might have ended up coming here about to start a mixed phase with a collection set // active. The following remark might change the change the "evacuation efficiency" of // the regions in this set, leading to failing asserts later. // Since the concurrent cycle will recreate the collection set anyway, simply drop it here. abandon_collection_set_candidates(); abort_time_to_mixed_tracking(); - initiate_conc_mark(); log_debug(gc, ergo)("Initiate concurrent cycle (%s requested concurrent cycle)", requester_for_mixed_abort(cause)); } else { diff --git a/src/hotspot/share/gc/g1/g1Policy.hpp b/src/hotspot/share/gc/g1/g1Policy.hpp index bcc3bceda49..5c5c2bc3572 100644 --- a/src/hotspot/share/gc/g1/g1Policy.hpp +++ b/src/hotspot/share/gc/g1/g1Policy.hpp @@ -313,9 +313,6 @@ public: void record_full_collection_start(); void record_full_collection_end(size_t allocation_word_size); - // Must currently be called while the world is stopped. - void record_concurrent_mark_init_end(); - void record_concurrent_mark_remark_end(); // Record start, end, and completion of cleanup. @@ -332,11 +329,6 @@ private: // regions and update the associated members. void update_survival_estimates_for_next_collection(); - // Set the state to start a concurrent marking cycle and clear - // _initiate_conc_mark_if_possible because it has now been - // acted on. - void initiate_conc_mark(); - public: // This sets the initiate_conc_mark_if_possible() flag to start a // new cycle, as long as we are not already in one. It's best if it From e340aeeee010baf2773fd0d50ce59aa55a823de3 Mon Sep 17 00:00:00 2001 From: Guanqiang Han Date: Wed, 1 Apr 2026 09:12:51 +0000 Subject: [PATCH 140/359] 8379174: G1: Too high G1RemSetArrayOfCardsEntriesBase causes invalid ergonomic G1RemSetArrayOfCardsEntries Reviewed-by: tschatzl, iwalulya --- src/hotspot/share/gc/g1/g1Arguments.cpp | 3 +- ...tG1RemSetArrayOfCardsEntriesErgoLimit.java | 43 +++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 test/hotspot/jtreg/gc/g1/TestG1RemSetArrayOfCardsEntriesErgoLimit.java diff --git a/src/hotspot/share/gc/g1/g1Arguments.cpp b/src/hotspot/share/gc/g1/g1Arguments.cpp index 8bec6e7e86f..c3bbd5a3b52 100644 --- a/src/hotspot/share/gc/g1/g1Arguments.cpp +++ b/src/hotspot/share/gc/g1/g1Arguments.cpp @@ -148,8 +148,9 @@ void G1Arguments::initialize_card_set_configuration() { if (FLAG_IS_DEFAULT(G1RemSetArrayOfCardsEntries)) { uint max_cards_in_inline_ptr = G1CardSetConfiguration::max_cards_in_inline_ptr(G1HeapRegion::LogCardsPerRegion); + const JVMTypedFlagLimit* limit = JVMFlagLimit::get_range_at(FLAG_MEMBER_ENUM(G1RemSetArrayOfCardsEntries))->cast(); FLAG_SET_ERGO(G1RemSetArrayOfCardsEntries, MAX2(max_cards_in_inline_ptr * 2, - G1RemSetArrayOfCardsEntriesBase << region_size_log_mb)); + MIN2(G1RemSetArrayOfCardsEntriesBase << region_size_log_mb, limit->max()))); } // Howl card set container globals. diff --git a/test/hotspot/jtreg/gc/g1/TestG1RemSetArrayOfCardsEntriesErgoLimit.java b/test/hotspot/jtreg/gc/g1/TestG1RemSetArrayOfCardsEntriesErgoLimit.java new file mode 100644 index 00000000000..4af09066def --- /dev/null +++ b/test/hotspot/jtreg/gc/g1/TestG1RemSetArrayOfCardsEntriesErgoLimit.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8379174 + * @summary Test for G1 ergonomics deriving an out-of-range + * G1RemSetArrayOfCardsEntries value from G1RemSetArrayOfCardsEntriesBase + * @requires vm.gc.G1 + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions + * -XX:+UseG1GC + * -XX:G1RemSetArrayOfCardsEntriesBase=62117 + * -XX:G1HeapRegionSize=4m + * ${test.main.class} + */ + +package gc.g1; + +public class TestG1RemSetArrayOfCardsEntriesErgoLimit { + public static void main(String[] args) { + System.out.println("passed"); + } +} From 2caf253017d00f758a038a16ba9d64d52dd1c202 Mon Sep 17 00:00:00 2001 From: Martin Doerr Date: Wed, 1 Apr 2026 09:20:10 +0000 Subject: [PATCH 141/359] 8381412: [PPC64] unproblemlist JDK-8320897 Reviewed-by: mbaesken --- test/hotspot/jtreg/ProblemList.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index 3b871d9f4b6..d4efaa7e631 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -56,7 +56,7 @@ compiler/c2/irTests/TestDuplicateBackedge.java 8318904 generic-all compiler/codecache/jmx/PoolsIndependenceTest.java 8264632 macosx-all -compiler/vectorapi/reshape/TestVectorReinterpret.java 8320897,8348519 aix-ppc64,linux-ppc64le,linux-s390x +compiler/vectorapi/reshape/TestVectorReinterpret.java 8348519 linux-s390x compiler/vectorapi/VectorRebracket128Test.java 8330538 generic-all compiler/vectorization/TestVectorAlgorithms.java#noSuperWord 8376803 aix-ppc64,linux-s390x From 3459f6b124c34f3187050495e34c690c017a0687 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eirik=20Bj=C3=B8rsn=C3=B8s?= Date: Wed, 1 Apr 2026 09:50:37 +0000 Subject: [PATCH 142/359] 8380452: ZipOutputStream::putNextEntry(ZipEntry) throws unspecified IllegalArgumentException for unmappable entry name Reviewed-by: jpai, lancea, alanb --- .../java/util/zip/ZipOutputStream.java | 21 ++++- .../UnmappableZipEntryNameOrComment.java | 76 +++++++++++++++++++ 2 files changed, 93 insertions(+), 4 deletions(-) create mode 100644 test/jdk/java/util/zip/ZipOutputStream/UnmappableZipEntryNameOrComment.java diff --git a/src/java.base/share/classes/java/util/zip/ZipOutputStream.java b/src/java.base/share/classes/java/util/zip/ZipOutputStream.java index 47499858a37..4ea4a103fef 100644 --- a/src/java.base/share/classes/java/util/zip/ZipOutputStream.java +++ b/src/java.base/share/classes/java/util/zip/ZipOutputStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -257,6 +257,11 @@ public class ZipOutputStream extends DeflaterOutputStream implements ZipConstant default: throw new ZipException("unsupported compression method"); } + // Verify that entry name and comment can be encoded + byte[] nameBytes = checkEncodable(e.name, "unmappable character in ZIP entry name"); + if (e.comment != null) { + checkEncodable(e.comment, "unmappable character in ZIP entry comment"); + } if (! names.add(e.name)) { throw new ZipException("duplicate entry: " + e.name); } @@ -270,7 +275,16 @@ public class ZipOutputStream extends DeflaterOutputStream implements ZipConstant } current = new XEntry(e, written); xentries.add(current); - writeLOC(current); + writeLOC(current, nameBytes); + } + + // Throws ZipException if the given string cannot be encoded + private byte[] checkEncodable(String str, String msg) throws ZipException { + try { + return zc.getBytes(str); + } catch (IllegalArgumentException ex) { + throw (ZipException) new ZipException(msg).initCause(ex); + } } /** @@ -424,7 +438,7 @@ public class ZipOutputStream extends DeflaterOutputStream implements ZipConstant /* * Writes local file (LOC) header for specified entry. */ - private void writeLOC(XEntry xentry) throws IOException { + private void writeLOC(XEntry xentry, byte[] nameBytes) throws IOException { ZipEntry e = xentry.entry; int flag = e.flag; boolean hasZip64 = false; @@ -461,7 +475,6 @@ public class ZipOutputStream extends DeflaterOutputStream implements ZipConstant writeInt(e.size); // uncompressed size } } - byte[] nameBytes = zc.getBytes(e.name); writeShort(nameBytes.length); int elenEXTT = 0; // info-zip extended timestamp diff --git a/test/jdk/java/util/zip/ZipOutputStream/UnmappableZipEntryNameOrComment.java b/test/jdk/java/util/zip/ZipOutputStream/UnmappableZipEntryNameOrComment.java new file mode 100644 index 00000000000..af08de2adcf --- /dev/null +++ b/test/jdk/java/util/zip/ZipOutputStream/UnmappableZipEntryNameOrComment.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.zip.ZipEntry; +import java.util.zip.ZipException; +import java.util.zip.ZipOutputStream; + +import static java.io.OutputStream.nullOutputStream; +import static org.junit.jupiter.api.Assertions.assertThrows; + +/* @test + * @bug 8380452 + * @summary Unmappable characters in ZipEntry name or comment should be rejected with ZipException + * @run junit ${test.main.class} + */ +public class UnmappableZipEntryNameOrComment { + + // Charset used by any ZipOutputStream in this test + static final Charset CHARSET = StandardCharsets.US_ASCII; + // 'ø' is an unmappable character in US_ASCII + static final String UNMAPPABLE = "\u00f8"; + + /** + * Verify that calling ZipOutputStream.putNextEntry with an unmappable ZipEntry + * name is rejected with a ZipException. + * + * @throws IOException if an unexpected IO error occurs + */ + @Test + void rejectUnmappableZipEntryName() throws IOException { + ZipEntry e = new ZipEntry(UNMAPPABLE); + try (var out = new ZipOutputStream(nullOutputStream(), CHARSET)) { + assertThrows(ZipException.class, () -> out.putNextEntry(e)); + } + } + + /** + * Verify that calling ZipOutputStream.putNextEntry with an unmappable ZipEntry + * comment is rejected with a ZipException. + * + * @throws IOException if an unexpected IO error occurs + */ + @Test + void rejectUnmappableZipEntryComment() throws IOException { + ZipEntry e = new ZipEntry("file.txt"); + e.setComment(UNMAPPABLE); + try (var out = new ZipOutputStream(nullOutputStream(), CHARSET)) { + assertThrows(ZipException.class, () -> out.putNextEntry(e)); + } + } +} From 92b1d8237ec0feaba44ff875cdd92fbb78896eae Mon Sep 17 00:00:00 2001 From: Liam Miller-Cushon Date: Wed, 1 Apr 2026 10:10:03 +0000 Subject: [PATCH 143/359] 8380147: Don't require a CompilationUnit for end position APIs Reviewed-by: vromero --- .../sun/source/util/DocSourcePositions.java | 59 +++++++++++++++++- .../com/sun/source/util/SourcePositions.java | 53 +++++++++++++++- .../com/sun/tools/javac/api/JavacTrees.java | 8 +-- .../internal/doclets/toolkit/util/Utils.java | 2 +- .../jdk/javadoc/internal/doclint/Env.java | 2 +- .../jdk/javadoc/internal/tool/JavadocLog.java | 4 +- .../shellsupport/doc/JavadocHelper.java | 62 +++++++++---------- .../jdk/jshell/SourceCodeAnalysisImpl.java | 30 ++++----- .../classes/jdk/jshell/TreeDissector.java | 4 +- 9 files changed, 163 insertions(+), 61 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/source/util/DocSourcePositions.java b/src/jdk.compiler/share/classes/com/sun/source/util/DocSourcePositions.java index 520943c464d..d0afd126bf6 100644 --- a/src/jdk.compiler/share/classes/com/sun/source/util/DocSourcePositions.java +++ b/src/jdk.compiler/share/classes/com/sun/source/util/DocSourcePositions.java @@ -28,6 +28,7 @@ package com.sun.source.util; import com.sun.source.doctree.DocCommentTree; import com.sun.source.doctree.DocTree; import com.sun.source.tree.CompilationUnitTree; +import com.sun.source.tree.Tree; /** * Provides methods to obtain the position of a DocTree within a javadoc comment. @@ -59,8 +60,31 @@ public interface DocSourcePositions extends SourcePositions { * position is being sought * @param tree tree for which a position is sought * @return the start position of tree + * @deprecated use {@link #getStartPosition(DocCommentTree, DocTree)} instead */ - long getStartPosition(CompilationUnitTree file, DocCommentTree comment, DocTree tree); + @Deprecated(since = "27", forRemoval = true) + default long getStartPosition(CompilationUnitTree file, DocCommentTree comment, DocTree tree) { + return getStartPosition(comment, tree); + } + + /** + * {@return the starting position of the given {@link Tree}. If the starting position is not available, returns + * {@link javax.tools.Diagnostic#NOPOS}} + * + *

The given tree should be under the given comment tree. The returned position must be at the start of the + * yield of this tree, that is for any sub-tree of this tree, the following must hold: + * + *

+ * {@code getStartPosition(comment, tree) <= getStartPosition(comment, subtree)} or
+ * {@code getStartPosition(comment, tree) == NOPOS} or
+ * {@code getStartPosition(comment, subtree) == NOPOS} + *

+ * + * @param comment the comment tree that encloses the tree for which the + * position is being sought + * @param tree tree for which a position is sought + */ + long getStartPosition(DocCommentTree comment, DocTree tree); /** * Returns the ending position of the tree within the comment within the file. If tree is not found within @@ -91,7 +115,38 @@ public interface DocSourcePositions extends SourcePositions { * position is being sought * @param tree tree for which a position is sought * @return the end position of tree + * @deprecated use {@link #getEndPosition(DocCommentTree, DocTree)} instead */ - long getEndPosition(CompilationUnitTree file, DocCommentTree comment, DocTree tree); + @Deprecated(since = "27", forRemoval = true) + default long getEndPosition(CompilationUnitTree file, DocCommentTree comment, DocTree tree) { + return getEndPosition(comment, tree); + } + + /** + * {@return the ending position of the given {@link Tree}. If the ending position is not available, returns + * {@link javax.tools.Diagnostic#NOPOS}} + * + *

The given tree should be under the given comment tree. The returned position must be at the end of the yield + * of this tree, that is for any sub-tree of this tree, the following must hold: + * + *

+ * {@code getEndPosition(comment, tree) >= getEndPosition(comment, subtree)} or
+ * {@code getEndPosition(comment, tree) == NOPOS} or
+ * {@code getEndPosition(comment, subtree) == NOPOS} + *

+ * + * In addition, the following must hold: + * + *

+ * {@code getStartPosition(comment, tree) <= getEndPosition(comment, tree)} or
+ * {@code getStartPosition(comment, tree) == NOPOS} or
+ * {@code getEndPosition(comment, tree) == NOPOS} + *

+ * + * @param comment the comment tree that encloses the tree for which the + * position is being sought + * @param tree tree for which a position is sought + */ + long getEndPosition(DocCommentTree comment, DocTree tree); } diff --git a/src/jdk.compiler/share/classes/com/sun/source/util/SourcePositions.java b/src/jdk.compiler/share/classes/com/sun/source/util/SourcePositions.java index b6112fd32e6..460f4f2a1ce 100644 --- a/src/jdk.compiler/share/classes/com/sun/source/util/SourcePositions.java +++ b/src/jdk.compiler/share/classes/com/sun/source/util/SourcePositions.java @@ -53,8 +53,29 @@ public interface SourcePositions { * @param file CompilationUnit in which to find tree * @param tree tree for which a position is sought * @return the start position of tree + * @deprecated use {@link #getStartPosition(Tree)} instead */ - long getStartPosition(CompilationUnitTree file, Tree tree); + @Deprecated(since = "27", forRemoval = true) + default long getStartPosition(CompilationUnitTree file, Tree tree) { + return getStartPosition(tree); + } + + /** + * {@return the starting position of the given {@link Tree}, or if the starting position is not available, returns + * {@link javax.tools.Diagnostic#NOPOS}} + * + *

The returned position must be at the start of the yield of this tree, that is for any sub-tree of this tree, + * the following must hold: + * + *

+ * {@code getStartPosition(tree) <= getStartPosition(subtree)} or
+ * {@code getStartPosition(tree) == NOPOS} or
+ * {@code getStartPosition(subtree) == NOPOS} + *

+ * + * @param tree tree for which a position is sought + */ + long getStartPosition(Tree tree); /** * Returns the ending position of tree within file. If tree is not found within @@ -80,7 +101,35 @@ public interface SourcePositions { * @param file CompilationUnit in which to find tree * @param tree tree for which a position is sought * @return the end position of tree + * @deprecated use {@link #getEndPosition(Tree)} instead */ - long getEndPosition(CompilationUnitTree file, Tree tree); + @Deprecated(since = "27", forRemoval = true) + default long getEndPosition(CompilationUnitTree file, Tree tree) { + return getEndPosition(tree); + } + /** + * {@return the ending position of the given {@link Tree}. If the ending position is not available, + * returns {@link javax.tools.Diagnostic#NOPOS}} + * + *

The returned position must be at the end of the yield of this tree, that is for any sub-tree of this tree, + * the following must hold: + * + *

+ * {@code getEndPosition(tree) >= getEndPosition(subtree)} or
+ * {@code getEndPosition(tree) == NOPOS} or
+ * {@code getEndPosition(subtree) == NOPOS} + *

+ * + * In addition, the following must hold: + * + *

+ * {@code getStartPosition(tree) <= getEndPosition(tree)} or
+ * {@code getStartPosition(tree) == NOPOS} or
+ * {@code getEndPosition(tree) == NOPOS} + *

+ * + * @param tree tree for which a position is sought + */ + long getEndPosition(Tree tree); } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java index ecd7f5b101a..41dd904bc8a 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java @@ -233,24 +233,24 @@ public class JavacTrees extends DocTrees { public DocSourcePositions getSourcePositions() { return new DocSourcePositions() { @Override @DefinedBy(Api.COMPILER_TREE) - public long getStartPosition(CompilationUnitTree file, Tree tree) { + public long getStartPosition(Tree tree) { return TreeInfo.getStartPos((JCTree) tree); } @Override @DefinedBy(Api.COMPILER_TREE) - public long getEndPosition(CompilationUnitTree file, Tree tree) { + public long getEndPosition(Tree tree) { return TreeInfo.getEndPos((JCTree) tree); } @Override @DefinedBy(Api.COMPILER_TREE) - public long getStartPosition(CompilationUnitTree file, DocCommentTree comment, DocTree tree) { + public long getStartPosition(DocCommentTree comment, DocTree tree) { DCDocComment dcComment = (DCDocComment) comment; DCTree dcTree = (DCTree) tree; return dcComment.getSourcePosition(dcTree.getStartPosition()); } @Override @DefinedBy(Api.COMPILER_TREE) - public long getEndPosition(CompilationUnitTree file, DocCommentTree comment, DocTree tree) { + public long getEndPosition(DocCommentTree comment, DocTree tree) { DCDocComment dcComment = (DCDocComment) comment; DCTree dcTree = (DCTree) tree; return dcComment.getSourcePosition(dcTree.getEndPosition()); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java index ddadd33a18b..0b3b767ea39 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java @@ -1618,7 +1618,7 @@ public class Utils { CompilationUnitTree cu = path.getCompilationUnit(); LineMap lineMap = cu.getLineMap(); DocSourcePositions spos = docTrees.getSourcePositions(); - long pos = spos.getStartPosition(cu, path.getLeaf()); + long pos = spos.getStartPosition(path.getLeaf()); return lineMap.getLineNumber(pos); } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Env.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Env.java index f2940963f17..ba7f68cccf6 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Env.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Env.java @@ -211,7 +211,7 @@ public class Env { long getStartPos(TreePath p) { SourcePositions sp = trees.getSourcePositions(); - return sp.getStartPosition(p.getCompilationUnit(), p.getLeaf()); + return sp.getStartPosition(p.getLeaf()); } boolean shouldCheck(CompilationUnitTree unit) { diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/JavadocLog.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/JavadocLog.java index b3bf1c14cb1..39bc58dff59 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/JavadocLog.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/JavadocLog.java @@ -582,9 +582,9 @@ public class JavadocLog extends Log implements Reporter { } CompilationUnitTree compUnit = tp.getCompilationUnit(); JCTree tree = (JCTree) tp.getLeaf(); - int start = (int) posns.getStartPosition(compUnit, tree); + int start = (int) posns.getStartPosition(tree); int pos = tree.getPreferredPosition(); - int end = (int) posns.getEndPosition(compUnit, tree); + int end = (int) posns.getEndPosition(tree); return createDiagnosticPosition(tree, start, pos, end); } diff --git a/src/jdk.jshell/share/classes/jdk/internal/shellsupport/doc/JavadocHelper.java b/src/jdk.jshell/share/classes/jdk/internal/shellsupport/doc/JavadocHelper.java index 7a1dd6c9877..112808420bc 100644 --- a/src/jdk.jshell/share/classes/jdk/internal/shellsupport/doc/JavadocHelper.java +++ b/src/jdk.jshell/share/classes/jdk/internal/shellsupport/doc/JavadocHelper.java @@ -543,9 +543,9 @@ public abstract class JavadocHelper implements AutoCloseable { for (DocTree t : inheritedText.get(0)) { start = Math.min(start, - sp.getStartPosition(null, inheritedDocTree, t) - offset); + sp.getStartPosition(inheritedDocTree, t) - offset); end = Math.max(end, - sp.getEndPosition(null, inheritedDocTree, t) - offset); + sp.getEndPosition(inheritedDocTree, t) - offset); } String text = end >= 0 ? inherited.substring((int) start, (int) end) : ""; @@ -559,8 +559,8 @@ public abstract class JavadocHelper implements AutoCloseable { } else { //replace the {@inheritDoc} with the full text from //the overridden method: - long inheritedStart = sp.getStartPosition(null, dcTree, node); - long inheritedEnd = sp.getEndPosition(null, dcTree, node); + long inheritedStart = sp.getStartPosition(dcTree, node); + long inheritedEnd = sp.getEndPosition(dcTree, node); int[] span = new int[] {(int) inheritedStart, (int) inheritedEnd}; replace.computeIfAbsent(span, s -> new ArrayList<>()) @@ -571,11 +571,11 @@ public abstract class JavadocHelper implements AutoCloseable { } @Override public Void visitLink(LinkTree node, Void p) { - if (sp.isRewrittenTree(null, dcTree, node)) { + if (sp.isRewrittenTree(dcTree, node)) { //this link is a synthetic rewritten link, replace //the original span with the new link: - int start = (int) sp.getStartPosition(null, dcTree, node); - int end = (int) sp.getEndPosition(null, dcTree, node); + int start = (int) sp.getStartPosition(dcTree, node); + int end = (int) sp.getEndPosition(dcTree, node); replace.computeIfAbsent(new int[] {start, end}, _ -> new ArrayList<>()) .add(node.toString()); @@ -601,7 +601,7 @@ public abstract class JavadocHelper implements AutoCloseable { //this tree) //if there is a newline immediately behind this tree, insert behind //the newline: - long endPos = sp.getEndPosition(null, dcTree, tree); + long endPos = sp.getEndPosition(dcTree, tree); if (endPos >= offset) { if (endPos - offset + 1 < docComment.length() && docComment.charAt((int) (endPos - offset + 1)) == '\n') { @@ -744,7 +744,7 @@ public abstract class JavadocHelper implements AutoCloseable { } }; DocCommentTree tree = trees.getDocCommentTree(fo); - offset += (int) trees.getSourcePositions().getStartPosition(null, tree, tree); + offset += (int) trees.getSourcePositions().getStartPosition(tree, tree); return Pair.of(tree, offset); } catch (URISyntaxException ex) { throw new IllegalStateException(ex); @@ -939,7 +939,7 @@ public abstract class JavadocHelper implements AutoCloseable { Iterable trees) { StringBuilder sourceBuilder = new StringBuilder(); List replaceSpans = new ArrayList<>(); - int currentSpanStart = (int) sp.getStartPosition(null, comment, trees.iterator().next()); + int currentSpanStart = (int) sp.getStartPosition(comment, trees.iterator().next()); DocTree lastTree = null; for (DocTree tree : trees) { @@ -958,8 +958,8 @@ public abstract class JavadocHelper implements AutoCloseable { } sourceBuilder.append(code); } else { - int treeStart = (int) sp.getStartPosition(null, comment, tree); - int treeEnd = (int) sp.getEndPosition(null, comment, tree); + int treeStart = (int) sp.getStartPosition(comment, tree); + int treeEnd = (int) sp.getEndPosition(comment, tree); replaceSpans.add(new int[] {currentSpanStart, treeStart}); currentSpanStart = treeEnd; sourceBuilder.append(PLACEHOLDER); @@ -967,7 +967,7 @@ public abstract class JavadocHelper implements AutoCloseable { lastTree = tree; } - int end = (int) sp.getEndPosition(null, comment, lastTree); + int end = (int) sp.getEndPosition(comment, lastTree); replaceSpans.add(new int[] {currentSpanStart, end}); @@ -1006,8 +1006,8 @@ public abstract class JavadocHelper implements AutoCloseable { } @Override - public long getStartPosition(CompilationUnitTree file, DocCommentTree comment, DocTree tree) { - ensureAdjustedSpansFilled(file, comment, tree); + public long getStartPosition(DocCommentTree comment, DocTree tree) { + ensureAdjustedSpansFilled(comment, tree); long[] adjusted = adjustedSpan.get(tree); @@ -1015,12 +1015,12 @@ public abstract class JavadocHelper implements AutoCloseable { return adjusted[0]; } - return delegate.getStartPosition(file, comment, tree); + return delegate.getStartPosition(comment, tree); } @Override - public long getEndPosition(CompilationUnitTree file, DocCommentTree comment, DocTree tree) { - ensureAdjustedSpansFilled(file, comment, tree); + public long getEndPosition(DocCommentTree comment, DocTree tree) { + ensureAdjustedSpansFilled(comment, tree); long[] adjusted = adjustedSpan.get(tree); @@ -1028,28 +1028,26 @@ public abstract class JavadocHelper implements AutoCloseable { return adjusted[1]; } - return delegate.getEndPosition(file, comment, tree); + return delegate.getEndPosition(comment, tree); } @Override - public long getStartPosition(CompilationUnitTree file, Tree tree) { - return delegate.getStartPosition(file, tree); + public long getStartPosition(Tree tree) { + return delegate.getStartPosition(tree); } @Override - public long getEndPosition(CompilationUnitTree file, Tree tree) { - return delegate.getEndPosition(file, tree); + public long getEndPosition(Tree tree) { + return delegate.getEndPosition(tree); } - boolean isRewrittenTree(CompilationUnitTree file, - DocCommentTree comment, + boolean isRewrittenTree(DocCommentTree comment, DocTree tree) { - ensureAdjustedSpansFilled(file, comment, tree); + ensureAdjustedSpansFilled(comment, tree); return rewrittenTrees.contains(tree); } - private void ensureAdjustedSpansFilled(CompilationUnitTree file, - DocCommentTree comment, + private void ensureAdjustedSpansFilled(DocCommentTree comment, DocTree tree) { if (tree.getKind() != DocTree.Kind.LINK && tree.getKind() != DocTree.Kind.LINK_PLAIN) { @@ -1057,7 +1055,7 @@ public abstract class JavadocHelper implements AutoCloseable { } long[] span; - long treeStart = delegate.getStartPosition(file, comment, tree); + long treeStart = delegate.getStartPosition(comment, tree); if (treeStart == (-1)) { LinkTree link = (LinkTree) tree; @@ -1069,15 +1067,15 @@ public abstract class JavadocHelper implements AutoCloseable { for (DocTree t : nested) { start = Math.min(start, - delegate.getStartPosition(file, comment, t)); + delegate.getStartPosition(comment, t)); end = Math.max(end, - delegate.getEndPosition(file, comment, t)); + delegate.getEndPosition(comment, t)); } span = new long[] {(int) start - 1, (int) end + 1}; rewrittenTrees.add(tree); } else { - long treeEnd = delegate.getEndPosition(file, comment, tree); + long treeEnd = delegate.getEndPosition(comment, tree); span = new long[] {treeStart, treeEnd}; } diff --git a/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java b/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java index 35faab231af..215b412003d 100644 --- a/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java +++ b/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java @@ -464,7 +464,7 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { ImportTree it = findImport(tp); if (it != null && it.isModule()) { - int selectStart = (int) sp.getStartPosition(topLevel, tp.getLeaf()); + int selectStart = (int) sp.getStartPosition(tp.getLeaf()); String qualifiedPrefix = it.getQualifiedIdentifier().getKind() == Kind.MEMBER_SELECT ? ((MemberSelectTree) it.getQualifiedIdentifier()).getExpression().toString() + "." : ""; @@ -634,7 +634,7 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { Element annotationType = tp.getParentPath().getParentPath().getLeaf().getKind() == Kind.ANNOTATION ? at.trees().getElement(tp.getParentPath().getParentPath()) : at.trees().getElement(tp.getParentPath().getParentPath().getParentPath()); - if (sp.getEndPosition(topLevel, tp.getParentPath().getLeaf()) == (-1)) { + if (sp.getEndPosition(tp.getParentPath().getLeaf()) == (-1)) { //synthetic 'value': //TODO: filter out existing: addElements(javadoc, ElementFilter.methodsIn(annotationType.getEnclosedElements()), TRUE, TRUE, cursor, prefix, result); @@ -846,14 +846,14 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { new TreePathScanner() { @Override public Void visitIdentifier(IdentifierTree node, Void p) { - long start = sp.getStartPosition(cut, node); - long end = sp.getEndPosition(cut, node); + long start = sp.getStartPosition(node); + long end = sp.getEndPosition(node); handleElement(false, start, end); return super.visitIdentifier(node, p); } @Override public Void visitMemberSelect(MemberSelectTree node, Void p) { - long exprEnd = sp.getEndPosition(cut, node.getExpression()); + long exprEnd = sp.getEndPosition(node.getExpression()); Token ident = findTokensFrom(exprEnd, TokenKind.DOT, TokenKind.IDENTIFIER); if (ident != null) { handleElement(false, ident.pos, ident.endPos); @@ -866,16 +866,16 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { if (mods.getFlags().contains(Modifier.SEALED) || mods.getFlags().contains(Modifier.NON_SEALED)) { List modifierTokens = new ArrayList<>(); - long modsStart = sp.getStartPosition(cut, mods); - long modsEnd = sp.getEndPosition(cut, mods); + long modsStart = sp.getStartPosition(mods); + long modsEnd = sp.getEndPosition(mods); for (Token t : tokens) { if (t.pos >= modsStart && t.endPos <= modsEnd) { modifierTokens.add(t); } } for (AnnotationTree at : mods.getAnnotations()) { - long annStart = sp.getStartPosition(cut, at); - long annEnd = sp.getEndPosition(cut, at); + long annStart = sp.getStartPosition(at); + long annEnd = sp.getEndPosition(at); modifierTokens.removeIf(t -> t.pos >= annStart && t.endPos <= annEnd); } OUTER: for (int i = 0; i < modifierTokens.size(); i++) { @@ -912,7 +912,7 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { handleElement(true, ident.pos, ident.endPos); } if (!node.getPermitsClause().isEmpty()) { - long start = sp.getStartPosition(cut, node.getPermitsClause().get(0)); + long start = sp.getStartPosition(node.getPermitsClause().get(0)); Token permitsCandidate = findTokensBefore(start, TokenKind.IDENTIFIER); if (permitsCandidate != null && permitsCandidate.name().contentEquals("permits")) { addKeyword.accept(permitsCandidate); @@ -946,7 +946,7 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { } @Override public Void visitYield(YieldTree node, Void p) { - long start = sp.getStartPosition(cut, node); + long start = sp.getStartPosition(node); Token yield = findTokensFrom(start, TokenKind.IDENTIFIER); addKeyword.accept(yield); return super.visitYield(node, p); @@ -961,7 +961,7 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { @Override public Void scan(Tree tree, Void p) { if (tree != null) { - long end = sp.getEndPosition(cut, tree); + long end = sp.getEndPosition(tree); if (end == (-1)) { //synthetic return null; @@ -1072,14 +1072,14 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis { if (tree == null) return null; - long start = sp.getStartPosition(topLevel, tree); - long end = sp.getEndPosition(topLevel, tree); + long start = sp.getStartPosition(tree); + long end = sp.getEndPosition(tree); if (end == (-1) && tree.getKind() == Kind.ASSIGNMENT && getCurrentPath() != null && getCurrentPath().getLeaf().getKind() == Kind.ANNOTATION) { //the assignment is synthetically generated, take the end pos of the nested tree: - end = sp.getEndPosition(topLevel, ((AssignmentTree) tree).getExpression()); + end = sp.getEndPosition(((AssignmentTree) tree).getExpression()); } if (start <= wrapEndPos && wrapEndPos <= end && (deepest[0] == null || deepest[0].getLeaf() == getCurrentPath().getLeaf())) { diff --git a/src/jdk.jshell/share/classes/jdk/jshell/TreeDissector.java b/src/jdk.jshell/share/classes/jdk/jshell/TreeDissector.java index ef50f8ce71c..e5817f84206 100644 --- a/src/jdk.jshell/share/classes/jdk/jshell/TreeDissector.java +++ b/src/jdk.jshell/share/classes/jdk/jshell/TreeDissector.java @@ -119,11 +119,11 @@ class TreeDissector { } int getStartPosition(Tree tree) { - return (int) getSourcePositions().getStartPosition(targetCompilationUnit, tree); + return (int) getSourcePositions().getStartPosition(tree); } int getEndPosition(Tree tree) { - return (int) getSourcePositions().getEndPosition(targetCompilationUnit, tree); + return (int) getSourcePositions().getEndPosition(tree); } Range treeToRange(Tree tree) { From 7df06d1489164e7668e5ca43ba256c76acc7bd33 Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Wed, 1 Apr 2026 12:18:29 +0000 Subject: [PATCH 144/359] 8379395: [VectorAlgorithms] new dot-product implementation using fma Reviewed-by: mchevalier, chagedorn --- .../vectorization/TestVectorAlgorithms.java | 12 ++++++++++++ .../vectorization/VectorAlgorithmsImpl.java | 15 +++++++++++++++ .../bench/vm/compiler/VectorAlgorithms.java | 5 +++++ .../bench/vm/compiler/VectorAlgorithmsImpl.java | 15 +++++++++++++++ 4 files changed, 47 insertions(+) diff --git a/test/hotspot/jtreg/compiler/vectorization/TestVectorAlgorithms.java b/test/hotspot/jtreg/compiler/vectorization/TestVectorAlgorithms.java index 2667ac59471..70dc9a4a0b4 100644 --- a/test/hotspot/jtreg/compiler/vectorization/TestVectorAlgorithms.java +++ b/test/hotspot/jtreg/compiler/vectorization/TestVectorAlgorithms.java @@ -122,6 +122,7 @@ public class TestVectorAlgorithms { testGroups.get("dotProductF").put("dotProductF_loop", i -> { return dotProductF_loop(d.aF, d.bF); }); testGroups.get("dotProductF").put("dotProductF_VectorAPI_naive", i -> { return dotProductF_VectorAPI_naive(d.aF, d.bF); }); testGroups.get("dotProductF").put("dotProductF_VectorAPI_reduction_after_loop", i -> { return dotProductF_VectorAPI_reduction_after_loop(d.aF, d.bF); }); + testGroups.get("dotProductF").put("dotProductF_VectorAPI_fma", i -> { return dotProductF_VectorAPI_fma(d.aF, d.bF); }); testGroups.put("hashCodeB", new HashMap()); testGroups.get("hashCodeB").put("hashCodeB_loop", i -> { return hashCodeB_loop(d.aB); }); @@ -192,6 +193,7 @@ public class TestVectorAlgorithms { "dotProductF_loop", "dotProductF_VectorAPI_naive", "dotProductF_VectorAPI_reduction_after_loop", + "dotProductF_VectorAPI_fma", "hashCodeB_loop", "hashCodeB_Arrays", "hashCodeB_VectorAPI_v1", @@ -409,6 +411,16 @@ public class TestVectorAlgorithms { return VectorAlgorithmsImpl.dotProductF_VectorAPI_reduction_after_loop(a, b); } + @Test + @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", + IRNode.ADD_REDUCTION_V, "> 0", + IRNode.FMA_VF, "> 0"}, + applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseSuperWord", "true"}) + public float dotProductF_VectorAPI_fma(float[] a, float[] b) { + return VectorAlgorithmsImpl.dotProductF_VectorAPI_fma(a, b); + } + @Test public int hashCodeB_loop(byte[] a) { return VectorAlgorithmsImpl.hashCodeB_loop(a); diff --git a/test/hotspot/jtreg/compiler/vectorization/VectorAlgorithmsImpl.java b/test/hotspot/jtreg/compiler/vectorization/VectorAlgorithmsImpl.java index 8276d90509f..e4c9eb74e7d 100644 --- a/test/hotspot/jtreg/compiler/vectorization/VectorAlgorithmsImpl.java +++ b/test/hotspot/jtreg/compiler/vectorization/VectorAlgorithmsImpl.java @@ -348,6 +348,21 @@ public class VectorAlgorithmsImpl { return sum; } + public static float dotProductF_VectorAPI_fma(float[] a, float[] b) { + var sums = FloatVector.broadcast(SPECIES_F, 0.0f); + int i; + for (i = 0; i < SPECIES_F.loopBound(a.length); i += SPECIES_F.length()) { + var va = FloatVector.fromArray(SPECIES_F, a, i); + var vb = FloatVector.fromArray(SPECIES_F, b, i); + sums = va.fma(vb, sums); + } + float sum = sums.reduceLanes(VectorOperators.ADD); + for (; i < a.length; i++) { + sum = Math.fma(a[i], b[i], sum); + } + return sum; + } + public static int hashCodeB_loop(byte[] a) { int h = 1; for (int i = 0; i < a.length; i++) { diff --git a/test/micro/org/openjdk/bench/vm/compiler/VectorAlgorithms.java b/test/micro/org/openjdk/bench/vm/compiler/VectorAlgorithms.java index f60dfcb2d7c..0a6aa03586b 100644 --- a/test/micro/org/openjdk/bench/vm/compiler/VectorAlgorithms.java +++ b/test/micro/org/openjdk/bench/vm/compiler/VectorAlgorithms.java @@ -165,6 +165,11 @@ public class VectorAlgorithms { return VectorAlgorithmsImpl.dotProductF_VectorAPI_reduction_after_loop(d.aF, d.bF); } + @Benchmark + public float dotProductF_VectorAPI_fma() { + return VectorAlgorithmsImpl.dotProductF_VectorAPI_fma(d.aF, d.bF); + } + @Benchmark public int hashCodeB_loop() { return VectorAlgorithmsImpl.hashCodeB_loop(d.aB); diff --git a/test/micro/org/openjdk/bench/vm/compiler/VectorAlgorithmsImpl.java b/test/micro/org/openjdk/bench/vm/compiler/VectorAlgorithmsImpl.java index 3ae4ed81634..0d33a109d5b 100644 --- a/test/micro/org/openjdk/bench/vm/compiler/VectorAlgorithmsImpl.java +++ b/test/micro/org/openjdk/bench/vm/compiler/VectorAlgorithmsImpl.java @@ -348,6 +348,21 @@ public class VectorAlgorithmsImpl { return sum; } + public static float dotProductF_VectorAPI_fma(float[] a, float[] b) { + var sums = FloatVector.broadcast(SPECIES_F, 0.0f); + int i; + for (i = 0; i < SPECIES_F.loopBound(a.length); i += SPECIES_F.length()) { + var va = FloatVector.fromArray(SPECIES_F, a, i); + var vb = FloatVector.fromArray(SPECIES_F, b, i); + sums = va.fma(vb, sums); + } + float sum = sums.reduceLanes(VectorOperators.ADD); + for (; i < a.length; i++) { + sum = Math.fma(a[i], b[i], sum); + } + return sum; + } + public static int hashCodeB_loop(byte[] a) { int h = 1; for (int i = 0; i < a.length; i++) { From 9607a7284d5858aee735c7a0db36c88d5d2a3a24 Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Wed, 1 Apr 2026 12:18:49 +0000 Subject: [PATCH 145/359] 8380513: [VectorAlgorithms] mismatch benchmark and test Reviewed-by: mchevalier, galder, chagedorn --- .../vectorization/TestVectorAlgorithms.java | 38 ++++++++++ .../vectorization/VectorAlgorithmsImpl.java | 72 +++++++++++++++++++ .../bench/vm/compiler/VectorAlgorithms.java | 20 ++++++ .../vm/compiler/VectorAlgorithmsImpl.java | 72 +++++++++++++++++++ 4 files changed, 202 insertions(+) diff --git a/test/hotspot/jtreg/compiler/vectorization/TestVectorAlgorithms.java b/test/hotspot/jtreg/compiler/vectorization/TestVectorAlgorithms.java index 70dc9a4a0b4..ec1b43dd3f2 100644 --- a/test/hotspot/jtreg/compiler/vectorization/TestVectorAlgorithms.java +++ b/test/hotspot/jtreg/compiler/vectorization/TestVectorAlgorithms.java @@ -143,6 +143,12 @@ public class TestVectorAlgorithms { testGroups.get("findI").put("findI_loop", i -> { return findI_loop(d.aI, d.eI_findI[i]); }); testGroups.get("findI").put("findI_VectorAPI", i -> { return findI_VectorAPI(d.aI, d.eI_findI[i]); }); + testGroups.put("mismatchB", new HashMap()); + testGroups.get("mismatchB").put("mismatchB_loop", i -> { return d.wrap_mismatchB(i, TestVectorAlgorithms::mismatchB_loop); }); + testGroups.get("mismatchB").put("mismatchB_Arrays", i -> { return d.wrap_mismatchB(i, TestVectorAlgorithms::mismatchB_Arrays); }); + testGroups.get("mismatchB").put("mismatchB_MemorySegment", i -> { return d.wrap_mismatchB(i, TestVectorAlgorithms::mismatchB_MemorySegment); }); + testGroups.get("mismatchB").put("mismatchB_VectorAPI", i -> { return d.wrap_mismatchB(i, TestVectorAlgorithms::mismatchB_VectorAPI); }); + testGroups.put("reverseI", new HashMap()); testGroups.get("reverseI").put("reverseI_loop", i -> { return reverseI_loop(d.aI, d.rI1); }); testGroups.get("reverseI").put("reverseI_VectorAPI", i -> { return reverseI_VectorAPI(d.aI, d.rI2); }); @@ -205,6 +211,10 @@ public class TestVectorAlgorithms { "findMinIndexI_VectorAPI", "findI_loop", "findI_VectorAPI", + "mismatchB_loop", + "mismatchB_Arrays", + "mismatchB_MemorySegment", + "mismatchB_VectorAPI", "reverseI_loop", "reverseI_VectorAPI", "filterI_loop", @@ -521,6 +531,34 @@ public class TestVectorAlgorithms { return VectorAlgorithmsImpl.findI_VectorAPI(a, e); } + @Test + @IR(counts = {IRNode.LOAD_VECTOR_B, "= 0"}) + // Currently does not vectorize, but might in the future. + public static int mismatchB_loop(byte[] a, byte[] b) { + return VectorAlgorithmsImpl.mismatchB_loop(a, b); + } + + @Test + // Inlining makes IR rules difficult. Just keep this as a correctness test. + public static int mismatchB_Arrays(byte[] a, byte[] b) { + return VectorAlgorithmsImpl.mismatchB_Arrays(a, b); + } + + @Test + // Inlining makes IR rules difficult. Just keep this as a correctness test. + public static int mismatchB_MemorySegment(byte[] a, byte[] b) { + return VectorAlgorithmsImpl.mismatchB_MemorySegment(a, b); + } + + @Test + @IR(counts = {IRNode.LOAD_VECTOR_B, "> 0", + IRNode.VECTOR_MASK_CMP, "> 0", + IRNode.VECTOR_TEST, "> 0"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}) + public static int mismatchB_VectorAPI(byte[] a, byte[] b) { + return VectorAlgorithmsImpl.mismatchB_VectorAPI(a, b); + } + @Test @IR(counts = {IRNode.LOAD_VECTOR_I, "= 0", IRNode.STORE_VECTOR, "= 0"}) diff --git a/test/hotspot/jtreg/compiler/vectorization/VectorAlgorithmsImpl.java b/test/hotspot/jtreg/compiler/vectorization/VectorAlgorithmsImpl.java index e4c9eb74e7d..c06473d26c5 100644 --- a/test/hotspot/jtreg/compiler/vectorization/VectorAlgorithmsImpl.java +++ b/test/hotspot/jtreg/compiler/vectorization/VectorAlgorithmsImpl.java @@ -26,6 +26,7 @@ package compiler.vectorization; import java.util.Arrays; import java.util.Random; +import java.lang.foreign.MemorySegment; import jdk.incubator.vector.*; /** @@ -94,6 +95,15 @@ public class VectorAlgorithmsImpl { public int[] oopsX4; public int[] memX4; + // Input for mismatchB + // We set m1B and m2B to have identical data, temporarily edit m2B at one position, + // run the mismatch implementation, and then reset that position. This means we + // perform as little mutation while randomizing the input data. + public byte[] m1B; + public byte[] m2B; + public int[] mismatchB_idx; + public int mismatchB_idx_idx = 0; + public Data(int size, int seed, int numX4Objects, float branchProbability) { Random random = new Random(seed); @@ -165,6 +175,30 @@ public class VectorAlgorithmsImpl { ? (byte)(random.nextInt(16) + 'A') : (byte)(random.nextInt(16) + 'a'); } + + // Input data for mismatchB + m1B = new byte[size]; + m2B = new byte[size]; + random.nextBytes(m1B); + System.arraycopy(m1B, 0, m2B, 0, size); + + mismatchB_idx = new int[0x10000]; + for (int i = 0; i < mismatchB_idx.length; i++) { + // Sometimes make no mutation (-1), sometimes pick index for mutation. + mismatchB_idx[i] = (random.nextInt(10) == 0) ? -1 : random.nextInt(m1B.length); + } + } + + public interface MismatchBImpl { + int run(byte[] a, byte[] b); + } + + public int wrap_mismatchB(int idx, MismatchBImpl impl) { + int i = mismatchB_idx[idx & 0xffff]; + if (i != -1) { m2B[i]++; } + int res = impl.run(m1B, m2B); + if (i != -1) { m2B[i]--; } + return res; } } @@ -671,6 +705,44 @@ public class VectorAlgorithmsImpl { return -1; } + public static int mismatchB_loop(byte[] a, byte[] b) { + for (int i = 0; i < a.length; i++) { + if (a[i] != b[i]) { + return i; + } + } + return -1; + } + + public static int mismatchB_Arrays(byte[] a, byte[] b) { + return Arrays.mismatch(a, b); + } + + public static int mismatchB_MemorySegment(byte[] a, byte[] b) { + var aMS = MemorySegment.ofArray(a); + var bMS = MemorySegment.ofArray(b); + return (int) aMS.mismatch(bMS); + } + + public static int mismatchB_VectorAPI(byte[] a, byte[] b) { + int i = 0; + for (; i < SPECIES_B.loopBound(a.length); i += SPECIES_B.length()) { + ByteVector va = ByteVector.fromArray(SPECIES_B, a, i); + ByteVector vb = ByteVector.fromArray(SPECIES_B, b, i); + var mask = va.compare(VectorOperators.NE, vb); + if (mask.anyTrue()) { + return i + mask.firstTrue(); + } + } + for (; i < a.length; i++) { + if (a[i] != b[i]) { + return i; + } + } + return -1; + } + + public static Object reverseI_loop(int[] a, int[] r) { for (int i = 0; i < a.length; i++) { r[a.length - i - 1] = a[i]; diff --git a/test/micro/org/openjdk/bench/vm/compiler/VectorAlgorithms.java b/test/micro/org/openjdk/bench/vm/compiler/VectorAlgorithms.java index 0a6aa03586b..8f5d83c4ae3 100644 --- a/test/micro/org/openjdk/bench/vm/compiler/VectorAlgorithms.java +++ b/test/micro/org/openjdk/bench/vm/compiler/VectorAlgorithms.java @@ -232,6 +232,26 @@ public class VectorAlgorithms { return VectorAlgorithmsImpl.findI_VectorAPI(d.aI, e); } + @Benchmark + public int mismatchB_loop() { + return d.wrap_mismatchB(d.mismatchB_idx_idx++, VectorAlgorithmsImpl::mismatchB_loop); + } + + @Benchmark + public int mismatchB_Arrays() { + return d.wrap_mismatchB(d.mismatchB_idx_idx++, VectorAlgorithmsImpl::mismatchB_Arrays); + } + + @Benchmark + public int mismatchB_MemorySegment() { + return d.wrap_mismatchB(d.mismatchB_idx_idx++, VectorAlgorithmsImpl::mismatchB_MemorySegment); + } + + @Benchmark + public int mismatchB_VectorAPI() { + return d.wrap_mismatchB(d.mismatchB_idx_idx++, VectorAlgorithmsImpl::mismatchB_VectorAPI); + } + @Benchmark public Object reverseI_loop() { return VectorAlgorithmsImpl.reverseI_loop(d.aI, d.rI1); diff --git a/test/micro/org/openjdk/bench/vm/compiler/VectorAlgorithmsImpl.java b/test/micro/org/openjdk/bench/vm/compiler/VectorAlgorithmsImpl.java index 0d33a109d5b..a60ecc0f41a 100644 --- a/test/micro/org/openjdk/bench/vm/compiler/VectorAlgorithmsImpl.java +++ b/test/micro/org/openjdk/bench/vm/compiler/VectorAlgorithmsImpl.java @@ -26,6 +26,7 @@ package org.openjdk.bench.vm.compiler; import java.util.Arrays; import java.util.Random; +import java.lang.foreign.MemorySegment; import jdk.incubator.vector.*; /** @@ -94,6 +95,15 @@ public class VectorAlgorithmsImpl { public int[] oopsX4; public int[] memX4; + // Input for mismatchB + // We set m1B and m2B to have identical data, temporarily edit m2B at one position, + // run the mismatch implementation, and then reset that position. This means we + // perform as little mutation while randomizing the input data. + public byte[] m1B; + public byte[] m2B; + public int[] mismatchB_idx; + public int mismatchB_idx_idx = 0; + public Data(int size, int seed, int numX4Objects, float branchProbability) { Random random = new Random(seed); @@ -165,6 +175,30 @@ public class VectorAlgorithmsImpl { ? (byte)(random.nextInt(16) + 'A') : (byte)(random.nextInt(16) + 'a'); } + + // Input data for mismatchB + m1B = new byte[size]; + m2B = new byte[size]; + random.nextBytes(m1B); + System.arraycopy(m1B, 0, m2B, 0, size); + + mismatchB_idx = new int[0x10000]; + for (int i = 0; i < mismatchB_idx.length; i++) { + // Sometimes make no mutation (-1), sometimes pick index for mutation. + mismatchB_idx[i] = (random.nextInt(10) == 0) ? -1 : random.nextInt(m1B.length); + } + } + + public interface MismatchBImpl { + int run(byte[] a, byte[] b); + } + + public int wrap_mismatchB(int idx, MismatchBImpl impl) { + int i = mismatchB_idx[idx & 0xffff]; + if (i != -1) { m2B[i]++; } + int res = impl.run(m1B, m2B); + if (i != -1) { m2B[i]--; } + return res; } } @@ -671,6 +705,44 @@ public class VectorAlgorithmsImpl { return -1; } + public static int mismatchB_loop(byte[] a, byte[] b) { + for (int i = 0; i < a.length; i++) { + if (a[i] != b[i]) { + return i; + } + } + return -1; + } + + public static int mismatchB_Arrays(byte[] a, byte[] b) { + return Arrays.mismatch(a, b); + } + + public static int mismatchB_MemorySegment(byte[] a, byte[] b) { + var aMS = MemorySegment.ofArray(a); + var bMS = MemorySegment.ofArray(b); + return (int) aMS.mismatch(bMS); + } + + public static int mismatchB_VectorAPI(byte[] a, byte[] b) { + int i = 0; + for (; i < SPECIES_B.loopBound(a.length); i += SPECIES_B.length()) { + ByteVector va = ByteVector.fromArray(SPECIES_B, a, i); + ByteVector vb = ByteVector.fromArray(SPECIES_B, b, i); + var mask = va.compare(VectorOperators.NE, vb); + if (mask.anyTrue()) { + return i + mask.firstTrue(); + } + } + for (; i < a.length; i++) { + if (a[i] != b[i]) { + return i; + } + } + return -1; + } + + public static Object reverseI_loop(int[] a, int[] r) { for (int i = 0; i < a.length; i++) { r[a.length - i - 1] = a[i]; From f3a1c67b1cc2db2d6b3c0519737a6519ea4fbeea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20H=C3=BCbner?= Date: Wed, 1 Apr 2026 13:03:01 +0000 Subject: [PATCH 146/359] 8381464: Typo in Linker::captureCallState JavaDoc Reviewed-by: liach, pminborg --- src/java.base/share/classes/java/lang/foreign/Linker.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/java.base/share/classes/java/lang/foreign/Linker.java b/src/java.base/share/classes/java/lang/foreign/Linker.java index 1a7d33266aa..f597e4ee52e 100644 --- a/src/java.base/share/classes/java/lang/foreign/Linker.java +++ b/src/java.base/share/classes/java/lang/foreign/Linker.java @@ -833,7 +833,7 @@ public sealed interface Linker permits AbstractLinker { *

* Captured state can be stored in, or retrieved from the capture state segment by * constructing var handles from the {@linkplain #captureStateLayout capture state layout}. - * Some functions require this state the be initialized to a particular value before + * Some functions require this state to be initialized to a particular value before * invoking the downcall. *

* The following example demonstrates the use of this linker option: From d2c1907349afcbc40b2626060960511e2dca01d4 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Wed, 1 Apr 2026 14:20:53 +0000 Subject: [PATCH 147/359] 8381466: G1: Fix outdated name in G1Policy::decide_on_concurrent_start_pause Reviewed-by: tschatzl --- src/hotspot/share/gc/g1/g1Policy.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/gc/g1/g1Policy.cpp b/src/hotspot/share/gc/g1/g1Policy.cpp index b1c9f3a5b6f..5744bbc2f03 100644 --- a/src/hotspot/share/gc/g1/g1Policy.cpp +++ b/src/hotspot/share/gc/g1/g1Policy.cpp @@ -1256,7 +1256,7 @@ void G1Policy::decide_on_concurrent_start_pause() { // We are about to decide on whether this pause will be a // concurrent start pause. - // First, collector_state()->in_concurrent_start_gc() should not be already set. We + // First, collector_state()->is_in_concurrent_start_gc() should not already be set. We // will set it here if we have to. However, it should be cleared by // the end of the pause (it's only set for the duration of a // concurrent start pause). From 3fba38ab74aafab07e2cbec5f159e0d4cccaa440 Mon Sep 17 00:00:00 2001 From: Mikael Vidstedt Date: Wed, 1 Apr 2026 16:51:28 +0000 Subject: [PATCH 148/359] 8373521: Bump minimum boot jdk to JDK 26 Reviewed-by: liach, darcy, iris, erikj --- make/conf/github-actions.conf | 20 ++++++++++---------- make/conf/jib-profiles.js | 4 ++-- make/conf/version-numbers.conf | 4 ++-- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/make/conf/github-actions.conf b/make/conf/github-actions.conf index ebfc9191535..6771e8923dc 100644 --- a/make/conf/github-actions.conf +++ b/make/conf/github-actions.conf @@ -29,21 +29,21 @@ GTEST_VERSION=1.14.0 JTREG_VERSION=8.2.1+1 LINUX_X64_BOOT_JDK_EXT=tar.gz -LINUX_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk25/bd75d5f9689641da8e1daabeccb5528b/36/GPL/openjdk-25_linux-x64_bin.tar.gz -LINUX_X64_BOOT_JDK_SHA256=59cdcaf255add4721de38eb411d4ecfe779356b61fb671aee63c7dec78054c2b +LINUX_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk26/c3cc523845074aa0af4f5e1e1ed4151d/35/GPL/openjdk-26_linux-x64_bin.tar.gz +LINUX_X64_BOOT_JDK_SHA256=83c78367f8c81257beef72aca4bbbf8e6dac8ca2b3a4546a85879a09e6e4e128 ALPINE_LINUX_X64_BOOT_JDK_EXT=tar.gz -ALPINE_LINUX_X64_BOOT_JDK_URL=https://github.com/adoptium/temurin25-binaries/releases/download/jdk-25%2B36/OpenJDK25U-jdk_x64_alpine-linux_hotspot_25_36.tar.gz -ALPINE_LINUX_X64_BOOT_JDK_SHA256=637e47474d411ed86134f413af7d5fef4180ddb0bf556347b7e74a88cf8904c8 +ALPINE_LINUX_X64_BOOT_JDK_URL=https://github.com/adoptium/temurin26-binaries/releases/download/jdk-26%2B35/OpenJDK26U-jdk_x64_alpine-linux_hotspot_26_35.tar.gz +ALPINE_LINUX_X64_BOOT_JDK_SHA256=c105e581fdccb4e7120d889235d1ad8d5b2bed0af4972bc881e0a8ba687c94a4 MACOS_AARCH64_BOOT_JDK_EXT=tar.gz -MACOS_AARCH64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk25/bd75d5f9689641da8e1daabeccb5528b/36/GPL/openjdk-25_macos-aarch64_bin.tar.gz -MACOS_AARCH64_BOOT_JDK_SHA256=2006337bf326fdfdf6117081751ba38c1c8706d63419ecac7ff102ff7c776876 +MACOS_AARCH64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk26/c3cc523845074aa0af4f5e1e1ed4151d/35/GPL/openjdk-26_macos-aarch64_bin.tar.gz +MACOS_AARCH64_BOOT_JDK_SHA256=254586bcd1bf6dcd125ad667ac32562cb1e2ab1abf3a61fb117b6fabb571e765 MACOS_X64_BOOT_JDK_EXT=tar.gz -MACOS_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk25/bd75d5f9689641da8e1daabeccb5528b/36/GPL/openjdk-25_macos-x64_bin.tar.gz -MACOS_X64_BOOT_JDK_SHA256=47482ad9888991ecac9b2bcc131e2b53ff78aff275104cef85f66252308e8a09 +MACOS_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk26/c3cc523845074aa0af4f5e1e1ed4151d/35/GPL/openjdk-26_macos-x64_bin.tar.gz +MACOS_X64_BOOT_JDK_SHA256=8642b89d889c14ede2c446fd5bbe3621c8a3082e3df02013fd1658e39f52929a WINDOWS_X64_BOOT_JDK_EXT=zip -WINDOWS_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk25/bd75d5f9689641da8e1daabeccb5528b/36/GPL/openjdk-25_windows-x64_bin.zip -WINDOWS_X64_BOOT_JDK_SHA256=85bcc178461e2cb3c549ab9ca9dfa73afd54c09a175d6510d0884071867137d3 +WINDOWS_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk26/c3cc523845074aa0af4f5e1e1ed4151d/35/GPL/openjdk-26_windows-x64_bin.zip +WINDOWS_X64_BOOT_JDK_SHA256=2dd2d92c9374cd49a120fe9d916732840bf6bb9f0e0cc29794917a3c08b99c5f diff --git a/make/conf/jib-profiles.js b/make/conf/jib-profiles.js index 76a94b7789e..4c1d2835054 100644 --- a/make/conf/jib-profiles.js +++ b/make/conf/jib-profiles.js @@ -387,8 +387,8 @@ var getJibProfilesCommon = function (input, data) { }; }; - common.boot_jdk_version = "25"; - common.boot_jdk_build_number = "37"; + common.boot_jdk_version = "26"; + common.boot_jdk_build_number = "35"; common.boot_jdk_home = input.get("boot_jdk", "install_path") + "/jdk-" + common.boot_jdk_version + (input.build_os == "macosx" ? ".jdk/Contents/Home" : ""); diff --git a/make/conf/version-numbers.conf b/make/conf/version-numbers.conf index 4392d86ac33..4f63179ae05 100644 --- a/make/conf/version-numbers.conf +++ b/make/conf/version-numbers.conf @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2026, Oracle and/or its affiliates. All rights reserved. # 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,6 @@ DEFAULT_VERSION_DATE=2026-09-15 DEFAULT_VERSION_CLASSFILE_MAJOR=71 # "`$EXPR $DEFAULT_VERSION_FEATURE + 44`" DEFAULT_VERSION_CLASSFILE_MINOR=0 DEFAULT_VERSION_DOCS_API_SINCE=11 -DEFAULT_ACCEPTABLE_BOOT_VERSIONS="25 26 27" +DEFAULT_ACCEPTABLE_BOOT_VERSIONS="26 27" DEFAULT_JDK_SOURCE_TARGET_VERSION=27 DEFAULT_PROMOTED_VERSION_PRE=ea From eed91689f347e1e0491c4197ede680ef17d01062 Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Wed, 1 Apr 2026 17:10:40 +0000 Subject: [PATCH 149/359] 8381117: AOT training run fails if memory for ConstantPool is reused Reviewed-by: asmehra, iveresov, kvn --- .../share/cds/aotLinkedClassBulkLoader.cpp | 4 + src/hotspot/share/cds/aotMetaspace.cpp | 13 +- src/hotspot/share/cds/heapShared.cpp | 11 +- src/hotspot/share/cds/heapShared.hpp | 1 + .../share/classfile/classLoaderData.cpp | 4 +- src/hotspot/share/oops/instanceKlass.cpp | 1 + .../aotCache/RedefineClassesInProfile.java | 178 ++++++++++++++++++ .../test-classes/RedefGeneration0.java | 75 ++++++++ .../test-classes/RedefGeneration1.java | 54 ++++++ .../runtime/cds/appcds/test-classes/Util.java | 5 +- 10 files changed, 336 insertions(+), 10 deletions(-) create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/aotCache/RedefineClassesInProfile.java create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/aotCache/test-classes/RedefGeneration0.java create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/aotCache/test-classes/RedefGeneration1.java diff --git a/src/hotspot/share/cds/aotLinkedClassBulkLoader.cpp b/src/hotspot/share/cds/aotLinkedClassBulkLoader.cpp index 6a60177fc40..8129e6a5a81 100644 --- a/src/hotspot/share/cds/aotLinkedClassBulkLoader.cpp +++ b/src/hotspot/share/cds/aotLinkedClassBulkLoader.cpp @@ -280,6 +280,10 @@ void AOTLinkedClassBulkLoader::init_non_javabase_classes_impl(TRAPS) { tty->print_cr("==================== archived_training_data ** after all classes preloaded ===================="); TrainingData::print_archived_training_data_on(tty); } + LogStreamHandle(Info, aot, training, data) log; + if (log.is_enabled()) { + TrainingData::print_archived_training_data_on(&log); + } } // For the AOT cache to function properly, all classes in the AOTLinkedClassTable diff --git a/src/hotspot/share/cds/aotMetaspace.cpp b/src/hotspot/share/cds/aotMetaspace.cpp index 55e9f93b3ab..4c23ede9cb8 100644 --- a/src/hotspot/share/cds/aotMetaspace.cpp +++ b/src/hotspot/share/cds/aotMetaspace.cpp @@ -949,11 +949,18 @@ void AOTMetaspace::dump_static_archive(TRAPS) { ResourceMark rm(THREAD); HandleMark hm(THREAD); - if (CDSConfig::is_dumping_final_static_archive() && AOTPrintTrainingInfo) { - tty->print_cr("==================== archived_training_data ** before dumping ===================="); - TrainingData::print_archived_training_data_on(tty); + if (CDSConfig::is_dumping_final_static_archive()) { + if (AOTPrintTrainingInfo) { + tty->print_cr("==================== archived_training_data ** before dumping ===================="); + TrainingData::print_archived_training_data_on(tty); + } + LogStreamHandle(Info, aot, training, data) log; + if (log.is_enabled()) { + TrainingData::print_archived_training_data_on(&log); + } } + StaticArchiveBuilder builder; dump_static_archive_impl(builder, THREAD); if (HAS_PENDING_EXCEPTION) { diff --git a/src/hotspot/share/cds/heapShared.cpp b/src/hotspot/share/cds/heapShared.cpp index f721b4b370c..d75816656b0 100644 --- a/src/hotspot/share/cds/heapShared.cpp +++ b/src/hotspot/share/cds/heapShared.cpp @@ -689,11 +689,6 @@ public: }; void HeapShared::add_scratch_resolved_references(ConstantPool* src, objArrayOop dest) { - if (CDSConfig::is_dumping_preimage_static_archive() && scratch_resolved_references(src) != nullptr) { - // We are in AOT training run. The class has been redefined and we are giving it a new resolved_reference. - // Ignore it, as this class will be excluded from the AOT config. - return; - } if (SystemDictionaryShared::is_builtin_loader(src->pool_holder()->class_loader_data())) { _scratch_objects_table->set_oop(src, dest); } @@ -703,6 +698,12 @@ objArrayOop HeapShared::scratch_resolved_references(ConstantPool* src) { return (objArrayOop)_scratch_objects_table->get_oop(src); } +void HeapShared::remove_scratch_resolved_references(ConstantPool* src) { + if (CDSConfig::is_dumping_heap()) { + _scratch_objects_table->remove_oop(src); + } +} + void HeapShared::init_dumping() { _scratch_objects_table = new (mtClass)MetaspaceObjToOopHandleTable(); _pending_roots = new GrowableArrayCHeap(500); diff --git a/src/hotspot/share/cds/heapShared.hpp b/src/hotspot/share/cds/heapShared.hpp index c3ad1f666b1..10ea35ab56e 100644 --- a/src/hotspot/share/cds/heapShared.hpp +++ b/src/hotspot/share/cds/heapShared.hpp @@ -451,6 +451,7 @@ private: static void write_heap(AOTMappedHeapInfo* mapped_heap_info, AOTStreamedHeapInfo* streamed_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 remove_scratch_resolved_references(ConstantPool* src) NOT_CDS_JAVA_HEAP_RETURN; static void init_dumping() 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; diff --git a/src/hotspot/share/classfile/classLoaderData.cpp b/src/hotspot/share/classfile/classLoaderData.cpp index dfc3b74db96..d1ea9c09d4c 100644 --- a/src/hotspot/share/classfile/classLoaderData.cpp +++ b/src/hotspot/share/classfile/classLoaderData.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ // The bootstrap loader (represented by null) also has a ClassLoaderData, // the singleton class the_null_class_loader_data(). +#include "cds/heapShared.hpp" #include "classfile/classLoaderData.inline.hpp" #include "classfile/classLoaderDataGraph.inline.hpp" #include "classfile/dictionary.hpp" @@ -899,6 +900,7 @@ void ClassLoaderData::free_deallocate_list() { if (m->is_method()) { MetadataFactory::free_metadata(this, (Method*)m); } else if (m->is_constantPool()) { + HeapShared::remove_scratch_resolved_references((ConstantPool*)m); MetadataFactory::free_metadata(this, (ConstantPool*)m); } else if (m->is_klass()) { MetadataFactory::free_metadata(this, (InstanceKlass*)m); diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp index cb071f2abf0..d675e61cc05 100644 --- a/src/hotspot/share/oops/instanceKlass.cpp +++ b/src/hotspot/share/oops/instanceKlass.cpp @@ -704,6 +704,7 @@ void InstanceKlass::deallocate_contents(ClassLoaderData* loader_data) { if (constants() != nullptr) { assert (!constants()->on_stack(), "shouldn't be called if anything is onstack"); if (!constants()->in_aot_cache()) { + HeapShared::remove_scratch_resolved_references(constants()); MetadataFactory::free_metadata(loader_data, constants()); } // Delete any cached resolution errors for the constant pool diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/RedefineClassesInProfile.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/RedefineClassesInProfile.java new file mode 100644 index 00000000000..f311629b2de --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/RedefineClassesInProfile.java @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 Class redefinition during training run + * @bug 8381117 + * @requires vm.cds.supports.aot.class.linking + * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds/test-classes + * + * @compile test-classes/RedefGeneration0.java + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar redef0.jar + * RedefFoo RedefBar + * RedefTaz0 RedefTaz1 RedefTaz2 RedefTaz3 RedefTaz4 + * Qux0 Qux1 Qux2 Qux3 Qux4 + * Qux5 Qux6 Qux7 Qux8 Qux9 + * + * @compile test-classes/RedefGeneration1.java + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar redef1.jar + * RedefFoo RedefBar + * RedefTaz0 RedefTaz1 RedefTaz2 RedefTaz3 RedefTaz4 + + * @run driver RedefineClassHelper + * @build RedefineClassesInProfile + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app.jar RedefineClassesInProfileApp Util + * @run driver RedefineClassesInProfile + */ + +import java.io.File; +import jdk.test.lib.cds.SimpleCDSAppTester; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +public class RedefineClassesInProfile { + public static void main(String... args) throws Exception { + SimpleCDSAppTester.of("RedefineClassesInProfile") + // redefineagent.jar is created by "@run driver RedefineClassHelper" + .addVmArgs("-javaagent:redefineagent.jar") + .addVmArgs("-Xlog:aot,aot+class=debug") + .addVmArgs("-Xlog:redefine+class+load") + .addVmArgs("-Xlog:aot+training+data") + .classpath("redef0.jar" + File.pathSeparator + "app.jar") + .appCommandLine("RedefineClassesInProfileApp") + .setTrainingChecker((OutputAnalyzer out) -> { + out.shouldContain("Skipping RedefFoo: Has been redefined"); + out.shouldContain("Skipping RedefBar: Has been redefined"); + + for (int i = 0; i < RedefineClassesInProfileApp.num_taz; i++) { + out.shouldMatch("redefine,class,load.*redefined name=RedefTaz" + i); + } + for (int i = 0; i < RedefineClassesInProfileApp.num_qux; i++) { + out.shouldMatch("aot,class.*klasses.*app *Qux" + i); + } + }) + .setAssemblyChecker((OutputAnalyzer out) -> { + out.shouldNotContain("RedefFoo"); + + // The names of the Redef* classes should not appear in training data, + // as these classes have been redefined and excluded from the AOT cache. + // + // Note: do not pass Redef* as parameters in any of the methods that can be + // stored into the AOT cache, or else the substring Redef* may appear in + // method signatures, and make the following checks fail. + String prefix = "aot,training,data.*"; + + out.shouldMatch(prefix + "RedefineClassesInProfileApp"); // sanity + out.shouldNotMatch(prefix + "RedefFoo"); + out.shouldNotMatch(prefix + "RedefBar"); + out.shouldNotMatch(prefix + "RedefTaz"); + }) + .setProductionChecker((OutputAnalyzer out) -> { + out.shouldContain("Redefined: class RedefBar"); + out.shouldContain("Redefined: class RedefFoo"); + }) + .runAOTWorkflow(); + } +} + +class RedefineClassesInProfileApp { + static final int num_taz = 5; + static final int num_qux = 10; + + public static void main(String[] args) throws Exception { + test1(); + } + + // test1 + // (1) Training run should work fine even if ConstantPool from redefined classes + // are reused by classes that are loaded later. See JDK-8381117 + // (2) Pointers to redefined classes should be cleaned from TrainingData. + static void test1() throws Exception { + String jarFile = "redef1.jar"; + Runnable dummy = () -> {}; + Runnable redef_bar = () -> { redefine(jarFile, RedefBar.class); }; + Runnable redef_foo = () -> { redefine(jarFile, RedefFoo.class); }; + + hotspot1(); + + int c1 = RedefFoo.foo1(dummy); + check("c1", c1, 1); + + int c2 = RedefFoo.foo1(redef_bar); + check("c2", c2, 12); + + int c3 = RedefFoo.foo1(redef_foo); + check("c3", c3, 22); + + int c4 = RedefFoo.foo1(dummy); + check("c4", c4, 22); + + // Redefine the RedefTaz* classes. This should free some constant pools + for (int i = 0; i < num_taz; i++) { + Class.forName("RedefTaz" + i); + } + for (int i = 0; i < num_taz; i++) { + redefine(jarFile, Class.forName("RedefTaz" + i)); + } + + // Load the Qux* classes. They *might* reuse the constant pools + // freed from above. See comments in test-classes/RedefGeneration0.java + // about the crash condition for JDK-8381117. + for (int i = 0; i < num_qux; i++) { + Class.forName("Qux" + i); + } + } + + static volatile int x; + static void hotspot1() { + long start = System.currentTimeMillis(); + // run this loop long enough (400ms) for it to be JIT compiled. + while (System.currentTimeMillis() - start < 400) { + // RedefFoo will be excluded fro the AOT configuration file, so + // any reference to RedefFoo recorded in TrainingData should be + // also be removed. If not, we are likely to see a crash in + // the assembly phase or production run. + x += RedefFoo.foo0(); + } + } + + static void check(String name, int actual, int expect) { + System.out.println(name + " = " + actual); + if (actual != expect) { + throw new RuntimeException(name + " should be " + expect + ", but is " + actual); + } + } + + static void redefine(String jarFile, Class c) { + try { + byte[] b = Util.getClassFileFromJar(jarFile, c.getName()); + RedefineClassHelper.redefineClass(c, b); + System.out.println("Redefined: " + c + ", Length = " + b.length); + } catch (Throwable t) { + throw new RuntimeException("Unexpected failure", t); + } + } +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/test-classes/RedefGeneration0.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/test-classes/RedefGeneration0.java new file mode 100644 index 00000000000..27542b94e98 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/test-classes/RedefGeneration0.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +// These are "generation 0" test classes used in redefinition tests. +// These classes are loaded from the classpath, and will later be redefined +// with the versions in RedefGeneration1.java + +class RedefFoo { + static int foo0() { + return 10; + } + static int foo1(Runnable r) { + return RedefBar.bar0(r); + } +} + +class RedefBar { + static int bar0(Runnable r) { + r.run(); + return bar1(); + } + static int bar1() { + return 1; + } +} + +// The following classes will be redefined +class RedefTaz0 { static int x1, x2, x3, x4, x5; int a; Runnable x() { return () -> {a += 1;}; } } +class RedefTaz1 { static int x1, x2, x3, x4, x5; int a; Runnable x() { return () -> {a += 1;}; } } +class RedefTaz2 { static int x1, x2, x3, x4, x5; int a; Runnable x() { return () -> {a += 1;}; } } +class RedefTaz3 { static int x1, x2, x3, x4, x5; int a; Runnable x() { return () -> {a += 1;}; } } +class RedefTaz4 { static int x1, x2, x3, x4, x5; int a; Runnable x() { return () -> {a += 1;}; } } + +// The following classes will be loaded after the RedefTaz* classes are redefined. +// They may reuse the constant pools that were freed during the redefinitions of RedefTaz*. +// +// These classes are NOT redefined in the training run, so they should be stored into AOT +// configuration and AOT cache. +// +// The Qux classes have a smaller constant pool size (as defined in the classfile) than the +// Taz classes, so they are likely to reuse the space of the constant pools freed from Taz. +// However, Qux uses a larger ConstantPool::resolved_reference(), as it has one extra +// String. Without the JDK-8381117 fix, the JVM would crash during the training run inside +// ConstantPool::prepare_resolved_references_for_archiving(). +class Qux0 { static final String s = "x"; int a; Runnable x() { return () -> {a += 1;}; } } +class Qux1 { static final String s = "x"; int a; Runnable x() { return () -> {a += 1;}; } } +class Qux2 { static final String s = "x"; int a; Runnable x() { return () -> {a += 1;}; } } +class Qux3 { static final String s = "x"; int a; Runnable x() { return () -> {a += 1;}; } } +class Qux4 { static final String s = "x"; int a; Runnable x() { return () -> {a += 1;}; } } +class Qux5 { static final String s = "x"; int a; Runnable x() { return () -> {a += 1;}; } } +class Qux6 { static final String s = "x"; int a; Runnable x() { return () -> {a += 1;}; } } +class Qux7 { static final String s = "x"; int a; Runnable x() { return () -> {a += 1;}; } } +class Qux8 { static final String s = "x"; int a; Runnable x() { return () -> {a += 1;}; } } +class Qux9 { static final String s = "x"; int a; Runnable x() { return () -> {a += 1;}; } } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/test-classes/RedefGeneration1.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/test-classes/RedefGeneration1.java new file mode 100644 index 00000000000..56261aefe16 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/test-classes/RedefGeneration1.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +// These are "generation 1" test classes used in redefinition tests. +// They are used to redefine the classes that were compiled from RedefGeneration0.java. + +class RedefFoo { + static int foo0() { + // WAS: return 10 + return 20; + } + static int foo1(Runnable r) { + return RedefBar.bar0(r); + } +} + +class RedefBar { + static int bar0(Runnable r) { + r.run(); + return bar1(); + } + + static int bar1() { + // WAS: return 1; + return 2 + RedefFoo.foo0(); + } +} + +class RedefTaz0 { static int x1, x2, x3, x4, x5; int a; Runnable x() { return () -> {a += 2;}; } } +class RedefTaz1 { static int x1, x2, x3, x4, x5; int a; Runnable x() { return () -> {a += 2;}; } } +class RedefTaz2 { static int x1, x2, x3, x4, x5; int a; Runnable x() { return () -> {a += 2;}; } } +class RedefTaz3 { static int x1, x2, x3, x4, x5; int a; Runnable x() { return () -> {a += 2;}; } } +class RedefTaz4 { static int x1, x2, x3, x4, x5; int a; Runnable x() { return () -> {a += 2;}; } } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/test-classes/Util.java b/test/hotspot/jtreg/runtime/cds/appcds/test-classes/Util.java index 295505003a8..e83865d5f03 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/test-classes/Util.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/test-classes/Util.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -104,6 +104,9 @@ public class Util { return b; } + public static byte[] getClassFileFromJar(String jarFile, String className) throws FileNotFoundException, IOException { + return getClassFileFromJar(new File(jarFile), className); + } public static byte[] getClassFileFromJar(File jarFile, String className) throws FileNotFoundException, IOException { JarFile jf = new JarFile(jarFile); JarEntry ent = jf.getJarEntry(className.replace('.', '/') + ".class"); From 9131c72d63cac7d2a0e845952cee0e3c7edbfc93 Mon Sep 17 00:00:00 2001 From: Weijun Wang Date: Wed, 1 Apr 2026 17:49:31 +0000 Subject: [PATCH 150/359] 8368692: Restrict Password::readPassword from reading from System.in Reviewed-by: mullan --- .../classes/sun/security/util/Password.java | 47 +++++++++---- .../share/conf/security/java.security | 29 ++++++++ .../security/tools/keytool/AllowSystemIn.java | 70 +++++++++++++++++++ 3 files changed, 133 insertions(+), 13 deletions(-) create mode 100644 test/jdk/sun/security/tools/keytool/AllowSystemIn.java diff --git a/src/java.base/share/classes/sun/security/util/Password.java b/src/java.base/share/classes/sun/security/util/Password.java index 02cdcaf53fd..c1b44856c8b 100644 --- a/src/java.base/share/classes/sun/security/util/Password.java +++ b/src/java.base/share/classes/sun/security/util/Password.java @@ -29,6 +29,7 @@ import java.io.*; import java.nio.*; import java.nio.charset.*; import java.util.Arrays; +import java.util.Locale; import jdk.internal.access.SharedSecrets; import jdk.internal.io.JdkConsoleImpl; @@ -43,6 +44,22 @@ public class Password { return readPassword(in, false); } + private static final boolean ALLOW_STDIN; + static { + var value = SecurityProperties.getOverridableProperty( + "jdk.security.password.allowSystemIn"); + if (value != null) { + value = value.toLowerCase(Locale.ROOT); + } + ALLOW_STDIN = switch (value) { + case null -> true; // Default true now + case "true" -> true; + case "false" -> false; + default -> throw new IllegalArgumentException( + "Invalid jdk.security.password.allowSystemIn value: " + value); + }; + } + /** Reads user password from given input stream. * @param isEchoOn true if the password should be echoed on the screen */ @@ -66,19 +83,23 @@ public class Password { } consoleBytes = ConsoleHolder.convertToBytes(consoleEntered); in = new ByteArrayInputStream(consoleBytes); - } else if (in == System.in && VM.isBooted() - && System.in.available() == 0) { - // Warn if reading password from System.in but it's empty. - // This may be running in an IDE Run Window or in JShell, - // which acts like an interactive console and echoes the - // entered password. In this case, print a warning that - // the password might be echoed. If available() is not zero, - // it's more likely the input comes from a pipe, such as - // "echo password |" or "cat password_file |" where input - // will be silently consumed without echoing to the screen. - // Warn only if VM is booted and ResourcesMgr is available. - System.err.print(ResourcesMgr.getString - ("warning.input.may.be.visible.on.screen")); + } else if (in == System.in) { + if (!ALLOW_STDIN) { + throw new UnsupportedOperationException("Console not available." + + " Reading passwords from standard input is disallowed."); + } else if (VM.isBooted() && in.available() == 0) { + // Warn if reading password from System.in but it's empty. + // This may be running in an IDE Run Window or in JShell, + // which acts like an interactive console and echoes the + // entered password. In this case, print a warning that + // the password might be echoed. If available() is not zero, + // it's more likely the input comes from a pipe, such as + // "echo password |" or "cat password_file |" where input + // will be silently consumed without echoing to the screen. + // Warn only if VM is booted and ResourcesMgr is available. + System.err.print(ResourcesMgr.getString + ("warning.input.may.be.visible.on.screen")); + } } } diff --git a/src/java.base/share/conf/security/java.security b/src/java.base/share/conf/security/java.security index d5d0488a004..976604b5cbc 100644 --- a/src/java.base/share/conf/security/java.security +++ b/src/java.base/share/conf/security/java.security @@ -1725,3 +1725,32 @@ com.sun.security.allowedAIALocations= # #jdk.mlkem.pkcs8.encoding = seed #jdk.mldsa.pkcs8.encoding = seed + +# +# Policy for reading passwords from System.in +# +# When Java needs to read a password, whether it's via a tool such as keytool or +# kinit, or by an API such as PasswordCallback with echo off, it normally reads +# directly from the console. If the console is not available, Java falls back +# to reading from the standard input stream ("System.in"), which typically +# represents a redirected file or an inter-process pipe. This fallback is not +# formally specified, and is not widely adopted by tools from other vendors. +# +# This security property determines whether passwords can be read from the +# standard input stream when a console is not available. The value can be set +# to either "true" or "false". If the value is set to "false", attempting +# to read passwords from the standard input stream without a console will +# throw an exception. The default value is "true". This default may change +# in a future release. +# +# If a system property of the same name is also specified, it supersedes the +# security property value defined here. +# +# Note: This property applies only to password reading from the standard input +# stream. It does not affect other supported password sources. For example, the +# JAAS KeyStoreLoginModule allows a password to be read from the user-specified +# "keyStorePasswordURL" option. The keytool and jarsigner commands also support +# options such as "-storepass:env" and "-storepass:file" that read passwords +# from an environment variable or a file. +# +#jdk.security.password.allowSystemIn = true diff --git a/test/jdk/sun/security/tools/keytool/AllowSystemIn.java b/test/jdk/sun/security/tools/keytool/AllowSystemIn.java new file mode 100644 index 00000000000..04373f8ba26 --- /dev/null +++ b/test/jdk/sun/security/tools/keytool/AllowSystemIn.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8368692 + * @summary Restrict Password::readPassword from reading from System.in + * @library /test/lib + * @run main AllowSystemIn succeed + * @run main/othervm -Djdk.security.password.allowSystemIn=true AllowSystemIn succeed + * @run main/othervm -Djdk.security.password.allowSystemIn=false AllowSystemIn fail + * @run main/othervm -Djdk.security.password.allowSystemIn=bogus AllowSystemIn invalid + */ + +import com.sun.security.auth.callback.TextCallbackHandler; +import jdk.test.lib.Asserts; + +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.PasswordCallback; +import java.io.ByteArrayInputStream; +import java.nio.charset.StandardCharsets; + +public class AllowSystemIn{ + + public static void main(String[] args) throws Exception { + switch (args[0]) { + case "succeed" -> Asserts.assertEQ("password", getPassword()); + case "fail" -> Asserts.assertThrows( + UnsupportedOperationException.class, + AllowSystemIn::getPassword); + case "invalid" -> Asserts.assertThrows( + ExceptionInInitializerError.class, // implementation detail + AllowSystemIn::getPassword); + } + } + + static String getPassword() throws Exception { + var in = System.in; + try { + var bin = new ByteArrayInputStream( + "password".getBytes(StandardCharsets.UTF_8)); + System.setIn(bin); + var pb = new PasswordCallback("> ", false); + new TextCallbackHandler().handle(new Callback[]{pb}); + return new String(pb.getPassword()); + } finally { + System.setIn(in); + } + } +} From 3cb4d7db19bb7b3daf5921dd5d98e3cbc6608051 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Wed, 1 Apr 2026 18:36:47 +0000 Subject: [PATCH 151/359] 8381037: Remove AppContext from miscellaneous awt shared classes Reviewed-by: azvegint, dnguyen --- .../classes/java/awt/EventDispatchThread.java | 6 +- .../java/awt/KeyboardFocusManager.java | 5 +- .../share/classes/java/awt/SentEvent.java | 15 +- .../classes/java/awt/WaitDispatchSupport.java | 4 +- .../share/classes/sun/awt/EmbeddedFrame.java | 9 +- .../classes/sun/awt/GlobalCursorManager.java | 4 +- .../sun/awt/KeyboardFocusManagerPeerImpl.java | 6 +- .../classes/sun/awt/PaintEventDispatcher.java | 4 +- .../classes/sun/font/SunFontManager.java | 24 +- .../swing/system/6799345/TestShutdown.java | 205 ------------------ .../awt/AppContext/8012933/Test8012933.java | 93 -------- 11 files changed, 20 insertions(+), 355 deletions(-) delete mode 100644 test/jdk/javax/swing/system/6799345/TestShutdown.java delete mode 100644 test/jdk/sun/awt/AppContext/8012933/Test8012933.java diff --git a/src/java.desktop/share/classes/java/awt/EventDispatchThread.java b/src/java.desktop/share/classes/java/awt/EventDispatchThread.java index b817ca12ece..1a991741fab 100644 --- a/src/java.desktop/share/classes/java/awt/EventDispatchThread.java +++ b/src/java.desktop/share/classes/java/awt/EventDispatchThread.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -203,8 +203,8 @@ class EventDispatchThread extends Thread { eq.dispatchEvent(event); } catch (InterruptedException interruptedException) { - doDispatch = false; // AppContext.dispose() interrupts all - // Threads in the AppContext + // keep this catch case for compatibility + doDispatch = false; } catch (Throwable e) { processException(e); diff --git a/src/java.desktop/share/classes/java/awt/KeyboardFocusManager.java b/src/java.desktop/share/classes/java/awt/KeyboardFocusManager.java index 06932d33f8a..9b55e754a64 100644 --- a/src/java.desktop/share/classes/java/awt/KeyboardFocusManager.java +++ b/src/java.desktop/share/classes/java/awt/KeyboardFocusManager.java @@ -2264,15 +2264,14 @@ public abstract class KeyboardFocusManager temporary, descendant, cause); // Fix 5028014. Rolled out. // SunToolkit.postPriorityEvent(currentFocusOwnerEvent); - SunToolkit.postEvent(currentFocusOwner.appContext, - currentFocusOwnerEvent); + SunToolkit.postEvent(currentFocusOwnerEvent); } FocusEvent newFocusOwnerEvent = new FocusEvent(descendant, FocusEvent.FOCUS_GAINED, temporary, currentFocusOwner, cause); // Fix 5028014. Rolled out. // SunToolkit.postPriorityEvent(newFocusOwnerEvent); - SunToolkit.postEvent(descendant.appContext, newFocusOwnerEvent); + SunToolkit.postEvent(newFocusOwnerEvent); if (focusLog.isLoggable(PlatformLogger.Level.FINEST)) focusLog.finest("2. SNFH_HANDLED for {0}", String.valueOf(descendant)); diff --git a/src/java.desktop/share/classes/java/awt/SentEvent.java b/src/java.desktop/share/classes/java/awt/SentEvent.java index 632b4ee85a8..eb85fa1453d 100644 --- a/src/java.desktop/share/classes/java/awt/SentEvent.java +++ b/src/java.desktop/share/classes/java/awt/SentEvent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,7 +27,6 @@ package java.awt; import java.io.Serial; -import sun.awt.AppContext; import sun.awt.SunToolkit; /** @@ -51,22 +50,16 @@ class SentEvent extends AWTEvent implements ActiveEvent { boolean dispatched; private AWTEvent nested; - @SuppressWarnings("serial") // Not statically typed as Serializable - private AppContext toNotify; SentEvent() { this(null); } SentEvent(AWTEvent nested) { - this(nested, null); - } - SentEvent(AWTEvent nested, AppContext toNotify) { super((nested != null) ? nested.getSource() : Toolkit.getDefaultToolkit(), ID); this.nested = nested; - this.toNotify = toNotify; } public void dispatch() { @@ -76,9 +69,6 @@ class SentEvent extends AWTEvent implements ActiveEvent { } } finally { dispatched = true; - if (toNotify != null) { - SunToolkit.postEvent(toNotify, new SentEvent()); - } synchronized (this) { notifyAll(); } @@ -86,9 +76,6 @@ class SentEvent extends AWTEvent implements ActiveEvent { } final void dispose() { dispatched = true; - if (toNotify != null) { - SunToolkit.postEvent(toNotify, new SentEvent()); - } synchronized (this) { notifyAll(); } diff --git a/src/java.desktop/share/classes/java/awt/WaitDispatchSupport.java b/src/java.desktop/share/classes/java/awt/WaitDispatchSupport.java index 71e8b3086a1..3e567f538b1 100644 --- a/src/java.desktop/share/classes/java/awt/WaitDispatchSupport.java +++ b/src/java.desktop/share/classes/java/awt/WaitDispatchSupport.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -211,8 +211,6 @@ class WaitDispatchSupport implements SecondaryLoop { } }, interval); } - // Dispose SequencedEvent we are dispatching on the current - // AppContext, to prevent us from hang - see 4531693 for details SequencedEvent currentSE = KeyboardFocusManager. getCurrentKeyboardFocusManager().getCurrentSequencedEvent(); if (currentSE != null) { diff --git a/src/java.desktop/share/classes/sun/awt/EmbeddedFrame.java b/src/java.desktop/share/classes/sun/awt/EmbeddedFrame.java index ab2ad5dfbf0..fa8ed1e707c 100644 --- a/src/java.desktop/share/classes/sun/awt/EmbeddedFrame.java +++ b/src/java.desktop/share/classes/sun/awt/EmbeddedFrame.java @@ -164,11 +164,8 @@ public abstract class EmbeddedFrame extends Frame } /** - * Because there may be many AppContexts, and we can't be sure where this - * EmbeddedFrame is first created or shown, we can't automatically determine - * the correct KeyboardFocusManager to attach to as KeyEventDispatcher. * Those who want to use the functionality of traversing out of the EmbeddedFrame - * must call this method on the AppContext. After that, all the changes + * must call this method. After that, all the changes * can be handled automatically, including possible replacement of * KeyboardFocusManager. */ @@ -184,7 +181,7 @@ public abstract class EmbeddedFrame extends Frame /** * Needed to avoid memory leak: we register this EmbeddedFrame as a listener with - * KeyboardFocusManager of an AppContext. We don't want the KFM to keep + * the KeyboardFocusManager. We don't want the KFM to keep * reference to our EmbeddedFrame forever if the Frame is no longer in use, so we * add listeners in show() and remove them in hide(). */ @@ -198,7 +195,7 @@ public abstract class EmbeddedFrame extends Frame /** * Needed to avoid memory leak: we register this EmbeddedFrame as a listener with - * KeyboardFocusManager of an AppContext. We don't want the KFM to keep + * the KeyboardFocusManager. We don't want the KFM to keep * reference to our EmbeddedFrame forever if the Frame is no longer in use, so we * add listeners in show() and remove them in hide(). */ diff --git a/src/java.desktop/share/classes/sun/awt/GlobalCursorManager.java b/src/java.desktop/share/classes/sun/awt/GlobalCursorManager.java index 27893d0ce87..8638bf81921 100644 --- a/src/java.desktop/share/classes/sun/awt/GlobalCursorManager.java +++ b/src/java.desktop/share/classes/sun/awt/GlobalCursorManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -61,7 +61,7 @@ public abstract class GlobalCursorManager { } } if (shouldPost) { - SunToolkit.postEvent(SunToolkit.targetToAppContext(heavy), in); + SunToolkit.postEvent(in); } } } diff --git a/src/java.desktop/share/classes/sun/awt/KeyboardFocusManagerPeerImpl.java b/src/java.desktop/share/classes/sun/awt/KeyboardFocusManagerPeerImpl.java index ef50d883ee5..909c0b58136 100644 --- a/src/java.desktop/share/classes/sun/awt/KeyboardFocusManagerPeerImpl.java +++ b/src/java.desktop/share/classes/sun/awt/KeyboardFocusManagerPeerImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * 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,7 @@ public abstract class KeyboardFocusManagerPeerImpl implements KeyboardFocusManag if (focusLog.isLoggable(PlatformLogger.Level.FINER)) { focusLog.finer("Posting focus event: " + fl); } - SunToolkit.postEvent(SunToolkit.targetToAppContext(currentOwner), fl); + SunToolkit.postEvent(fl); } FocusEvent fg = new FocusEvent(lightweightChild, FocusEvent.FOCUS_GAINED, @@ -136,7 +136,7 @@ public abstract class KeyboardFocusManagerPeerImpl implements KeyboardFocusManag if (focusLog.isLoggable(PlatformLogger.Level.FINER)) { focusLog.finer("Posting focus event: " + fg); } - SunToolkit.postEvent(SunToolkit.targetToAppContext(lightweightChild), fg); + SunToolkit.postEvent(fg); return true; } diff --git a/src/java.desktop/share/classes/sun/awt/PaintEventDispatcher.java b/src/java.desktop/share/classes/sun/awt/PaintEventDispatcher.java index eec1fc93c66..831c67e1e4f 100644 --- a/src/java.desktop/share/classes/sun/awt/PaintEventDispatcher.java +++ b/src/java.desktop/share/classes/sun/awt/PaintEventDispatcher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ public class PaintEventDispatcher { * This method is invoked from the toolkit thread when the surface * data of the component needs to be replaced. The method run() of * the Runnable argument performs surface data replacing, run() - * should be invoked on the EDT of this component's AppContext. + * should be invoked on the EDT. * Returns true if the Runnable has been enqueued to be invoked * on the EDT. * (Fix 6255371.) diff --git a/src/java.desktop/share/classes/sun/font/SunFontManager.java b/src/java.desktop/share/classes/sun/font/SunFontManager.java index 85a948ef594..323f0d056e1 100644 --- a/src/java.desktop/share/classes/sun/font/SunFontManager.java +++ b/src/java.desktop/share/classes/sun/font/SunFontManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2480,30 +2480,12 @@ public abstract class SunFontManager implements FontSupport, FontManagerForSGE { * SunGraphicsEnvironment it performs the same initialization as is * performed normally. There may be some duplication of effort, but * that code is already written to be able to perform properly if called - * to duplicate work. The main difference is that if we detect we are - * in an AppContext environment these new fonts - * are not placed in the "default" maps but into an AppContext instance. - * The font lookup mechanism in java.awt.Font.getFont2D() is also updated - * so that look-up for composite fonts will in that case always - * do a lookup rather than returning a cached result. - * This is inefficient but necessary else singleton java.awt.Font - * instances would not retrieve the correct Font2D for the appcontext. - * sun.font.FontManager.findFont2D is also updated to that it uses - * a name map cache specific to that appcontext. - * - * Getting an AppContext is expensive, so there is a global variable - * that records whether these methods have ever been called and can - * avoid the expense for almost all applications. Once the correct - * CompositeFont is associated with the Font, everything should work - * through existing mechanisms. - * A special case is that GraphicsEnvironment.getAllFonts() must - * return an AppContext specific list. + * to duplicate work. * * Calling the methods below is "heavyweight" but it is expected that * these methods will be called very rarely. * - * If _usingAlternateComposites is true, we are not in an "AppContext" - * environment and the (single) application has selected + * If _usingAlternateComposites is true, the application has selected * an alternate composite font behaviour. * * - Printing: The implementation delegates logical fonts to an AWT diff --git a/test/jdk/javax/swing/system/6799345/TestShutdown.java b/test/jdk/javax/swing/system/6799345/TestShutdown.java deleted file mode 100644 index 54ae1e227df..00000000000 --- a/test/jdk/javax/swing/system/6799345/TestShutdown.java +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/** - * @test - * @bug 6799345 - * @key headful - * @summary Tests that no exceptions are thrown from TimerQueue and - * SwingWorker on AppContext shutdown - * @author art - * @modules java.desktop/sun.awt - * @run main TestShutdown - */ - -import java.awt.*; -import java.awt.event.*; - -import java.util.*; - -import javax.swing.*; - -import sun.awt.*; - -public class TestShutdown -{ - private static AppContext targetAppContext; - - private static JFrame f; - private static JTextField tf; - - private static volatile boolean exceptionsOccurred = false; - private static volatile boolean appcontextInitDone = false; - - private static int timerValue = 0; - - public static void main(String[] args) - throws Exception - { - ThreadGroup tg = new TestThreadGroup("TTG"); - Thread t = new Thread(tg, new TestRunnable(), "InitThread"); - t.start(); - - while (!appcontextInitDone) - { - Thread.sleep(1000); - } - - targetAppContext.dispose(); - - if (exceptionsOccurred) - { - throw new RuntimeException("Test FAILED: some exceptions occurred"); - } - } - - static void initGUI() - { - f = new JFrame("F"); - f.setBounds(100, 100, 200, 100); - tf = new JTextField("Test"); - f.add(tf); - f.setVisible(true); - } - - static void startGUI() - { - // caret blink Timer - tf.requestFocusInWindow(); - - // misc Timer - ActionListener al = new ActionListener() - { - @Override - public void actionPerformed(ActionEvent ae) - { - System.out.println("Timer tick: " + timerValue++); - } - }; - new javax.swing.Timer(30, al).start(); - } - - static class TestThreadGroup extends ThreadGroup - { - public TestThreadGroup(String name) - { - super(name); - } - - @Override - public synchronized void uncaughtException(Thread thread, Throwable t) - { - if (t instanceof ThreadDeath) - { - // this one is expected, rethrow - throw (ThreadDeath)t; - } - System.err.println("Test FAILED: an exception is caught in the " + - "target thread group on thread " + thread.getName()); - t.printStackTrace(System.err); - exceptionsOccurred = true; - } - } - - static class TestRunnable implements Runnable - { - @Override - public void run() - { - SunToolkit stk = (SunToolkit)Toolkit.getDefaultToolkit(); - targetAppContext = stk.createNewAppContext(); - - // create and show frame and text field - SwingUtilities.invokeLater(new Runnable() - { - @Override - public void run() - { - initGUI(); - } - }); - stk.realSync(); - - // start some Timers - SwingUtilities.invokeLater(new Runnable() - { - @Override - public void run() - { - startGUI(); - } - }); - - // start multiple SwingWorkers - while (!Thread.interrupted()) - { - try - { - new TestSwingWorker().execute(); - Thread.sleep(40); - } - catch (Exception e) - { - // exception here is expected, skip - break; - } - } - } - } - - static class TestSwingWorker extends SwingWorker - { - @Override - public String doInBackground() - { - Random r = new Random(); - for (int i = 0; i < 10; i++) - { - try - { - int delay = r.nextInt() % 50; - Thread.sleep(delay); - publish(delay); - } - catch (Exception z) - { - break; - } - } - if (!appcontextInitDone) - { - appcontextInitDone = true; - } - return "Done"; - } - - @Override - public void process(java.util.List chunks) - { - for (Integer i : chunks) - { - System.err.println("Processed: " + i); - } - } - } -} diff --git a/test/jdk/sun/awt/AppContext/8012933/Test8012933.java b/test/jdk/sun/awt/AppContext/8012933/Test8012933.java deleted file mode 100644 index 51c5250f3ac..00000000000 --- a/test/jdk/sun/awt/AppContext/8012933/Test8012933.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please 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 8012933 - * @summary Tests (although somewhat indirectly) that createNewAppContext() - * immediately followed by dispose() works correctly - * @author Leonid Romanov - * @modules java.desktop/sun.awt - */ - -import sun.awt.SunToolkit; -import sun.awt.AppContext; - -public class Test8012933 { - private AppContext appContext = null; - final ThreadGroup threadGroup = new ThreadGroup("test thread group"); - final Object lock = new Object(); - boolean isCreated = false; - - public static void main(String[] args) throws Exception { - SunToolkit.createNewAppContext(); - new Test8012933().test(); - } - - private void test() throws Exception { - createAppContext(); - long startTime = System.currentTimeMillis(); - appContext.dispose(); - long endTime = System.currentTimeMillis(); - - // In case of the bug, calling dispose() when there is no EQ - // dispatch thread running fails to create it, so it takes - // almost 10 sec to return from dispose(), which is spent - // waiting on the notificationLock. - if ((endTime - startTime) > 9000) { - throw new RuntimeException("Returning from dispose() took too much time, probably a bug"); - } - } - - private void createAppContext() { - isCreated = false; - final Runnable runnable = new Runnable() { - public void run() { - appContext = SunToolkit.createNewAppContext(); - synchronized (lock) { - isCreated = true; - lock.notifyAll(); - } - } - }; - - final Thread thread = new Thread(threadGroup, runnable, "creates app context"); - synchronized (lock) { - thread.start(); - while (!isCreated) { - try { - lock.wait(); - } catch (InterruptedException ie) { - ie.printStackTrace(); - } - } - } - - if (appContext == null) { - throw new RuntimeException("failed to create app context."); - } else { - System.out.println("app context was created."); - } - } - -} From 40e5745dea472621651fe495d27eef3563714157 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Wed, 1 Apr 2026 19:10:39 +0000 Subject: [PATCH 152/359] 8380714: sun.font.HBShaper : use getUpcallStub to create all up call stubs Reviewed-by: serb, psadhukhan --- .../share/classes/sun/font/HBShaper.java | 55 +++++++------------ 1 file changed, 20 insertions(+), 35 deletions(-) diff --git a/src/java.desktop/share/classes/sun/font/HBShaper.java b/src/java.desktop/share/classes/sun/font/HBShaper.java index 3a532072004..dea8a9e22dd 100644 --- a/src/java.desktop/share/classes/sun/font/HBShaper.java +++ b/src/java.desktop/share/classes/sun/font/HBShaper.java @@ -216,45 +216,30 @@ public class HBShaper { JAVA_INT, // return type JAVA_INT, ADDRESS); // arg types - FunctionDescriptor get_var_glyph_fd = getFunctionDescriptor(JAVA_INT, // return type - ADDRESS, ADDRESS, JAVA_INT, JAVA_INT, ADDRESS, ADDRESS); // arg types - MethodHandle get_var_glyph_mh = - getMethodHandle("get_variation_glyph", get_var_glyph_fd); - @SuppressWarnings("restricted") - MemorySegment tmp5 = LINKER.upcallStub(get_var_glyph_mh, get_var_glyph_fd, garena); - get_var_glyph_stub = tmp5; + get_var_glyph_stub = getUpcallStub(garena, + "get_variation_glyph", // method name + JAVA_INT, // return type + ADDRESS, ADDRESS, JAVA_INT, JAVA_INT, ADDRESS, ADDRESS); // arg types - FunctionDescriptor get_nominal_glyph_fd = getFunctionDescriptor(JAVA_INT, // return type - ADDRESS, ADDRESS, JAVA_INT, ADDRESS, ADDRESS); // arg types - MethodHandle get_nominal_glyph_mh = - getMethodHandle("get_nominal_glyph", get_nominal_glyph_fd); - @SuppressWarnings("restricted") - MemorySegment tmp6 = LINKER.upcallStub(get_nominal_glyph_mh, get_nominal_glyph_fd, garena); - get_nominal_glyph_stub = tmp6; + get_nominal_glyph_stub = getUpcallStub(garena, + "get_nominal_glyph", // method name + JAVA_INT, // return type + ADDRESS, ADDRESS, JAVA_INT, ADDRESS, ADDRESS); // arg types - FunctionDescriptor get_h_adv_fd = getFunctionDescriptor(JAVA_INT, // return type - ADDRESS, ADDRESS, JAVA_INT, ADDRESS); // arg types - MethodHandle get_h_adv_mh = - getMethodHandle("get_glyph_h_advance", get_h_adv_fd); - @SuppressWarnings("restricted") - MemorySegment tmp7 = LINKER.upcallStub(get_h_adv_mh, get_h_adv_fd, garena); - get_h_advance_stub = tmp7; + get_h_advance_stub = getUpcallStub(garena, + "get_glyph_h_advance", // method name + JAVA_INT, // return type + ADDRESS, ADDRESS, JAVA_INT, ADDRESS); // arg types - FunctionDescriptor get_v_adv_fd = getFunctionDescriptor(JAVA_INT, // return type - ADDRESS, ADDRESS, JAVA_INT, ADDRESS); // arg types - MethodHandle get_v_adv_mh = - getMethodHandle("get_glyph_v_advance", get_v_adv_fd); - @SuppressWarnings("restricted") - MemorySegment tmp8 = LINKER.upcallStub(get_v_adv_mh, get_v_adv_fd, garena); - get_v_advance_stub = tmp8; + get_v_advance_stub = getUpcallStub(garena, + "get_glyph_v_advance", // method name + JAVA_INT, // return type + ADDRESS, ADDRESS, JAVA_INT, ADDRESS); // arg types - FunctionDescriptor get_contour_pt_fd = getFunctionDescriptor(JAVA_INT, // return type - ADDRESS, ADDRESS, JAVA_INT, JAVA_INT, ADDRESS, ADDRESS, ADDRESS); // arg types - MethodHandle get_contour_pt_mh = - getMethodHandle("get_glyph_contour_point", get_contour_pt_fd); - @SuppressWarnings("restricted") - MemorySegment tmp9 = LINKER.upcallStub(get_contour_pt_mh, get_contour_pt_fd, garena); - get_contour_pt_stub = tmp9; + get_contour_pt_stub = getUpcallStub(garena, + "get_glyph_contour_point", // method name + JAVA_INT, // return type + ADDRESS, ADDRESS, JAVA_INT, JAVA_INT, ADDRESS, ADDRESS, ADDRESS); // arg types /* Having now created the font upcall stubs, we can call down to create * the native harfbuzz object holding these. From ce9b3b59aa7477cf399716022204c1d5e83676f4 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Wed, 1 Apr 2026 19:10:55 +0000 Subject: [PATCH 153/359] 8380941: Remove AppContext from java.awt.Window implementation Reviewed-by: azvegint, kizune --- .../share/classes/java/awt/Window.java | 85 +++++++------------ 1 file changed, 30 insertions(+), 55 deletions(-) diff --git a/src/java.desktop/share/classes/java/awt/Window.java b/src/java.desktop/share/classes/java/awt/Window.java index b41409a138e..23aefd8860d 100644 --- a/src/java.desktop/share/classes/java/awt/Window.java +++ b/src/java.desktop/share/classes/java/awt/Window.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -64,7 +64,6 @@ import javax.accessibility.AccessibleState; import javax.accessibility.AccessibleStateSet; import sun.awt.AWTAccessor; -import sun.awt.AppContext; import sun.awt.DebugSettings; import sun.awt.SunToolkit; import sun.awt.util.IdentityArrayList; @@ -259,7 +258,7 @@ public class Window extends Container implements Accessible { /** * Contains all the windows that have a peer object associated, * i. e. between addNotify() and removeNotify() calls. The list - * of all Window instances can be obtained from AppContext object. + * of all Window instances can be obtained from {@link #getWindows()} * * @since 1.6 */ @@ -275,7 +274,7 @@ public class Window extends Container implements Accessible { new Vector>(); /* - * We insert a weak reference into the Vector of all Windows in AppContext + * We insert a weak reference into the Vector of all Windows * instead of 'this' so that garbage collection can still take place * correctly. */ @@ -427,11 +426,9 @@ public class Window extends Container implements Accessible { static class WindowDisposerRecord implements sun.java2d.DisposerRecord { WeakReference owner; final WeakReference weakThis; - final WeakReference context; - WindowDisposerRecord(AppContext context, Window victim) { + WindowDisposerRecord(Window victim) { weakThis = victim.weakThis; - this.context = new WeakReference(context); } public void updateOwner() { @@ -448,10 +445,7 @@ public class Window extends Container implements Accessible { parent.removeOwnedWindow(weakThis); } } - AppContext ac = context.get(); - if (null != ac) { - Window.removeFromWindowList(ac, weakThis); - } + Window.removeFromWindowList(weakThis); } } @@ -499,7 +493,7 @@ public class Window extends Container implements Accessible { } modalExclusionType = Dialog.ModalExclusionType.NO_EXCLUDE; - disposerRecord = new WindowDisposerRecord(appContext, this); + disposerRecord = new WindowDisposerRecord(this); sun.java2d.Disposer.addRecord(anchor, disposerRecord); SunToolkit.checkAndSetPolicy(this); @@ -1489,34 +1483,6 @@ public class Window extends Container implements Accessible { } } - private static Window[] getWindows(AppContext appContext) { - synchronized (Window.class) { - Window[] realCopy; - @SuppressWarnings("unchecked") - Vector> windowList = - (Vector>)appContext.get(Window.class); - if (windowList != null) { - int fullSize = windowList.size(); - int realSize = 0; - Window[] fullCopy = new Window[fullSize]; - for (int i = 0; i < fullSize; i++) { - Window w = windowList.get(i).get(); - if (w != null) { - fullCopy[realSize++] = w; - } - } - if (fullSize != realSize) { - realCopy = Arrays.copyOf(fullCopy, realSize); - } else { - realCopy = fullCopy; - } - } else { - realCopy = new Window[0]; - } - return realCopy; - } - } - /** * Returns an array of all {@code Window}s, both owned and ownerless, * created by this application. @@ -1534,7 +1500,24 @@ public class Window extends Container implements Accessible { * @since 1.6 */ public static Window[] getWindows() { - return getWindows(AppContext.getAppContext()); + synchronized (Window.class) { + Window[] realCopy; + int fullSize = windowList.size(); + int realSize = 0; + Window[] fullCopy = new Window[fullSize]; + for (int i = 0; i < fullSize; i++) { + Window w = windowList.get(i).get(); + if (w != null) { + fullCopy[realSize++] = w; + } + } + if (fullSize != realSize) { + realCopy = Arrays.copyOf(fullCopy, realSize); + } else { + realCopy = fullCopy; + } + return realCopy; + } } /** @@ -2746,30 +2729,22 @@ public class Window extends Container implements Accessible { child.disposerRecord.updateOwner(); } + private static final Vector> windowList = new Vector<>(); + private void addToWindowList() { synchronized (Window.class) { - @SuppressWarnings("unchecked") - Vector> windowList = (Vector>)appContext.get(Window.class); - if (windowList == null) { - windowList = new Vector>(); - appContext.put(Window.class, windowList); - } windowList.add(weakThis); } } - private static void removeFromWindowList(AppContext context, WeakReference weakThis) { + private static void removeFromWindowList(WeakReference weakThis) { synchronized (Window.class) { - @SuppressWarnings("unchecked") - Vector> windowList = (Vector>)context.get(Window.class); - if (windowList != null) { - windowList.remove(weakThis); - } + windowList.remove(weakThis); } } private void removeFromWindowList() { - removeFromWindowList(appContext, weakThis); + removeFromWindowList(weakThis); } /** @@ -2909,7 +2884,7 @@ public class Window extends Container implements Accessible { weakThis = new WeakReference<>(this); anchor = new Object(); - disposerRecord = new WindowDisposerRecord(appContext, this); + disposerRecord = new WindowDisposerRecord(this); sun.java2d.Disposer.addRecord(anchor, disposerRecord); addToWindowList(); From cddee6d6eb3e048635c380a32bd2f6ebfd2c18b5 Mon Sep 17 00:00:00 2001 From: Daniel Gredler Date: Wed, 1 Apr 2026 20:37:24 +0000 Subject: [PATCH 154/359] 8380028: Fix Page8 of manual test java/awt/print/PrinterJob/PrintTextTest.java on macOS Reviewed-by: prr, psadhukhan --- .../classes/sun/lwawt/macosx/CTextPipe.java | 33 +++++++++++++++---- .../java/awt/geom/AffineTransform.java | 4 +-- .../classes/sun/java2d/SunGraphics2D.java | 4 ++- .../awt/print/PrinterJob/PrintTextTest.java | 4 +-- 4 files changed, 33 insertions(+), 12 deletions(-) diff --git a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CTextPipe.java b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CTextPipe.java index cf4a6e72136..ba5bb769ad5 100644 --- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CTextPipe.java +++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CTextPipe.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ package sun.lwawt.macosx; - import java.awt.*; import java.awt.font.*; @@ -73,12 +72,17 @@ public class CTextPipe implements TextPipe { @Override public void drawString(final SunGraphics2D sg2d, final String s, final double x, final double y) { + + FontInfo info = sg2d.getFontInfo(); + double dx = x + info.originX; + double dy = y + info.originY; + final long nativeStrikePtr = getNativeStrikePtr(sg2d); if (OSXSurfaceData.IsSimpleColor(sg2d.paint) && nativeStrikePtr != 0) { final OSXSurfaceData surfaceData = (OSXSurfaceData)sg2d.getSurfaceData(); - surfaceData.drawString(this, sg2d, nativeStrikePtr, s, x, y); + surfaceData.drawString(this, sg2d, nativeStrikePtr, s, dx, dy); } else { - drawTextAsShape(sg2d, s, x, y); + drawTextAsShape(sg2d, s, dx, dy); } } @@ -153,6 +157,15 @@ public class CTextPipe implements TextPipe { final Font prevFont = sg2d.getFont(); sg2d.setFont(gV.getFont()); + int flags = gV.getLayoutFlags(); + boolean positionAdjustments = (flags & GlyphVector.FLAG_HAS_POSITION_ADJUSTMENTS) != 0; + if (positionAdjustments) { + // make sure GV positions are initialized, so they are available later in native code; this + // will already be the case if the user explicitly set the glyph positions, but not if the + // position adjustment flag was set because of a font translation transform or font tracking + gV.getGlyphPosition(0); + } + if (hasSlotData(gV)) { final int length = gV.getNumGlyphs(); float[] positions = gV.getGlyphPositions(0, length, null); @@ -177,12 +190,17 @@ public class CTextPipe implements TextPipe { @Override public void drawChars(final SunGraphics2D sg2d, final char[] data, final int offset, final int length, final int x, final int y) { + + FontInfo info = sg2d.getFontInfo(); + double dx = x + info.originX; + double dy = y + info.originY; + final long nativeStrikePtr = getNativeStrikePtr(sg2d); if (OSXSurfaceData.IsSimpleColor(sg2d.paint) && nativeStrikePtr != 0) { final OSXSurfaceData surfaceData = (OSXSurfaceData)sg2d.getSurfaceData(); - surfaceData.drawUnicodes(this, sg2d, nativeStrikePtr, data, offset, length, x, y); + surfaceData.drawUnicodes(this, sg2d, nativeStrikePtr, data, offset, length, (float) dx, (float) dy); } else { - drawTextAsShape(sg2d, new String(data, offset, length), x, y); + drawTextAsShape(sg2d, new String(data, offset, length), dx, dy); } } @@ -191,7 +209,8 @@ public class CTextPipe implements TextPipe { } public static final class Tracer extends CTextPipe { - void doDrawString(final SurfaceData sData, final long nativeStrikePtr, final String s, final float x, final float y) { + @Override + public void doDrawString(final SurfaceData sData, final long nativeStrikePtr, final String s, final double x, final double y) { GraphicsPrimitive.tracePrimitive("QuartzDrawString"); super.doDrawString(sData, nativeStrikePtr, s, x, y); } diff --git a/src/java.desktop/share/classes/java/awt/geom/AffineTransform.java b/src/java.desktop/share/classes/java/awt/geom/AffineTransform.java index 9abc55d8e6f..a6869369714 100644 --- a/src/java.desktop/share/classes/java/awt/geom/AffineTransform.java +++ b/src/java.desktop/share/classes/java/awt/geom/AffineTransform.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1137,7 +1137,7 @@ public class AffineTransform implements Cloneable, java.io.Serializable { * The values are stored in the array as * { m00 m10 m01 m11 m02 m12 }. * An array of 4 doubles can also be specified, in which case only the - * first four elements representing the non-transform + * first four elements representing the non-translation * parts of the array are retrieved and the values are stored into * the array as { m00 m10 m01 m11 } * @param flatmatrix the double array used to store the returned diff --git a/src/java.desktop/share/classes/sun/java2d/SunGraphics2D.java b/src/java.desktop/share/classes/sun/java2d/SunGraphics2D.java index 891a15f24de..d66cd3fe3d5 100644 --- a/src/java.desktop/share/classes/sun/java2d/SunGraphics2D.java +++ b/src/java.desktop/share/classes/sun/java2d/SunGraphics2D.java @@ -596,7 +596,9 @@ public final class SunGraphics2D textAt.scale(ptSize, ptSize); info.originX = (float)textAt.getTranslateX(); info.originY = (float)textAt.getTranslateY(); - textAt.translate(-info.originX, -info.originY); + textAt.setTransform(textAt.getScaleX(), textAt.getShearY(), + textAt.getShearX(), textAt.getScaleY(), + 0, 0); if (transformState >= TRANSFORM_TRANSLATESCALE) { transform.getMatrix(info.devTx = new double[4]); devAt = new AffineTransform(info.devTx); diff --git a/test/jdk/java/awt/print/PrinterJob/PrintTextTest.java b/test/jdk/java/awt/print/PrinterJob/PrintTextTest.java index defca807fc0..0b9663a9e99 100644 --- a/test/jdk/java/awt/print/PrinterJob/PrintTextTest.java +++ b/test/jdk/java/awt/print/PrinterJob/PrintTextTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * 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 6425068 7156751 7157659 8029204 8132890 8148334 8344637 8368702 + * @bug 6425068 7156751 7157659 8029204 8132890 8148334 8344637 8368702 8380028 * @key printer * @summary Confirm that text prints where we expect to the length we expect. * @library /java/awt/regtesthelpers From c18e3a3377e67f50ab065d1ac9365c7d43950fb6 Mon Sep 17 00:00:00 2001 From: Igor Veresov Date: Thu, 2 Apr 2026 00:18:11 +0000 Subject: [PATCH 155/359] 8379819: Creating AOT configuration crashes in MethodTrainingData::prepare Reviewed-by: iklam, kvn --- src/hotspot/share/oops/methodData.cpp | 2 +- src/hotspot/share/oops/trainingData.cpp | 49 ++++++++++++++----- src/hotspot/share/oops/trainingData.hpp | 4 +- .../share/prims/jvmtiRedefineClasses.cpp | 5 ++ .../aotCache/RedefineClassesInProfile.java | 35 ++++++++++++- .../aotCache/test-classes/CustomLoadee.java | 38 ++++++++++++++ 6 files changed, 117 insertions(+), 16 deletions(-) create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/aotCache/test-classes/CustomLoadee.java diff --git a/src/hotspot/share/oops/methodData.cpp b/src/hotspot/share/oops/methodData.cpp index 38bdc33c628..ad1049ffa34 100644 --- a/src/hotspot/share/oops/methodData.cpp +++ b/src/hotspot/share/oops/methodData.cpp @@ -329,7 +329,7 @@ static bool is_excluded(Klass* k) { log_debug(aot, training)("Purged %s from MDO: unloaded class", k->name()->as_C_string()); return true; } else { - bool excluded = SystemDictionaryShared::should_be_excluded(k); + bool excluded = SystemDictionaryShared::should_be_excluded(k) || !SystemDictionaryShared::is_builtin_loader(k->class_loader_data()); if (excluded) { log_debug(aot, training)("Purged %s from MDO: excluded class", k->name()->as_C_string()); } diff --git a/src/hotspot/share/oops/trainingData.cpp b/src/hotspot/share/oops/trainingData.cpp index f52c22ad38a..7976da35374 100644 --- a/src/hotspot/share/oops/trainingData.cpp +++ b/src/hotspot/share/oops/trainingData.cpp @@ -118,10 +118,23 @@ void TrainingData::verify() { } } +static bool is_excluded(InstanceKlass* k) { + if (!k->is_loaded() || k->has_been_redefined()) { + return true; + } + if (CDSConfig::is_at_aot_safepoint()) { + // Check for AOT exclusion only at AOT safe point. + return SystemDictionaryShared::should_be_excluded(k) || !SystemDictionaryShared::is_builtin_loader(k->class_loader_data()); + } + return false; +} + MethodTrainingData* MethodTrainingData::make(const methodHandle& method, bool null_if_not_found, bool use_cache) { - MethodTrainingData* mtd = nullptr; if (!have_data() && !need_data()) { - return mtd; + return nullptr; + } + if (is_excluded(method->method_holder())) { + return nullptr; } // Try grabbing the cached value first. // Cache value is stored in MethodCounters and the following are the @@ -133,6 +146,7 @@ MethodTrainingData* MethodTrainingData::make(const methodHandle& method, bool nu // i.e. null_if_no_found == true, then just return a null. // 3. Cache value is not null. // Return it, the value of training_data_lookup_failed doesn't matter. + MethodTrainingData* mtd = nullptr; MethodCounters* mcs = method->method_counters(); if (mcs != nullptr) { mtd = mcs->method_training_data(); @@ -175,6 +189,7 @@ MethodTrainingData* MethodTrainingData::make(const methodHandle& method, bool nu return nullptr; // allocation failure } td = training_data_set()->install(mtd); + assert(!is_excluded(method->method_holder()), "Should not be excluded"); assert(td == mtd, ""); } else { mtd = nullptr; @@ -376,6 +391,9 @@ void CompileTrainingData::prepare(Visitor& visitor) { } KlassTrainingData* KlassTrainingData::make(InstanceKlass* holder, bool null_if_not_found) { + if (is_excluded(holder)) { + return nullptr; + } Key key(holder); TrainingData* td = CDS_ONLY(have_data() ? lookup_archived_training_data(&key) :) nullptr; KlassTrainingData* ktd = nullptr; @@ -401,6 +419,7 @@ KlassTrainingData* KlassTrainingData::make(InstanceKlass* holder, bool null_if_n } td = training_data_set()->install(ktd); assert(ktd == td, ""); + assert(!is_excluded(holder), "Should not be excluded"); } else { ktd = td->as_KlassTrainingData(); guarantee(ktd->holder() != nullptr, "null holder"); @@ -543,18 +562,24 @@ void TrainingData::cleanup_training_data() { } } +void TrainingData::cleanup_after_redefinition() { + if (need_data()) { + TrainingDataLocker l; + ResourceMark rm; + Visitor visitor(training_data_set()->size()); + training_data_set()->iterate([&](TrainingData* td) { + td->cleanup(visitor); + }); + } +} + void KlassTrainingData::cleanup(Visitor& visitor) { if (visitor.is_visited(this)) { return; } visitor.visit(this); if (has_holder()) { - bool is_excluded = !holder()->is_loaded(); - if (CDSConfig::is_at_aot_safepoint()) { - // Check for AOT exclusion only at AOT safe point. - is_excluded |= SystemDictionaryShared::should_be_excluded(holder()); - } - if (is_excluded) { + if (is_excluded(holder())) { ResourceMark rm; log_debug(aot, training)("Cleanup KTD %s", name()->as_klass_external_name()); _holder = nullptr; @@ -572,12 +597,8 @@ void MethodTrainingData::cleanup(Visitor& visitor) { } visitor.visit(this); if (has_holder()) { - if (CDSConfig::is_at_aot_safepoint() && SystemDictionaryShared::should_be_excluded(holder()->method_holder())) { - // Check for AOT exclusion only at AOT safe point. + if (is_excluded(holder()->method_holder())) { log_debug(aot, training)("Cleanup MTD %s::%s", name()->as_klass_external_name(), signature()->as_utf8()); - if (_final_profile != nullptr && _final_profile->method() != _holder) { - log_warning(aot, training)("Stale MDO for %s::%s", name()->as_klass_external_name(), signature()->as_utf8()); - } _final_profile = nullptr; _final_counters = nullptr; _holder = nullptr; @@ -593,6 +614,7 @@ void MethodTrainingData::cleanup(Visitor& visitor) { } void KlassTrainingData::verify() { + guarantee(!has_holder() || !is_excluded(holder()), "Bad holder"); for (int i = 0; i < comp_dep_count(); i++) { CompileTrainingData* ctd = comp_dep(i); if (!ctd->_init_deps.contains(this)) { @@ -604,6 +626,7 @@ void KlassTrainingData::verify() { } void MethodTrainingData::verify(bool verify_dep_counter) { + guarantee(!has_holder() || !is_excluded(holder()->method_holder()), "Bad holder"); iterate_compiles([&](CompileTrainingData* ctd) { ctd->verify(verify_dep_counter); }); diff --git a/src/hotspot/share/oops/trainingData.hpp b/src/hotspot/share/oops/trainingData.hpp index c549004e76e..bd696f52a8b 100644 --- a/src/hotspot/share/oops/trainingData.hpp +++ b/src/hotspot/share/oops/trainingData.hpp @@ -310,7 +310,7 @@ private: static void iterate(Function& fn) { // lambda enabled API TrainingDataLocker l; if (have_data()) { - archived_training_data_dictionary()->iterate(fn); + archived_training_data_dictionary()->iterate_all(fn); } if (need_data()) { training_data_set()->iterate(fn); @@ -431,6 +431,8 @@ private: } return nullptr; } + + static void cleanup_after_redefinition(); }; // Training data that is associated with an InstanceKlass diff --git a/src/hotspot/share/prims/jvmtiRedefineClasses.cpp b/src/hotspot/share/prims/jvmtiRedefineClasses.cpp index c594cfc6816..8beddc5d406 100644 --- a/src/hotspot/share/prims/jvmtiRedefineClasses.cpp +++ b/src/hotspot/share/prims/jvmtiRedefineClasses.cpp @@ -53,6 +53,7 @@ #include "oops/method.hpp" #include "oops/oop.inline.hpp" #include "oops/recordComponent.hpp" +#include "oops/trainingData.hpp" #include "prims/jvmtiImpl.hpp" #include "prims/jvmtiRedefineClasses.hpp" #include "prims/jvmtiThreadState.inline.hpp" @@ -274,6 +275,10 @@ void VM_RedefineClasses::doit() { redefine_single_class(current, _class_defs[i].klass, _scratch_classes[i]); } +#if INCLUDE_CDS + TrainingData::cleanup_after_redefinition(); +#endif + // Flush all compiled code that depends on the classes redefined. flush_dependent_code(); diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/RedefineClassesInProfile.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/RedefineClassesInProfile.java index f311629b2de..bb1992d5c82 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/RedefineClassesInProfile.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/RedefineClassesInProfile.java @@ -41,7 +41,10 @@ * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar redef1.jar * RedefFoo RedefBar * RedefTaz0 RedefTaz1 RedefTaz2 RedefTaz3 RedefTaz4 - + * + * @compile test-classes/CustomLoadee.java + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar cust.jar CustomLoadee + * * @run driver RedefineClassHelper * @build RedefineClassesInProfile * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app.jar RedefineClassesInProfileApp Util @@ -49,6 +52,8 @@ */ import java.io.File; +import java.net.URL; +import java.net.URLClassLoader; import jdk.test.lib.cds.SimpleCDSAppTester; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; @@ -89,6 +94,7 @@ public class RedefineClassesInProfile { out.shouldNotMatch(prefix + "RedefFoo"); out.shouldNotMatch(prefix + "RedefBar"); out.shouldNotMatch(prefix + "RedefTaz"); + out.shouldNotMatch(prefix + "CustomLoadee"); }) .setProductionChecker((OutputAnalyzer out) -> { out.shouldContain("Redefined: class RedefBar"); @@ -104,6 +110,7 @@ class RedefineClassesInProfileApp { public static void main(String[] args) throws Exception { test1(); + test2(); } // test1 @@ -175,4 +182,30 @@ class RedefineClassesInProfileApp { throw new RuntimeException("Unexpected failure", t); } } + + // Test 2 -- TrainingData interaction with custom class loaders. + static void test2() throws Exception { + // Do this several times. The AOT cache should contain only one + // copy of CustomLoadee as an "unregistered" class, which will be + // used in the first iteration of this loop. + // + // The JVM should work well even if the cached version of CustomLoadee + // has been unloaded. + for (int i = 0; i < 4; i++) { + test2_inner(); + System.gc(); // trigger unloading of CustomLoadee. + } + } + + static void test2_inner() throws Exception { + // Load a class and run a loop to make sure it's compiled, but + // TrainingData should not record any class/method that are loaded + // by custom class loaders + File custJar = new File("cust.jar"); + URL[] urls = new URL[] {custJar.toURI().toURL()}; + URLClassLoader loader = new URLClassLoader(urls, RedefineClassesInProfileApp.class.getClassLoader()); + Class c = loader.loadClass("CustomLoadee"); + System.out.println(c.newInstance()); + } } + diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/test-classes/CustomLoadee.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/test-classes/CustomLoadee.java new file mode 100644 index 00000000000..aa78f2ba57a --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/test-classes/CustomLoadee.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +public class CustomLoadee { + public CustomLoadee() { + hotspot2(); + } + + static volatile int x; + static void hotspot2() { + long start = System.currentTimeMillis(); + // run this loop long enough (400ms) for it to be JIT compiled. + while (System.currentTimeMillis() - start < 400) { + x += 1; + } + } +} From fa5ec62405af5ca104ca269d3470e07de690386f Mon Sep 17 00:00:00 2001 From: Dusan Balek Date: Thu, 2 Apr 2026 08:20:47 +0000 Subject: [PATCH 156/359] 8378950: Repeated warnings when annotation processing is happening Co-authored-by: Archie Cobbs Reviewed-by: jlahoda --- .../JavacProcessingEnvironment.java | 15 ++++-- .../APImplicitClassesWarnings.java | 53 +++++++++++++++++-- .../tools/javac/modules/IncubatingTest.java | 46 ++++++++++++++-- .../rounds/OverwriteBetweenCompilations_2.out | 2 - 4 files changed, 103 insertions(+), 13 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java index 74d082d4b64..809c19d5012 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1104,7 +1104,7 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea return true; return deferredDiagnosticHandler.getDiagnostics().stream() - .anyMatch(d -> (d.getKind() == Diagnostic.Kind.WARNING && werror) || + .anyMatch(d -> (d.getKind() == Diagnostic.Kind.WARNING && werror && ACCEPT_NON_RECOVERABLE_LINTS.test(d)) || (d.getKind() == Diagnostic.Kind.ERROR && (fatalErrors || !d.isFlagSet(RECOVERABLE)))); } @@ -1195,12 +1195,19 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea } void showDiagnostics(boolean showAll) { - deferredDiagnosticHandler.reportDeferredDiagnostics(showAll ? ACCEPT_ALL - : ACCEPT_NON_RECOVERABLE); + deferredDiagnosticHandler.reportDeferredDiagnostics( + ACCEPT_NON_RECOVERABLE_LINTS.and(showAll ? ACCEPT_ALL + : ACCEPT_NON_RECOVERABLE)); log.popDiagnosticHandler(deferredDiagnosticHandler); compiler.setDeferredDiagnosticHandler(null); } //where: + private final Predicate ACCEPT_NON_RECOVERABLE_LINTS = + d -> !Optional.of(d) + .map(JCDiagnostic::getLintCategory) + .map(lc -> lc.annotationSuppression || + lc == Lint.LintCategory.INCUBATING) + .orElse(false); private final Predicate ACCEPT_NON_RECOVERABLE = d -> d.getKind() != JCDiagnostic.Kind.ERROR || !d.isFlagSet(DiagnosticFlag.RECOVERABLE) || diff --git a/test/langtools/tools/javac/implicitCompile/APImplicitClassesWarnings.java b/test/langtools/tools/javac/implicitCompile/APImplicitClassesWarnings.java index dc60c6cc78a..8c1e356217c 100644 --- a/test/langtools/tools/javac/implicitCompile/APImplicitClassesWarnings.java +++ b/test/langtools/tools/javac/implicitCompile/APImplicitClassesWarnings.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8378740 + * @bug 8378740 8378950 * @summary Verify warnings are properly suppressed for the combination of * annotation processing and implicit compilation * @library /tools/lib @@ -96,9 +96,7 @@ public class APImplicitClassesWarnings { List expected = List.of( "Use.java:4:5: compiler.warn.has.been.deprecated.for.removal: test.Depr, test", - "Use.java:4:5: compiler.warn.has.been.deprecated.for.removal: test.Depr, test", - "Use.java:4:5: compiler.warn.has.been.deprecated.for.removal: test.Depr, test", - "3 warnings" + "1 warning" ); tb.checkEqual(expected, log); @@ -143,6 +141,53 @@ public class APImplicitClassesWarnings { .writeAll(); } + @Test + public void testCorrectImport() throws Exception { + Path src = base.resolve("src"); + Path classes = base.resolve("classes"); + tb.writeJavaFiles(src, + """ + package test; + + @Deprecated(forRemoval=true) + public class Depr { + public static class Nested {} + } + """, + """ + package test; + import test.Depr.Nested; + public class Use { + Implicit implicit; + Nested nest; + } + """, + """ + package test; + public interface Implicit {} + """); + Files.createDirectories(classes); + + List log = new JavacTask(tb) + .options("-d", classes.toString(), + "-XDrawDiagnostics", + "-implicit:class", + "-sourcepath", src.toString()) + .files(src.resolve("test").resolve("Depr.java"), + src.resolve("test").resolve("Use.java")) + .processors(new ProcessorImpl()) + .run() + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + + List expected = List.of( + "Use.java:2:12: compiler.warn.has.been.deprecated.for.removal: test.Depr, test", + "1 warning" + ); + + tb.checkEqual(expected, log); + } + @SupportedAnnotationTypes("*") private static class ProcessorImpl extends AbstractProcessor { @Override diff --git a/test/langtools/tools/javac/modules/IncubatingTest.java b/test/langtools/tools/javac/modules/IncubatingTest.java index 68f615abc04..6ff1a0a29c8 100644 --- a/test/langtools/tools/javac/modules/IncubatingTest.java +++ b/test/langtools/tools/javac/modules/IncubatingTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * 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 8171177 8187591 + * @bug 8171177 8187591 8378950 * @summary Verify that ModuleResolution attribute flags are honored. * @library /tools/lib * @modules jdk.compiler/com.sun.tools.javac.api @@ -46,10 +46,15 @@ import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; - +import java.util.Set; import java.lang.classfile.*; import java.lang.classfile.attribute.ModuleResolutionAttribute; import java.lang.classfile.constantpool.*; +import javax.annotation.processing.AbstractProcessor; +import javax.annotation.processing.RoundEnvironment; +import javax.annotation.processing.SupportedAnnotationTypes; +import javax.lang.model.SourceVersion; +import javax.lang.model.element.TypeElement; import toolbox.JavacTask; import toolbox.Task; import toolbox.Task.Expect; @@ -242,6 +247,29 @@ public class IncubatingTest extends ModuleTestBase { .outdir(testModuleClasses) .files(findJavaFiles(testModuleSrc)) .run(Expect.SUCCESS); + + //test with annotation processing + log = new JavacTask(tb) + .options("--module-path", classes.toString(), + "-XDrawDiagnostics", + "-Werror") + .outdir(testModuleClasses) + .files(findJavaFiles(testModuleSrc)) + .processors(new ProcessorImpl()) + .run(Expect.FAIL) + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + + expected = Arrays.asList( + "- compiler.warn.incubating.modules: jdk.i", + "- compiler.err.warnings.and.werror", + "1 error", + "1 warning" + ); + + if (!expected.equals(log)) { + throw new AssertionError("Unexpected output: " + log); + } } private void copyJavaBase(Path targetDir) throws IOException { @@ -270,4 +298,16 @@ public class IncubatingTest extends ModuleTestBase { out.write(newBytes); } } + + @SupportedAnnotationTypes("*") + private static class ProcessorImpl extends AbstractProcessor { + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + return false; + } + @Override + public SourceVersion getSupportedSourceVersion() { + return SourceVersion.latest(); + } + } } diff --git a/test/langtools/tools/javac/processing/rounds/OverwriteBetweenCompilations_2.out b/test/langtools/tools/javac/processing/rounds/OverwriteBetweenCompilations_2.out index 826e2b4bcb0..431fd3d9079 100644 --- a/test/langtools/tools/javac/processing/rounds/OverwriteBetweenCompilations_2.out +++ b/test/langtools/tools/javac/processing/rounds/OverwriteBetweenCompilations_2.out @@ -53,5 +53,3 @@ public abstract class GeneratedClass extends java.ut public void test(long a); } -- compiler.note.deprecated.filename: OverwriteBetweenCompilationsSource.java -- compiler.note.deprecated.recompile From a506853a8267e5e4a5395ea0303e054d19acdbac Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Thu, 2 Apr 2026 08:53:05 +0000 Subject: [PATCH 157/359] 8374020: Inconsistent handling of type updates in typeWithAnnotations Reviewed-by: abimpoudis --- .../sun/tools/javac/code/TypeAnnotations.java | 17 ++- .../TypeAnnotationsOnTypes.java | 143 ++++++++++++++++++ 2 files changed, 152 insertions(+), 8 deletions(-) create mode 100644 test/langtools/tools/javac/annotations/typeAnnotations/TypeAnnotationsOnTypes.java diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java index 8eba79c7480..0393ed79897 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java @@ -472,11 +472,12 @@ public class TypeAnnotations { Assert.check(tc.position == pos); } - if (type.hasTag(TypeTag.ARRAY)) - return rewriteArrayType(typetree, (ArrayType)type, annotations, onlyTypeAnnotations, pos); + Type ret; - if (type.hasTag(TypeTag.TYPEVAR)) { - return type.annotatedType(onlyTypeAnnotations); + if (type.hasTag(TypeTag.ARRAY)) { + ret = rewriteArrayType(typetree, (ArrayType)type, annotations, onlyTypeAnnotations, pos); + } else if (type.hasTag(TypeTag.TYPEVAR)) { + ret = type.annotatedType(onlyTypeAnnotations); } else if (type.getKind() == TypeKind.UNION) { // There is a TypeKind, but no TypeTag. UnionClassType ut = (UnionClassType) type; @@ -487,7 +488,7 @@ public class TypeAnnotations { ListBuffer alternatives = new ListBuffer<>(); alternatives.add(res); alternatives.addAll(ut.alternatives_field.tail); - return new UnionClassType((ClassType) ut.getLub(), alternatives.toList()); + ret = new UnionClassType((ClassType) ut.getLub(), alternatives.toList()); } else { Type enclTy = type; Element enclEl = type.asElement(); @@ -567,10 +568,10 @@ public class TypeAnnotations { pos.location = pos.location.appendList(depth.toList()); } - Type ret = typeWithAnnotations(type, enclTy, annotations); - typetree.type = ret; - return ret; + ret = typeWithAnnotations(type, enclTy, annotations); } + typetree.type = ret; + return ret; } /** diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/TypeAnnotationsOnTypes.java b/test/langtools/tools/javac/annotations/typeAnnotations/TypeAnnotationsOnTypes.java new file mode 100644 index 00000000000..5ae6b17a24c --- /dev/null +++ b/test/langtools/tools/javac/annotations/typeAnnotations/TypeAnnotationsOnTypes.java @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8374020 + * @summary Verify types are set back to the AST. + * @library /tools/lib + * @modules + * jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * @build toolbox.ToolBox toolbox.JavacTask + * @compile TypeAnnotationsOnTypes.java + * @run main TypeAnnotationsOnTypes + */ + +import com.sun.source.tree.VariableTree; +import com.sun.source.util.TaskEvent; +import com.sun.source.util.TaskListener; +import com.sun.source.util.TreePath; +import com.sun.source.util.TreePathScanner; +import com.sun.source.util.Trees; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.type.UnionType; +import toolbox.JavacTask; +import toolbox.ToolBox; + +public class TypeAnnotationsOnTypes { + + public static void main(String... args) throws Exception { + new TypeAnnotationsOnTypes().run(); + } + + ToolBox tb = new ToolBox(); + + void run() throws Exception { + typeAnnotationInConstantExpressionFieldInit(Paths.get(".")); + } + + void typeAnnotationInConstantExpressionFieldInit(Path base) throws Exception { + Path src = base.resolve("src"); + Path classes = base.resolve("classes"); + tb.writeJavaFiles(src, + """ + import java.lang.annotation.ElementType; + import java.util.List; + import java.lang.annotation.Target; + + class Test { + + void f() { + @TA List l1; + @TA String[] l2; + @TA TypeVar l3; + try { + } catch (@TA IllegalStateException | NullPointerException | @TA IllegalArgumentException ex) {} + } + + @Target(ElementType.TYPE_USE) + @interface TA {} + } + """); + Files.createDirectories(classes); + List actual = new ArrayList<>(); + new JavacTask(tb) + .options("-d", classes.toString()) + .files(tb.findJavaFiles(src)) + .callback(task -> { + task.addTaskListener(new TaskListener() { + @Override + public void finished(TaskEvent e) { + if (e.getKind() != TaskEvent.Kind.ANALYZE) { + return ; + } + Trees trees = Trees.instance(task); + new TreePathScanner() { + @Override + public Void visitVariable(VariableTree node, Void p) { + TreePath typePath = + new TreePath(getCurrentPath(), node.getType()); + actual.add(node.getName() + + ": type on variable: " + + typeToString(trees.getTypeMirror(getCurrentPath())) + + ": type on type: " + + typeToString(trees.getTypeMirror(typePath))); + return super.visitVariable(node, p); + } + }.scan(e.getCompilationUnit(), null); + } + }); + }) + .run() + .writeAll(); + + List expected = List.of( + "l1: type on variable: java.util.@Test.TA List: type on type: java.util.@Test.TA List", + "l2: type on variable: java.lang.@Test.TA String[]: type on type: java.lang.@Test.TA String[]", + "l3: type on variable: @Test.TA TypeVar: type on type: @Test.TA TypeVar", + "ex: type on variable: java.lang.@Test.TA IllegalStateException | java.lang.NullPointerException | java.lang.@Test.TA IllegalArgumentException: " + + "type on type: java.lang.@Test.TA IllegalStateException | java.lang.NullPointerException | java.lang.@Test.TA IllegalArgumentException" + ); + + actual.forEach(System.out::println); + if (!expected.equals(actual)) { + throw new AssertionError("Expected: " + expected + ", but got: " + actual); + } + } + + static String typeToString(TypeMirror type) { + if (type != null && type.getKind() == TypeKind.UNION) { + return ((UnionType) type).getAlternatives().stream().map(t -> typeToString(t)).collect(Collectors.joining(" | ")); + } else { + return String.valueOf(type); + } + } +} From 262f574abcea619c4159ff7d47d3d538953ddfac Mon Sep 17 00:00:00 2001 From: Alan Bateman Date: Thu, 2 Apr 2026 13:06:06 +0000 Subject: [PATCH 158/359] 8381487: Replace threadDump.schema.json with document to describe format Reviewed-by: kevinw --- .../management/HotSpotDiagnosticMXBean.java | 9 +- .../sun/management/doc-files/threadDump.html | 283 ++++++++++++++++++ .../doc-files/threadDump.schema.json | 169 ----------- 3 files changed, 286 insertions(+), 175 deletions(-) create mode 100644 src/jdk.management/share/classes/com/sun/management/doc-files/threadDump.html delete mode 100644 src/jdk.management/share/classes/com/sun/management/doc-files/threadDump.schema.json diff --git a/src/jdk.management/share/classes/com/sun/management/HotSpotDiagnosticMXBean.java b/src/jdk.management/share/classes/com/sun/management/HotSpotDiagnosticMXBean.java index 8ce7c03f62d..9ed1069155b 100644 --- a/src/jdk.management/share/classes/com/sun/management/HotSpotDiagnosticMXBean.java +++ b/src/jdk.management/share/classes/com/sun/management/HotSpotDiagnosticMXBean.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2026, Oracle and/or its affiliates. All rights reserved. * 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,11 +117,8 @@ public interface HotSpotDiagnosticMXBean extends PlatformManagedObject { * does not exist. * *

When the format is specified as {@link ThreadDumpFormat#JSON JSON}, the - * thread dump is generated in JavaScript Object Notation. - * threadDump.schema.json - * describes the thread dump format in draft - * - * JSON Schema Language version 2. + * thread dump is generated as JSON text in the + * JSON Thread Dump Format. * *

The thread dump will include output for all platform threads. It may * include output for some or all virtual threads. diff --git a/src/jdk.management/share/classes/com/sun/management/doc-files/threadDump.html b/src/jdk.management/share/classes/com/sun/management/doc-files/threadDump.html new file mode 100644 index 00000000000..f7dd84d4f32 --- /dev/null +++ b/src/jdk.management/share/classes/com/sun/management/doc-files/threadDump.html @@ -0,0 +1,283 @@ + + + + + JSON Thread Dump Format + + + +

JSON Thread Dump Format

+ +The JSON text is an object with a member named "threadDump" that is an object with the +following members: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
threadDump members
NameData typeOptionalDescription
formatVersion number no The format version. Its value is 2.
processId number no The process identifier (pid) of the VM that generated the thread dump.
time string no The timestamp, in ISO 8601 format, when the thread dump was generated.
runtimeVersion string no The {@linkplain java.lang.Runtime.Version runtime version} of the VM that + generated the thread dump.
threadContainers array no The array of thread "groupings". The first element is the root grouping/container + with name "<root>".
+ +

Each element in the "threadContainers" array is an object that represents a + grouping/container of threads with the following members: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
threadContainers members
NameData typeOptionalDescription
container string no The thread container name. The name is unique.
parent string or null no The thread container parent's name or {@code null} for the root container.
owner number or null no The {@linkplain java.lang.Thread#threadId() thread identifier} of the thread + that owns the thread container or {@code null} if no owner.
threads array no The array of threads in the thread grouping/container.
threadCount number yes The number of threads in the thread grouping/container. If the thread dump + includes all virtual threads then this count is the same as the number of + elements in the threads array. If all virtual threads are not included then + it may be larger than the number of elements in the threads array.
+ +

Each element in a "threads" array is an object with the following members: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
threads members
NameData typeOptionalDescription
tid number no The {@linkplain java.lang.Thread#threadId() thread identifier}.
time string no The timestamp, in ISO 8601 format, when the thread was sampled.
name string no The {@linkplain java.lang.Thread#getName() thread name}.
state string no The string representation of the {@linkplain java.lang.Thread#getState() thread state}.
virtual boolean yes {@code true} if the thread is a {@linkplain java.lang.Thread#isVirtual() virtual thread}.
carrier number yes The thread identifier of the carrier thread when this thread is a mounted + virtual thread.
stack array no The thread stack. The elements in the array are of type string with the string + representation of a {@linkplain java.lang.StackTraceElement stack trace element}. + If the thread stack has one or more elements, then the first element is the top + of the stack.
parkBlocker object yes The object responsible for the thread parking. Its members identify the + blocker object, and the exclusive owner thread if owned.
blockedOn string yes The {@linkplain java.util.Objects#toIdentityString(Object) identity string} of the + object that the thread is blocked on waiting to enter/re-enter a synchronization + method or block.
waitingOn string yes The {@linkplain java.util.Objects#toIdentityString(Object) identity string} + of the object that the thread is {@linkplain java.lang.Object#wait() waiting} + to be notified.
monitorsOwned array yes The objects for which a monitor is owned by the thread.
+ +

A "parkBlocker" object has the following members: + + + + + + + + + + + + + + + + + + + + + + + + +
parkBlocker members
NameData typeOptionalDescription
object string no The {@linkplain java.util.Objects#toIdentityString(Object) identity string} + of the {@linkplain java.util.concurrent.locks.LockSupport#park(Object) blocker + object} responsible for the thread parking.
owner number yes The thread identifier of the exclusive owner thread when the parkBlocker is + an {@link java.util.concurrent.locks.AbstractOwnableSynchronizer}.
+ +

Each element in a "monitorsOwned" array is an object with the following members:

+ + + + + + + + + + + + + + + + + + + + + + + + +
monitorsOwned members
NameData typeOptionalDescription
depth number no The stack depth at which the monitors are owned.
locks array no The elements of the array are of type string or null. An element of type string + has a value that is the {@linkplain java.util.Objects#toIdentityString(Object) + identity string} of the object for which the monitor is owned by the thread. + The element is of type null when the object has been eliminated.
+ + + diff --git a/src/jdk.management/share/classes/com/sun/management/doc-files/threadDump.schema.json b/src/jdk.management/share/classes/com/sun/management/doc-files/threadDump.schema.json deleted file mode 100644 index 30161b0bb74..00000000000 --- a/src/jdk.management/share/classes/com/sun/management/doc-files/threadDump.schema.json +++ /dev/null @@ -1,169 +0,0 @@ -{ - "type": "object", - "properties": { - "threadDump": { - "type": "object", - "properties": { - "formatVersion": { - "type": "integer", - "description": "Format version (2)." - }, - "processId": { - "type": "integer", - "description": "The native process id of the Java virtual machine." - }, - "time": { - "type": "string", - "description": "The time in ISO 8601 format when the thread dump was generated." - }, - "runtimeVersion": { - "type": "string", - "description": "The runtime version, see java.lang.Runtime.Version" - }, - "threadContainers": { - "type": "array", - "description": "The array of thread containers (thread groupings).", - "items": [ - { - "type": "object", - "properties": { - "container": { - "type": "string", - "description": "The container name. The container name is unique." - }, - "parent": { - "type": [ "string", "null" ], - "description": "The parent container name or null for the root container." - }, - "owner": { - "type": [ "integer", "null" ], - "description": "The thread identifier of the owner thread or null if no owner." - }, - "threads": { - "type": "array", - "description": "The array of threads in the thread container.", - "items": [ - { - "type": "object", - "properties": { - "tid": { - "type": "integer", - "description": "The thread identifier." - }, - "time": { - "type": "string", - "description": "The time in ISO 8601 format that the thread was sampled." - }, - "name": { - "type": "string", - "description": "The thread name." - }, - "state": { - "type": "string", - "description": "The thread state (Thread::getState)." - }, - "virtual" : { - "type": "boolean", - "description": "true for a virtual thread." - }, - "parkBlocker": { - "type": "object", - "properties": { - "object": { - "type": "string", - "description": "The blocker object responsible for the thread parking." - } - }, - "owner": { - "type": "integer", - "description": "The thread identifier of the owner when the parkBlocker is an AbstractOwnableSynchronizer." - }, - "required": [ - "object" - ] - }, - "blockedOn": { - "type": "string", - "description": "The object that the thread is blocked on waiting to enter/re-enter a synchronization block/method." - }, - "waitingOn": { - "type": "string", - "description": "The object that the thread is waiting to be notified (Object.wait)." - }, - "stack": { - "type": "array", - "description": "The thread stack. The first element is the top of the stack.", - "items": [ - { - "type": "string", - "description": "A stack trace element (java.lang.StackTraceElement)." - } - ] - }, - "monitorsOwned": { - "type": "array", - "description": "The objects for which monitors are owned by the thread.", - "items": { - "type": "object", - "properties": { - "depth": { - "type": "integer", - "description": "The stack depth at which the monitors are owned." - }, - "locks": { - "type": "array", - "items": { - "type": [ "string", "null" ], - "description": "The object for which the monitor is owned by the thread, null if eliminated." - } - } - }, - "required": [ - "depth", - "locks" - ] - } - }, - "carrier": { - "type": "integer", - "description": "The thread identifier of the carrier thread if mounted." - } - }, - "required": [ - "tid", - "time", - "name", - "state", - "stack" - ] - } - ] - }, - "threadCount": { - "type": "integer", - "description": "The number of threads in the thread container." - } - }, - "required": [ - "container", - "parent", - "owner", - "threads" - ] - } - ] - } - }, - "required": [ - "formatVersion", - "processId", - "time", - "runtimeVersion", - "threadContainers" - ] - } - }, - "required": [ - "threadDump" - ] -} From 81b6fcc3e9e6a5a53a7a53d8371d86a2f48f3d90 Mon Sep 17 00:00:00 2001 From: Vladimir Petko Date: Thu, 2 Apr 2026 13:12:48 +0000 Subject: [PATCH 159/359] 8381555: test/hotspot/jtreg/gc/arguments/TestG1CompressedOops.java fails on 32 bit architectures Reviewed-by: jsikstro --- test/hotspot/jtreg/gc/arguments/TestG1CompressedOops.java | 1 + 1 file changed, 1 insertion(+) diff --git a/test/hotspot/jtreg/gc/arguments/TestG1CompressedOops.java b/test/hotspot/jtreg/gc/arguments/TestG1CompressedOops.java index 3aec113990c..c4c1d364308 100644 --- a/test/hotspot/jtreg/gc/arguments/TestG1CompressedOops.java +++ b/test/hotspot/jtreg/gc/arguments/TestG1CompressedOops.java @@ -27,6 +27,7 @@ package gc.arguments; /* * @test TestG1CompressedOops * @bug 8354145 + * @requires vm.bits == 64 * @requires vm.flagless * @summary Verify that the flag UseCompressedOops is updated properly * @library /test/lib From 06c9aebce3aefec4c75c5ebb46bd9ffc62d09266 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Jeli=C5=84ski?= Date: Thu, 2 Apr 2026 13:40:51 +0000 Subject: [PATCH 160/359] 8377550: [REDO] Need to keep leading zeros in TlsPremasterSecret of TLS1.3 DHKeyAgreement Reviewed-by: hchao, mullan --- .../share/classes/sun/security/ssl/KAKeyDerivation.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/java.base/share/classes/sun/security/ssl/KAKeyDerivation.java b/src/java.base/share/classes/sun/security/ssl/KAKeyDerivation.java index dea86351cc8..0ca197160a9 100644 --- a/src/java.base/share/classes/sun/security/ssl/KAKeyDerivation.java +++ b/src/java.base/share/classes/sun/security/ssl/KAKeyDerivation.java @@ -49,6 +49,9 @@ import sun.security.util.KeyUtil; */ public class KAKeyDerivation implements SSLKeyDerivation { + // Algorithm used to derive TLS 1.3 shared secrets + private static final String t13KeyDerivationAlgorithm = + System.getProperty("jdk.tls.t13KeyDerivationAlgorithm", "Generic"); private final String algorithmName; private final HandshakeContext context; private final PrivateKey localPrivateKey; @@ -234,7 +237,7 @@ public class KAKeyDerivation implements SSLKeyDerivation { var decapsulator = kem.newDecapsulator(localPrivateKey); sharedSecret = decapsulator.decapsulate( keyshare, 0, decapsulator.secretSize(), - "TlsPremasterSecret"); + t13KeyDerivationAlgorithm); } catch (IllegalArgumentException | InvalidKeyException | DecapsulateException e) { // Peer validation failure @@ -252,7 +255,7 @@ public class KAKeyDerivation implements SSLKeyDerivation { KeyAgreement ka = KeyAgreement.getInstance(algorithmName); ka.init(localPrivateKey); ka.doPhase(peerPublicKey, true); - sharedSecret = ka.generateSecret("TlsPremasterSecret"); + sharedSecret = ka.generateSecret(t13KeyDerivationAlgorithm); } return deriveHandshakeSecret(type, sharedSecret); From 0ada293cb4b1e7ec492d20fb8d99bb3db35974c8 Mon Sep 17 00:00:00 2001 From: Matias Saavedra Silva Date: Thu, 2 Apr 2026 14:10:46 +0000 Subject: [PATCH 161/359] 8380091: Tests in runtime/cds are failing with log parsing errors - missing output - but the output seems present Reviewed-by: coleenp, dholmes --- .../jtreg/runtime/cds/BootAppendTests.java | 10 +++++----- .../cds/appcds/SpecifySysLoaderProp.java | 20 +++++++++++-------- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/test/hotspot/jtreg/runtime/cds/BootAppendTests.java b/test/hotspot/jtreg/runtime/cds/BootAppendTests.java index 43466734fa3..642aa2209f4 100644 --- a/test/hotspot/jtreg/runtime/cds/BootAppendTests.java +++ b/test/hotspot/jtreg/runtime/cds/BootAppendTests.java @@ -162,7 +162,7 @@ public class BootAppendTests { .addSuffix("-Xlog:class+load=info", APP_CLASS, BOOT_APPEND_DUPLICATE_MODULE_CLASS_NAME); - String MATCH_PATTERN = ".class.load. javax.annotation.processing.FilerException source:.*bootAppend.jar*"; + String MATCH_PATTERN = ".class.load.*javax.annotation.processing.FilerException source:.*bootAppend.jar*"; CDSTestUtils.run(opts) .assertNormalExit(out -> { out.shouldNotMatch(MATCH_PATTERN); @@ -188,7 +188,7 @@ public class BootAppendTests { APP_CLASS, BOOT_APPEND_MODULE_CLASS_NAME); CDSTestUtils.Result res = CDSTestUtils.run(opts); String MATCH_PATTERN = - ".class.load. javax.sound.sampled.MyClass source:.*bootAppend.jar*"; + ".class.load.*javax.sound.sampled.MyClass source:.*bootAppend.jar*"; if (mode.equals("on")) { res.assertSilentlyDisabledCDS(out -> { out.shouldHaveExitValue(0) @@ -225,7 +225,7 @@ public class BootAppendTests { CDSTestUtils.Result res = CDSTestUtils.run(opts); String MATCH_PATTERN = - ".class.load. javax.annotation.processing.FilerException source:.*bootAppend.jar*"; + ".class.load.*javax.annotation.processing.FilerException source:.*bootAppend.jar*"; if (mode.equals("on")) { res.assertSilentlyDisabledCDS(out -> { out.shouldHaveExitValue(0) @@ -258,7 +258,7 @@ public class BootAppendTests { CDSTestUtils.Result res = CDSTestUtils.run(opts); String MATCH_PATTERN = - ".class.load. nonjdk.myPackage.MyClass source:.*bootAppend.jar*"; + ".class.load.*nonjdk.myPackage.MyClass source:.*bootAppend.jar*"; if (mode.equals("on")) { res.assertSilentlyDisabledCDS(out -> { out.shouldHaveExitValue(0) @@ -287,7 +287,7 @@ public class BootAppendTests { CDSTestUtils.Result res = CDSTestUtils.run(opts); String MATCH_PATTERN = - ".class.load. nonjdk.myPackage.MyClass source:.*bootAppend.jar*"; + ".class.load.*nonjdk.myPackage.MyClass source:.*bootAppend.jar*"; if (mode.equals("on")) { res.assertSilentlyDisabledCDS(out -> { out.shouldHaveExitValue(0) diff --git a/test/hotspot/jtreg/runtime/cds/appcds/SpecifySysLoaderProp.java b/test/hotspot/jtreg/runtime/cds/appcds/SpecifySysLoaderProp.java index ed7f02569ef..8548f76d2ec 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/SpecifySysLoaderProp.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/SpecifySysLoaderProp.java @@ -53,8 +53,10 @@ public class SpecifySysLoaderProp { "-verbose:class", "-cp", appJar, "ReportMyLoader") - .assertNormalExit("[class,load] ReportMyLoader source: shared objects file", - "ReportMyLoader's loader = jdk.internal.loader.ClassLoaders$AppClassLoader@"); + .assertNormalExit(output -> { + output.shouldMatch(".class,load.*ReportMyLoader source: shared objects file"); + output.shouldContain("ReportMyLoader's loader = jdk.internal.loader.ClassLoaders$AppClassLoader@"); + }); // (1) Try to execute the archive with -Djava.system.class.loader=no.such.Klass, // it should fail @@ -79,8 +81,8 @@ public class SpecifySysLoaderProp { "TestClassLoader.called = true", //<-but this proves that TestClassLoader was indeed called. "TestClassLoader: loadClass(\"ReportMyLoader\",") //<- this also proves that TestClassLoader was indeed called. .assertNormalExit(output -> { - output.shouldMatch(".class,load. TestClassLoader source: file:"); - output.shouldMatch(".class,load. ReportMyLoader source: file:.*" + jarFileName); + output.shouldMatch(".class,load.*TestClassLoader source: file:"); + output.shouldMatch(".class,load.*ReportMyLoader source: file:.*" + jarFileName); output.shouldContain("full module graph: disabled due to incompatible property: java.system.class.loader="); }); @@ -91,9 +93,11 @@ public class SpecifySysLoaderProp { "-verbose:class", "-cp", appJar, "TrySwitchMyLoader") - .assertNormalExit("[class,load] ReportMyLoader source: shared objects file", - "TrySwitchMyLoader's loader = jdk.internal.loader.ClassLoaders$AppClassLoader@", - "ReportMyLoader's loader = jdk.internal.loader.ClassLoaders$AppClassLoader@", - "TestClassLoader.called = false"); + .assertNormalExit(output -> { + output.shouldMatch(".class,load.*ReportMyLoader source: shared objects file"); + output.shouldContain("TrySwitchMyLoader's loader = jdk.internal.loader.ClassLoaders$AppClassLoader@"); + output.shouldContain("ReportMyLoader's loader = jdk.internal.loader.ClassLoaders$AppClassLoader@"); + output.shouldContain("TestClassLoader.called = false"); + }); } } From 5e89669d180a4ac969f13cf6c066efbdb9998dc5 Mon Sep 17 00:00:00 2001 From: Mahendra Chhipa Date: Thu, 2 Apr 2026 19:59:21 +0000 Subject: [PATCH 162/359] 8381568: Refactor java/net/spi/InetAddressResolverProvider test from testNg to use JUnit Reviewed-by: dfuchs --- .../AddressesCachingTest.java | 37 +++++++------ .../AddressesStaleCachingTest.java | 24 +++++---- .../BootstrapResolverUsageTest.java | 12 ++--- .../BuiltInResolverTest.java | 22 ++++---- .../EmptyResultsStreamTest.java | 28 +++++----- .../InetAddressUsageInGetProviderTest.java | 7 ++- .../LookupPolicyMappingTest.java | 53 ++++++++++--------- .../LookupPolicyOfTest.java | 25 ++++----- .../ProviderGetExceptionTest.java | 20 +++---- .../ResolutionWithExceptionTest.java | 18 ++++--- .../ReverseLookupDelegationTest.java | 14 ++--- .../classpath/ClasspathProviderTest.java | 9 ++-- .../module/ModularProviderTest.java | 7 +-- 13 files changed, 148 insertions(+), 128 deletions(-) diff --git a/test/jdk/java/net/spi/InetAddressResolverProvider/AddressesCachingTest.java b/test/jdk/java/net/spi/InetAddressResolverProvider/AddressesCachingTest.java index 26dabc00063..f4fa2016983 100644 --- a/test/jdk/java/net/spi/InetAddressResolverProvider/AddressesCachingTest.java +++ b/test/jdk/java/net/spi/InetAddressResolverProvider/AddressesCachingTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * 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,10 +24,13 @@ import java.net.InetAddress; import java.net.UnknownHostException; -import org.testng.Assert; -import org.testng.annotations.Test; import impl.SimpleResolverProviderImpl; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; /* @@ -37,26 +40,26 @@ import impl.SimpleResolverProviderImpl; * @library lib providers/simple * @build test.library/testlib.ResolutionRegistry * simple.provider/impl.SimpleResolverProviderImpl AddressesCachingTest - * @run testng/othervm -Djava.security.properties=${test.src}/props/NeverCache.props + * @run junit/othervm -Djava.security.properties=${test.src}/props/NeverCache.props * -Dtest.cachingDisabled=true AddressesCachingTest - * @run testng/othervm -Djava.security.properties=${test.src}/props/ForeverCache.props + * @run junit/othervm -Djava.security.properties=${test.src}/props/ForeverCache.props * -Dtest.cachingDisabled=false AddressesCachingTest - * @run testng/othervm + * @run junit/othervm * -Djava.security.properties=${test.src}/props/NeverCacheIgnoreMinusStale.props * -Dtest.cachingDisabled=true AddressesCachingTest - * @run testng/othervm + * @run junit/othervm * -Djava.security.properties=${test.src}/props/NeverCacheIgnorePositiveStale.props * -Dtest.cachingDisabled=true AddressesCachingTest - * @run testng/othervm + * @run junit/othervm * -Djava.security.properties=${test.src}/props/NeverCacheIgnoreZeroStale.props * -Dtest.cachingDisabled=true AddressesCachingTest - * @run testng/othervm + * @run junit/othervm * -Djava.security.properties=${test.src}/props/ForeverCacheIgnoreMinusStale.props * -Dtest.cachingDisabled=false AddressesCachingTest - * @run testng/othervm + * @run junit/othervm * -Djava.security.properties=${test.src}/props/ForeverCacheIgnorePositiveStale.props * -Dtest.cachingDisabled=false AddressesCachingTest - * @run testng/othervm + * @run junit/othervm * -Djava.security.properties=${test.src}/props/ForeverCacheIgnoreZeroStale.props * -Dtest.cachingDisabled=false AddressesCachingTest */ @@ -66,10 +69,10 @@ public class AddressesCachingTest { public void testPositiveCaching() { boolean observedTwoLookups = performLookups(false); if (CACHING_DISABLED) { - Assert.assertTrue(observedTwoLookups, + assertTrue(observedTwoLookups, "Two positive lookups are expected with caching disabled"); } else { - Assert.assertFalse(observedTwoLookups, + assertFalse(observedTwoLookups, "Only one positive lookup is expected with caching enabled"); } } @@ -78,10 +81,10 @@ public class AddressesCachingTest { public void testNegativeCaching() { boolean observedTwoLookups = performLookups(true); if (CACHING_DISABLED) { - Assert.assertTrue(observedTwoLookups, + assertTrue(observedTwoLookups, "Two negative lookups are expected with caching disabled"); } else { - Assert.assertFalse(observedTwoLookups, + assertFalse(observedTwoLookups, "Only one negative lookup is expected with caching enabled"); } } @@ -107,11 +110,11 @@ public class AddressesCachingTest { try { InetAddress.getByName(hostName); if (performNegativeLookup) { - Assert.fail("Host name is expected to get unresolved"); + fail("Host name is expected to get unresolved"); } } catch (UnknownHostException uhe) { if (!performNegativeLookup) { - Assert.fail("Host name is expected to get resolved"); + fail("Host name is expected to get resolved"); } } } diff --git a/test/jdk/java/net/spi/InetAddressResolverProvider/AddressesStaleCachingTest.java b/test/jdk/java/net/spi/InetAddressResolverProvider/AddressesStaleCachingTest.java index a8393221a72..a2c5c3e8443 100644 --- a/test/jdk/java/net/spi/InetAddressResolverProvider/AddressesStaleCachingTest.java +++ b/test/jdk/java/net/spi/InetAddressResolverProvider/AddressesStaleCachingTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * 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,11 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import impl.SimpleResolverProviderImpl; -import org.testng.Assert; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; /* @@ -38,7 +41,7 @@ import org.testng.annotations.Test; * @library lib providers/simple * @build test.library/testlib.ResolutionRegistry * simple.provider/impl.SimpleResolverProviderImpl AddressesStaleCachingTest - * @run testng/othervm -Djava.security.properties=${test.src}/props/CacheStale.props AddressesStaleCachingTest + * @run junit/othervm -Djava.security.properties=${test.src}/props/CacheStale.props AddressesStaleCachingTest */ public class AddressesStaleCachingTest { @@ -64,20 +67,21 @@ public class AddressesStaleCachingTest { Thread.sleep(10000); // intentionally big delay > x2 stale property // The refreshTime is expired, we will do the successful lookup. Lookup second = doLookup(false, 0); - Assert.assertNotEquals(first.timestamp, second.timestamp, + assertNotEquals(first.timestamp, second.timestamp, "Two lookups are expected"); Thread.sleep(10000); // intentionally big delay > x2 stale property // The refreshTime is expired again, we will do the failed lookup. Lookup third = doLookup(true, 0); - Assert.assertNotEquals(second.timestamp, third.timestamp, + assertNotEquals(second.timestamp, third.timestamp, "Two lookups are expected"); // The stale cache is enabled, so we should get valid/same data for // all requests(even for the failed request). - Assert.assertEquals(first.address, second.address, + assertArrayEquals(first.address, second.address, "Same address is expected"); - Assert.assertEquals(second.address, third.address, + + assertArrayEquals(second.address, third.address, "Same address is expected"); } @@ -133,10 +137,10 @@ public class AddressesStaleCachingTest { byte[] secondAddress = InetAddress.getByName("javaTest.org").getAddress(); long secondTimestamp = SimpleResolverProviderImpl.getLastLookupTimestamp(); - Assert.assertEquals(firstAddress, secondAddress, + assertArrayEquals(firstAddress, secondAddress, "Same address is expected"); if (timeout == 0 || timeout - System.nanoTime() > 0) { - Assert.assertEquals(firstTimestamp, secondTimestamp, + assertEquals(firstTimestamp, secondTimestamp, "Only one positive lookup is expected with caching enabled"); } return new Lookup(firstAddress, firstTimestamp); diff --git a/test/jdk/java/net/spi/InetAddressResolverProvider/BootstrapResolverUsageTest.java b/test/jdk/java/net/spi/InetAddressResolverProvider/BootstrapResolverUsageTest.java index 9f0902d2c1d..012410c1566 100644 --- a/test/jdk/java/net/spi/InetAddressResolverProvider/BootstrapResolverUsageTest.java +++ b/test/jdk/java/net/spi/InetAddressResolverProvider/BootstrapResolverUsageTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,12 +21,13 @@ * questions. */ +import org.junit.jupiter.api.Test; + import java.net.InetAddress; -import org.testng.Assert; -import org.testng.annotations.Test; import static impl.WithBootstrapResolverUsageProvider.numberOfGetCalls; +import static org.junit.jupiter.api.Assertions.assertEquals; /** * @test @@ -35,7 +36,7 @@ import static impl.WithBootstrapResolverUsageProvider.numberOfGetCalls; * InetAddressResolverProvider.get method uses InetAddress lookup API. * @library providers/bootstrapUsage * @build bootstrap.usage.provider/impl.WithBootstrapResolverUsageProvider - * @run testng/othervm BootstrapResolverUsageTest + * @run junit/othervm BootstrapResolverUsageTest */ public class BootstrapResolverUsageTest { @@ -43,7 +44,6 @@ public class BootstrapResolverUsageTest { @Test public void testSuccessfulProviderInstantiationTest() throws Exception { System.err.println(InetAddress.getAllByName(InetAddress.getLocalHost().getHostName())); - Assert.assertEquals(numberOfGetCalls, 1, - "InetAddressResolverProvider.get was called more than once"); + assertEquals(1, numberOfGetCalls, "InetAddressResolverProvider.get was called more than once"); } } diff --git a/test/jdk/java/net/spi/InetAddressResolverProvider/BuiltInResolverTest.java b/test/jdk/java/net/spi/InetAddressResolverProvider/BuiltInResolverTest.java index 8b8b866d7b2..e91446e540a 100644 --- a/test/jdk/java/net/spi/InetAddressResolverProvider/BuiltInResolverTest.java +++ b/test/jdk/java/net/spi/InetAddressResolverProvider/BuiltInResolverTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * 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,30 +21,34 @@ * questions. */ -import org.testng.annotations.BeforeTest; -import org.testng.annotations.Test; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; import java.lang.reflect.Field; import java.net.InetAddress; import java.net.UnknownHostException; import java.net.spi.InetAddressResolver; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + /* * @test * @summary white-box test to check that the built-in resolver * is used by default. * @modules java.base/java.net:open - * @run testng/othervm BuiltInResolverTest + * @run junit/othervm BuiltInResolverTest */ public class BuiltInResolverTest { - private Field builtInResolverField, resolverField; + private static Field builtInResolverField, resolverField; - @BeforeTest - public void beforeTest() throws NoSuchFieldException { + @BeforeAll + public static void beforeTest() throws NoSuchFieldException { Class inetAddressClass = InetAddress.class; // Needs to happen for InetAddress.resolver to be initialized try { @@ -72,7 +76,7 @@ public class BuiltInResolverTest { assertNotNull(defaultClassName, "defaultClassName not set"); assertNotNull(currentClassName, "currentClassName name not set"); - assertEquals(currentClassName, defaultClassName, + assertEquals(defaultClassName, currentClassName, "BUILTIN_RESOLVER resolver was not used."); System.err.println("Resolver used by default is the built-in resolver"); } diff --git a/test/jdk/java/net/spi/InetAddressResolverProvider/EmptyResultsStreamTest.java b/test/jdk/java/net/spi/InetAddressResolverProvider/EmptyResultsStreamTest.java index 17b9aa5d011..db0f293b712 100644 --- a/test/jdk/java/net/spi/InetAddressResolverProvider/EmptyResultsStreamTest.java +++ b/test/jdk/java/net/spi/InetAddressResolverProvider/EmptyResultsStreamTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * 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,32 +21,36 @@ * questions. */ -import org.testng.Assert; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.Arrays; +import static org.junit.jupiter.api.Assertions.assertThrows; /* * @test * @summary checks that InetAddress forward lookup API throw UnknownHostException * when resolver returns empty address stream. * @library providers/empty * @build empty.results.provider/impl.EmptyResultsProviderImpl - * @run testng/othervm EmptyResultsStreamTest + * @run junit/othervm EmptyResultsStreamTest */ public class EmptyResultsStreamTest { - @Test(expectedExceptions = UnknownHostException.class) - public void getAllByNameTest() throws UnknownHostException { - System.err.println("getAllByName unexpectedly completed: " + - Arrays.deepToString(InetAddress.getAllByName("test1.org"))); + @Test() + public void getAllByNameTest() { + assertThrows(UnknownHostException.class, () -> { + System.err.println("getAllByName unexpectedly completed: " + + Arrays.deepToString(InetAddress.getAllByName("test1.org"))); + }); } - @Test(expectedExceptions = UnknownHostException.class) - public void getByNameTest() throws UnknownHostException { - System.err.println("getByName unexpectedly completed: " + - InetAddress.getByName("test2.org")); + @Test() + public void getByNameTest() { + assertThrows(UnknownHostException.class, () -> { + System.err.println("getByName unexpectedly completed: " + + InetAddress.getByName("test2.org")); + }); } } diff --git a/test/jdk/java/net/spi/InetAddressResolverProvider/InetAddressUsageInGetProviderTest.java b/test/jdk/java/net/spi/InetAddressResolverProvider/InetAddressUsageInGetProviderTest.java index dd52893c1e8..3458270960b 100644 --- a/test/jdk/java/net/spi/InetAddressResolverProvider/InetAddressUsageInGetProviderTest.java +++ b/test/jdk/java/net/spi/InetAddressResolverProvider/InetAddressUsageInGetProviderTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,8 +21,7 @@ * questions. */ -import org.testng.Assert; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import java.net.InetAddress; @@ -32,7 +31,7 @@ import java.net.InetAddress; * wouldn't cause stack overflow and will be successfully installed. * @library providers/recursive * @build recursive.init.provider/impl.InetAddressUsageInGetProviderImpl - * @run testng/othervm InetAddressUsageInGetProviderTest + * @run junit/othervm InetAddressUsageInGetProviderTest */ public class InetAddressUsageInGetProviderTest { diff --git a/test/jdk/java/net/spi/InetAddressResolverProvider/LookupPolicyMappingTest.java b/test/jdk/java/net/spi/InetAddressResolverProvider/LookupPolicyMappingTest.java index e845e2e0461..bbfa9f5555c 100644 --- a/test/jdk/java/net/spi/InetAddressResolverProvider/LookupPolicyMappingTest.java +++ b/test/jdk/java/net/spi/InetAddressResolverProvider/LookupPolicyMappingTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * 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,9 +34,10 @@ import static java.net.spi.InetAddressResolver.LookupPolicy.IPV6_FIRST; import jdk.test.lib.net.IPSupport; import jdk.test.lib.NetworkConfiguration; -import org.testng.annotations.Test; -import org.testng.Assert; -import org.testng.SkipException; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assumptions.abort; /* * @test @@ -45,26 +46,26 @@ import org.testng.SkipException; * @library lib providers/simple /test/lib * @build test.library/testlib.ResolutionRegistry simple.provider/impl.SimpleResolverProviderImpl * jdk.test.lib.net.IPSupport LookupPolicyMappingTest - * @run testng/othervm LookupPolicyMappingTest - * @run testng/othervm -Djava.net.preferIPv4Stack=true -Djava.net.preferIPv6Addresses=true LookupPolicyMappingTest - * @run testng/othervm -Djava.net.preferIPv4Stack=true -Djava.net.preferIPv6Addresses=false LookupPolicyMappingTest - * @run testng/othervm -Djava.net.preferIPv4Stack=true -Djava.net.preferIPv6Addresses=system LookupPolicyMappingTest - * @run testng/othervm -Djava.net.preferIPv4Stack=true -Djava.net.preferIPv6Addresses LookupPolicyMappingTest - * @run testng/othervm -Djava.net.preferIPv4Stack=true LookupPolicyMappingTest - * @run testng/othervm -Djava.net.preferIPv4Stack=false -Djava.net.preferIPv6Addresses=true LookupPolicyMappingTest - * @run testng/othervm -Djava.net.preferIPv4Stack=false -Djava.net.preferIPv6Addresses=false LookupPolicyMappingTest - * @run testng/othervm -Djava.net.preferIPv4Stack=false -Djava.net.preferIPv6Addresses=system LookupPolicyMappingTest - * @run testng/othervm -Djava.net.preferIPv4Stack=false -Djava.net.preferIPv6Addresses LookupPolicyMappingTest - * @run testng/othervm -Djava.net.preferIPv4Stack=false LookupPolicyMappingTest - * @run testng/othervm -Djava.net.preferIPv4Stack -Djava.net.preferIPv6Addresses=true LookupPolicyMappingTest - * @run testng/othervm -Djava.net.preferIPv4Stack -Djava.net.preferIPv6Addresses=false LookupPolicyMappingTest - * @run testng/othervm -Djava.net.preferIPv4Stack -Djava.net.preferIPv6Addresses=system LookupPolicyMappingTest - * @run testng/othervm -Djava.net.preferIPv4Stack -Djava.net.preferIPv6Addresses LookupPolicyMappingTest - * @run testng/othervm -Djava.net.preferIPv4Stack LookupPolicyMappingTest - * @run testng/othervm -Djava.net.preferIPv6Addresses=true LookupPolicyMappingTest - * @run testng/othervm -Djava.net.preferIPv6Addresses=false LookupPolicyMappingTest - * @run testng/othervm -Djava.net.preferIPv6Addresses=system LookupPolicyMappingTest - * @run testng/othervm -Djava.net.preferIPv6Addresses LookupPolicyMappingTest + * @run junit/othervm LookupPolicyMappingTest + * @run junit/othervm -Djava.net.preferIPv4Stack=true -Djava.net.preferIPv6Addresses=true LookupPolicyMappingTest + * @run junit/othervm -Djava.net.preferIPv4Stack=true -Djava.net.preferIPv6Addresses=false LookupPolicyMappingTest + * @run junit/othervm -Djava.net.preferIPv4Stack=true -Djava.net.preferIPv6Addresses=system LookupPolicyMappingTest + * @run junit/othervm -Djava.net.preferIPv4Stack=true -Djava.net.preferIPv6Addresses LookupPolicyMappingTest + * @run junit/othervm -Djava.net.preferIPv4Stack=true LookupPolicyMappingTest + * @run junit/othervm -Djava.net.preferIPv4Stack=false -Djava.net.preferIPv6Addresses=true LookupPolicyMappingTest + * @run junit/othervm -Djava.net.preferIPv4Stack=false -Djava.net.preferIPv6Addresses=false LookupPolicyMappingTest + * @run junit/othervm -Djava.net.preferIPv4Stack=false -Djava.net.preferIPv6Addresses=system LookupPolicyMappingTest + * @run junit/othervm -Djava.net.preferIPv4Stack=false -Djava.net.preferIPv6Addresses LookupPolicyMappingTest + * @run junit/othervm -Djava.net.preferIPv4Stack=false LookupPolicyMappingTest + * @run junit/othervm -Djava.net.preferIPv4Stack -Djava.net.preferIPv6Addresses=true LookupPolicyMappingTest + * @run junit/othervm -Djava.net.preferIPv4Stack -Djava.net.preferIPv6Addresses=false LookupPolicyMappingTest + * @run junit/othervm -Djava.net.preferIPv4Stack -Djava.net.preferIPv6Addresses=system LookupPolicyMappingTest + * @run junit/othervm -Djava.net.preferIPv4Stack -Djava.net.preferIPv6Addresses LookupPolicyMappingTest + * @run junit/othervm -Djava.net.preferIPv4Stack LookupPolicyMappingTest + * @run junit/othervm -Djava.net.preferIPv6Addresses=true LookupPolicyMappingTest + * @run junit/othervm -Djava.net.preferIPv6Addresses=false LookupPolicyMappingTest + * @run junit/othervm -Djava.net.preferIPv6Addresses=system LookupPolicyMappingTest + * @run junit/othervm -Djava.net.preferIPv6Addresses LookupPolicyMappingTest */ public class LookupPolicyMappingTest { @@ -88,7 +89,7 @@ public class LookupPolicyMappingTest { String expectedResultsKey = calculateMapKey(preferIPv4Stack, preferIPv6Addresses); int expectedCharacteristics = EXPECTED_RESULTS_MAP.get(expectedResultsKey); - Assert.assertTrue(characteristicsMatch( + assertTrue(characteristicsMatch( runtimeCharacteristics, expectedCharacteristics), "Unexpected LookupPolicy observed"); } @@ -100,7 +101,7 @@ public class LookupPolicyMappingTest { // If preferIPv4=true and no IPv4 - skip if (IPSupport.preferIPv4Stack()) { if (!IPSupport.hasIPv4()) { - throw new SkipException("Skip tests - IPv4 support required"); + abort("Skip tests - IPv4 support required"); } return; } diff --git a/test/jdk/java/net/spi/InetAddressResolverProvider/LookupPolicyOfTest.java b/test/jdk/java/net/spi/InetAddressResolverProvider/LookupPolicyOfTest.java index 73e2581f5cd..09585322c83 100644 --- a/test/jdk/java/net/spi/InetAddressResolverProvider/LookupPolicyOfTest.java +++ b/test/jdk/java/net/spi/InetAddressResolverProvider/LookupPolicyOfTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * 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,11 +25,11 @@ * @test * @summary check if LookupPolicy.of correctly handles valid and illegal * combinations of characteristics bit mask flags. - * @run testng LookupPolicyOfTest + * @run junit LookupPolicyOfTest */ -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; import java.net.spi.InetAddressResolver.LookupPolicy; import java.util.List; @@ -38,21 +38,23 @@ import static java.net.spi.InetAddressResolver.LookupPolicy.IPV4; import static java.net.spi.InetAddressResolver.LookupPolicy.IPV4_FIRST; import static java.net.spi.InetAddressResolver.LookupPolicy.IPV6; import static java.net.spi.InetAddressResolver.LookupPolicy.IPV6_FIRST; +import static org.junit.jupiter.api.Assertions.assertThrows; public class LookupPolicyOfTest { - @Test(dataProvider = "validCharacteristics") + @ParameterizedTest + @MethodSource("validCharacteristicValue") public void testValidCharacteristicCombinations(List validCombination) { LookupPolicy.of(bitFlagsToCharacteristicsValue(validCombination)); } - @Test(dataProvider = "invalidCharacteristics", expectedExceptions = IllegalArgumentException.class) - public void testInvalidCharacteristicCombinations(List invalidCombination) { - LookupPolicy.of(bitFlagsToCharacteristicsValue(invalidCombination)); + @ParameterizedTest + @MethodSource("illegalCharacteristicValue") + public void testInvalidCharacteristicCombination(List invalidCombination) { + assertThrows(IllegalArgumentException.class, () -> LookupPolicy.of(bitFlagsToCharacteristicsValue(invalidCombination))); } - @DataProvider(name = "validCharacteristics") - public Object[][] validCharacteristicValue() { + public static Object[][] validCharacteristicValue() { return new Object[][]{ {List.of(IPV4)}, {List.of(IPV4, IPV4_FIRST)}, @@ -68,8 +70,7 @@ public class LookupPolicyOfTest { }; } - @DataProvider(name = "invalidCharacteristics") - public Object[][] illegalCharacteristicValue() { + public static Object[][] illegalCharacteristicValue() { return new Object[][]{ {List.of()}, {List.of(IPV4_FIRST)}, diff --git a/test/jdk/java/net/spi/InetAddressResolverProvider/ProviderGetExceptionTest.java b/test/jdk/java/net/spi/InetAddressResolverProvider/ProviderGetExceptionTest.java index fe5269c7b46..7df304bc235 100644 --- a/test/jdk/java/net/spi/InetAddressResolverProvider/ProviderGetExceptionTest.java +++ b/test/jdk/java/net/spi/InetAddressResolverProvider/ProviderGetExceptionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * 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,13 +21,15 @@ * questions. */ +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.function.Executable; import java.net.InetAddress; import java.util.Arrays; -import org.testng.Assert; -import org.testng.annotations.Test; - import static impl.FaultyResolverProviderGetImpl.EXCEPTION_MESSAGE; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; /* * @test @@ -35,7 +37,7 @@ import static impl.FaultyResolverProviderGetImpl.EXCEPTION_MESSAGE; * instantiate a resolver. * @library providers/faulty * @build faulty.provider/impl.FaultyResolverProviderGetImpl - * @run testng/othervm ProviderGetExceptionTest + * @run junit/othervm ProviderGetExceptionTest */ public class ProviderGetExceptionTest { @@ -54,10 +56,10 @@ public class ProviderGetExceptionTest { callInetAddressAndCheckException(() -> InetAddress.getByAddress(address).getHostName()); } - private void callInetAddressAndCheckException(Assert.ThrowingRunnable apiCall) { - IllegalArgumentException iae = Assert.expectThrows(IllegalArgumentException.class, apiCall); + private void callInetAddressAndCheckException(Executable apiCall) { + IllegalArgumentException iae = assertThrows(IllegalArgumentException.class, apiCall); System.out.println("Got exception of expected type:" + iae); - Assert.assertNull(iae.getCause(), "cause is not null"); - Assert.assertEquals(iae.getMessage(), EXCEPTION_MESSAGE); + assertNull(iae.getCause(), "cause is not null"); + assertEquals(EXCEPTION_MESSAGE, iae.getMessage()); } } diff --git a/test/jdk/java/net/spi/InetAddressResolverProvider/ResolutionWithExceptionTest.java b/test/jdk/java/net/spi/InetAddressResolverProvider/ResolutionWithExceptionTest.java index dd17c1d987c..ce68f8a8e6f 100644 --- a/test/jdk/java/net/spi/InetAddressResolverProvider/ResolutionWithExceptionTest.java +++ b/test/jdk/java/net/spi/InetAddressResolverProvider/ResolutionWithExceptionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,9 +27,11 @@ import java.net.UnknownHostException; import impl.ThrowingLookupsProviderImpl; import static impl.ThrowingLookupsProviderImpl.RUNTIME_EXCEPTION_MESSAGE; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; -import org.testng.Assert; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; /* * @test @@ -37,7 +39,7 @@ import org.testng.annotations.Test; * implementation throws RuntimeException during forward or reverse lookup. * @library providers/throwing * @build throwing.lookups.provider/impl.ThrowingLookupsProviderImpl - * @run testng/othervm ResolutionWithExceptionTest + * @run junit/othervm ResolutionWithExceptionTest */ public class ResolutionWithExceptionTest { @@ -68,7 +70,7 @@ public class ResolutionWithExceptionTest { private void runGetByNameTest() { // InetAddress.getByName() is expected to throw UnknownHostException in all cases - UnknownHostException uhe = Assert.expectThrows(UnknownHostException.class, + UnknownHostException uhe = Assertions.assertThrows(UnknownHostException.class, () -> InetAddress.getByName("doesnt.matter.com")); // If provider is expected to throw RuntimeException - check that UnknownHostException // is set as its cause @@ -76,10 +78,10 @@ public class ResolutionWithExceptionTest { Throwable cause = uhe.getCause(); if (cause instanceof RuntimeException re) { // Check RuntimeException message - Assert.assertEquals(re.getMessage(), RUNTIME_EXCEPTION_MESSAGE, + assertEquals(RUNTIME_EXCEPTION_MESSAGE, re.getMessage(), "incorrect exception message"); } else { - Assert.fail("UnknownHostException cause is not RuntimeException"); + fail("UnknownHostException cause is not RuntimeException"); } } } @@ -89,6 +91,6 @@ public class ResolutionWithExceptionTest { // if there is an error during reverse lookup operation the literal IP // address String will be returned. String literalIP = InetAddress.getByAddress(new byte[]{1, 2, 3, 4}).getCanonicalHostName(); - Assert.assertEquals(literalIP, "1.2.3.4"); + assertEquals("1.2.3.4", literalIP); } } diff --git a/test/jdk/java/net/spi/InetAddressResolverProvider/ReverseLookupDelegationTest.java b/test/jdk/java/net/spi/InetAddressResolverProvider/ReverseLookupDelegationTest.java index 439521736db..d72a6b1fc0e 100644 --- a/test/jdk/java/net/spi/InetAddressResolverProvider/ReverseLookupDelegationTest.java +++ b/test/jdk/java/net/spi/InetAddressResolverProvider/ReverseLookupDelegationTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * 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,9 +21,9 @@ * questions. */ -import impl.DelegatingProviderImpl; -import org.testng.Assert; -import org.testng.annotations.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.Test; import java.net.InetAddress; import java.net.UnknownHostException; @@ -37,7 +37,7 @@ import static impl.DelegatingProviderImpl.lastReverseLookupThrowable; * InetAddressResolver. * @library providers/delegating * @build delegating.provider/impl.DelegatingProviderImpl - * @run testng/othervm ReverseLookupDelegationTest + * @run junit/othervm ReverseLookupDelegationTest */ public class ReverseLookupDelegationTest { @@ -53,10 +53,10 @@ public class ReverseLookupDelegationTest { // Check that originally supplied byte array was used to construct canonical host name after // failed reverse lookup. - Assert.assertEquals("1.2.3.4", canonicalHostName, "unexpected canonical hostname"); + assertEquals("1.2.3.4", canonicalHostName, "unexpected canonical hostname"); // Check that on a provider side the IllegalArgumentException has been thrown by the built-in resolver - Assert.assertTrue(lastReverseLookupThrowable instanceof IllegalArgumentException, + assertTrue(lastReverseLookupThrowable instanceof IllegalArgumentException, "wrong exception type is thrown by the built-in resolver"); } } diff --git a/test/jdk/java/net/spi/InetAddressResolverProvider/serviceProviderOriginType/classpath/ClasspathProviderTest.java b/test/jdk/java/net/spi/InetAddressResolverProvider/serviceProviderOriginType/classpath/ClasspathProviderTest.java index 51285fb045c..c82f2442831 100644 --- a/test/jdk/java/net/spi/InetAddressResolverProvider/serviceProviderOriginType/classpath/ClasspathProviderTest.java +++ b/test/jdk/java/net/spi/InetAddressResolverProvider/serviceProviderOriginType/classpath/ClasspathProviderTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * 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,18 +21,17 @@ * questions. */ +import org.junit.jupiter.api.Test; + import java.net.InetAddress; -import org.testng.annotations.Test; - -import static org.testng.Assert.assertThrows; /* * @test * @summary Test that InetAddressResolverProvider implementation can be installed to a class path. * @library ../../lib * @build test.library/testlib.ResolutionRegistry ClasspathResolverProviderImpl - * @run testng/othervm ClasspathProviderTest + * @run junit/othervm ClasspathProviderTest */ public class ClasspathProviderTest { diff --git a/test/jdk/java/net/spi/InetAddressResolverProvider/serviceProviderOriginType/module/ModularProviderTest.java b/test/jdk/java/net/spi/InetAddressResolverProvider/serviceProviderOriginType/module/ModularProviderTest.java index 410f25aa9c3..56e52d52729 100644 --- a/test/jdk/java/net/spi/InetAddressResolverProvider/serviceProviderOriginType/module/ModularProviderTest.java +++ b/test/jdk/java/net/spi/InetAddressResolverProvider/serviceProviderOriginType/module/ModularProviderTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * 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,9 +21,10 @@ * questions. */ +import org.junit.jupiter.api.Test; + import java.net.InetAddress; -import org.testng.annotations.Test; /* * @test @@ -31,7 +32,7 @@ import org.testng.annotations.Test; * @library ../../lib ../../providers/simple * @build test.library/testlib.ResolutionRegistry simple.provider/impl.SimpleResolverProviderImpl * ModularProviderTest - * @run testng/othervm ModularProviderTest + * @run junit/othervm ModularProviderTest */ From e05eb1418e73b69c9c4571006a009bb1d3cf21ce Mon Sep 17 00:00:00 2001 From: Vicente Romero Date: Thu, 2 Apr 2026 22:57:35 +0000 Subject: [PATCH 163/359] 8381475: Test tools/sincechecker/modules/jdk.compiler/JdkCompilerCheckSince.java fails for DocSourcePositions.java Reviewed-by: mikael --- .../share/classes/com/sun/source/util/DocSourcePositions.java | 2 ++ .../share/classes/com/sun/source/util/SourcePositions.java | 2 ++ .../modules/jdk.compiler/JdkCompilerCheckSince.java | 2 +- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/jdk.compiler/share/classes/com/sun/source/util/DocSourcePositions.java b/src/jdk.compiler/share/classes/com/sun/source/util/DocSourcePositions.java index d0afd126bf6..4eb6d12fd38 100644 --- a/src/jdk.compiler/share/classes/com/sun/source/util/DocSourcePositions.java +++ b/src/jdk.compiler/share/classes/com/sun/source/util/DocSourcePositions.java @@ -83,6 +83,7 @@ public interface DocSourcePositions extends SourcePositions { * @param comment the comment tree that encloses the tree for which the * position is being sought * @param tree tree for which a position is sought + * @since 27 */ long getStartPosition(DocCommentTree comment, DocTree tree); @@ -146,6 +147,7 @@ public interface DocSourcePositions extends SourcePositions { * @param comment the comment tree that encloses the tree for which the * position is being sought * @param tree tree for which a position is sought + * @since 27 */ long getEndPosition(DocCommentTree comment, DocTree tree); diff --git a/src/jdk.compiler/share/classes/com/sun/source/util/SourcePositions.java b/src/jdk.compiler/share/classes/com/sun/source/util/SourcePositions.java index 460f4f2a1ce..3ff6fafe58b 100644 --- a/src/jdk.compiler/share/classes/com/sun/source/util/SourcePositions.java +++ b/src/jdk.compiler/share/classes/com/sun/source/util/SourcePositions.java @@ -74,6 +74,7 @@ public interface SourcePositions { *

* * @param tree tree for which a position is sought + * @since 27 */ long getStartPosition(Tree tree); @@ -130,6 +131,7 @@ public interface SourcePositions { *

* * @param tree tree for which a position is sought + * @since 27 */ long getEndPosition(Tree tree); } diff --git a/test/jdk/tools/sincechecker/modules/jdk.compiler/JdkCompilerCheckSince.java b/test/jdk/tools/sincechecker/modules/jdk.compiler/JdkCompilerCheckSince.java index 5eb819786e9..bf4b906b623 100644 --- a/test/jdk/tools/sincechecker/modules/jdk.compiler/JdkCompilerCheckSince.java +++ b/test/jdk/tools/sincechecker/modules/jdk.compiler/JdkCompilerCheckSince.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8341399 + * @bug 8341399 8381475 * @summary Test for `@since` in jdk.compiler module * @library /test/lib /test/jdk/tools/sincechecker * @run main SinceChecker jdk.compiler From f1a414b61cab8bf839e3d6e4437ad4ef527c9aa3 Mon Sep 17 00:00:00 2001 From: Shiv Shah Date: Fri, 3 Apr 2026 00:44:00 +0000 Subject: [PATCH 164/359] 8338594: Update nsk/aod tests to use driver instead of othervm Reviewed-by: lmesnik, cjplummer --- .../AttachProvider/AttachProvider01/AttachProvider01.java | 5 ++--- .../VirtualMachine/VirtualMachine01/VirtualMachine01.java | 5 ++--- .../VirtualMachine/VirtualMachine04/VirtualMachine04.java | 5 ++--- .../VirtualMachine/VirtualMachine05/VirtualMachine05.java | 5 ++--- .../VirtualMachine/VirtualMachine06/VirtualMachine06.java | 5 ++--- .../VirtualMachine/VirtualMachine07/VirtualMachine07.java | 3 +-- .../VirtualMachine/VirtualMachine08/TestDescription.java | 3 +-- .../VirtualMachine/VirtualMachine09/VirtualMachine09.java | 3 +-- .../VirtualMachine/VirtualMachine10/TestDescription.java | 3 +-- .../VirtualMachineDescriptor01.java | 5 ++--- .../jtreg/vmTestbase/nsk/share/aod/AODTestRunner.java | 7 ++++++- 11 files changed, 22 insertions(+), 27 deletions(-) diff --git a/test/hotspot/jtreg/vmTestbase/nsk/aod/AttachProvider/AttachProvider01/AttachProvider01.java b/test/hotspot/jtreg/vmTestbase/nsk/aod/AttachProvider/AttachProvider01/AttachProvider01.java index 7e3f7a9687d..dbe640a8719 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/aod/AttachProvider/AttachProvider01/AttachProvider01.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/aod/AttachProvider/AttachProvider01/AttachProvider01.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2026, Oracle and/or its affiliates. All rights reserved. * 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,8 +36,7 @@ * @library /vmTestbase /test/hotspot/jtreg/vmTestbase * /test/lib * @build nsk.share.aod.DummyTargetApplication - * @run main/othervm - * -XX:+UsePerfData + * @run driver * nsk.aod.AttachProvider.AttachProvider01.AttachProvider01 * -jdk ${test.jdk} * -javaOpts="-XX:+UsePerfData ${test.vm.opts} ${test.java.opts}" diff --git a/test/hotspot/jtreg/vmTestbase/nsk/aod/VirtualMachine/VirtualMachine01/VirtualMachine01.java b/test/hotspot/jtreg/vmTestbase/nsk/aod/VirtualMachine/VirtualMachine01/VirtualMachine01.java index 257d4022d2b..3f171367361 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/aod/VirtualMachine/VirtualMachine01/VirtualMachine01.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/aod/VirtualMachine/VirtualMachine01/VirtualMachine01.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2026, Oracle and/or its affiliates. All rights reserved. * 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,7 @@ * @library /vmTestbase /test/hotspot/jtreg/vmTestbase * /test/lib * @build nsk.share.aod.DummyTargetApplication - * @run main/othervm - * -XX:+UsePerfData + * @run driver * nsk.aod.VirtualMachine.VirtualMachine01.VirtualMachine01 * -jdk ${test.jdk} * -javaOpts="-XX:+UsePerfData ${test.vm.opts} ${test.java.opts}" diff --git a/test/hotspot/jtreg/vmTestbase/nsk/aod/VirtualMachine/VirtualMachine04/VirtualMachine04.java b/test/hotspot/jtreg/vmTestbase/nsk/aod/VirtualMachine/VirtualMachine04/VirtualMachine04.java index 3bd98cd5043..066b2ef8a0f 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/aod/VirtualMachine/VirtualMachine04/VirtualMachine04.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/aod/VirtualMachine/VirtualMachine04/VirtualMachine04.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,8 +39,7 @@ * @library /vmTestbase /test/hotspot/jtreg/vmTestbase * /test/lib * @build nsk.aod.VirtualMachine.VirtualMachine04.VM04Target - * @run main/othervm - * -XX:+UsePerfData + * @run driver * nsk.aod.VirtualMachine.VirtualMachine04.VirtualMachine04 * -jdk ${test.jdk} * -javaOpts="-XX:+UsePerfData ${test.vm.opts} ${test.java.opts}" diff --git a/test/hotspot/jtreg/vmTestbase/nsk/aod/VirtualMachine/VirtualMachine05/VirtualMachine05.java b/test/hotspot/jtreg/vmTestbase/nsk/aod/VirtualMachine/VirtualMachine05/VirtualMachine05.java index 3c7e90a7ffa..c8e7299fd39 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/aod/VirtualMachine/VirtualMachine05/VirtualMachine05.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/aod/VirtualMachine/VirtualMachine05/VirtualMachine05.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2026, Oracle and/or its affiliates. All rights reserved. * 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,8 +36,7 @@ * @library /vmTestbase /test/hotspot/jtreg/vmTestbase * /test/lib * @build nsk.share.aod.DummyTargetApplication - * @run main/othervm - * -XX:+UsePerfData + * @run driver * nsk.aod.VirtualMachine.VirtualMachine05.VirtualMachine05 * -jdk ${test.jdk} * -javaOpts="-XX:+UsePerfData ${test.vm.opts} ${test.java.opts}" diff --git a/test/hotspot/jtreg/vmTestbase/nsk/aod/VirtualMachine/VirtualMachine06/VirtualMachine06.java b/test/hotspot/jtreg/vmTestbase/nsk/aod/VirtualMachine/VirtualMachine06/VirtualMachine06.java index 0fd11e6b8d5..f9bf43d2fe0 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/aod/VirtualMachine/VirtualMachine06/VirtualMachine06.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/aod/VirtualMachine/VirtualMachine06/VirtualMachine06.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -76,8 +76,7 @@ * * * @build nsk.share.aod.TargetApplicationWaitingAgents - * @run main/othervm - * -XX:+UsePerfData + * @run driver * nsk.aod.VirtualMachine.VirtualMachine06.VirtualMachine06 * -jdk ${test.jdk} * -javaOpts="-XX:+UsePerfData ${test.vm.opts} ${test.java.opts}" diff --git a/test/hotspot/jtreg/vmTestbase/nsk/aod/VirtualMachine/VirtualMachine07/VirtualMachine07.java b/test/hotspot/jtreg/vmTestbase/nsk/aod/VirtualMachine/VirtualMachine07/VirtualMachine07.java index 73b4522ae6e..ab37e253fc8 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/aod/VirtualMachine/VirtualMachine07/VirtualMachine07.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/aod/VirtualMachine/VirtualMachine07/VirtualMachine07.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,7 +42,6 @@ * /test/lib * @build nsk.share.aod.TargetApplicationWaitingAgents * @run main/othervm/native - * -XX:+UsePerfData * nsk.aod.VirtualMachine.VirtualMachine07.VirtualMachine07 * -jdk ${test.jdk} * -javaOpts="-XX:+UsePerfData ${test.vm.opts} ${test.java.opts}" diff --git a/test/hotspot/jtreg/vmTestbase/nsk/aod/VirtualMachine/VirtualMachine08/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/aod/VirtualMachine/VirtualMachine08/TestDescription.java index e484641dd2a..14a05f53702 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/aod/VirtualMachine/VirtualMachine08/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/aod/VirtualMachine/VirtualMachine08/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,7 +43,6 @@ * /test/lib * @build nsk.share.aod.TargetApplicationWaitingAgents * @run main/othervm/native - * -XX:+UsePerfData * nsk.aod.VirtualMachine.VirtualMachine07.VirtualMachine07 * -jdk ${test.jdk} * -javaOpts="-XX:+UsePerfData ${test.vm.opts} ${test.java.opts}" diff --git a/test/hotspot/jtreg/vmTestbase/nsk/aod/VirtualMachine/VirtualMachine09/VirtualMachine09.java b/test/hotspot/jtreg/vmTestbase/nsk/aod/VirtualMachine/VirtualMachine09/VirtualMachine09.java index 47d1a718e88..3b2852fc0ad 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/aod/VirtualMachine/VirtualMachine09/VirtualMachine09.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/aod/VirtualMachine/VirtualMachine09/VirtualMachine09.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ * /test/lib * @build nsk.aod.VirtualMachine.VirtualMachine09.VM09Target * @run main/othervm/native - * -XX:+UsePerfData * nsk.aod.VirtualMachine.VirtualMachine09.VirtualMachine09 * -jdk ${test.jdk} * -javaOpts="-agentlib:VirtualMachine09agent00 -XX:+UsePerfData ${test.vm.opts} ${test.java.opts}" diff --git a/test/hotspot/jtreg/vmTestbase/nsk/aod/VirtualMachine/VirtualMachine10/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/aod/VirtualMachine/VirtualMachine10/TestDescription.java index c9c5b1ee64f..139fe236635 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/aod/VirtualMachine/VirtualMachine10/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/aod/VirtualMachine/VirtualMachine10/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,7 +40,6 @@ * /test/lib * @build nsk.aod.VirtualMachine.VirtualMachine09.VM09Target * @run main/othervm/native - * -XX:+UsePerfData * nsk.aod.VirtualMachine.VirtualMachine09.VirtualMachine09 * -jdk ${test.jdk} * -javaOpts="-agentlib:VirtualMachine09agent00 -XX:+UsePerfData ${test.vm.opts} ${test.java.opts}" diff --git a/test/hotspot/jtreg/vmTestbase/nsk/aod/VirtualMachineDescriptor/VirtualMachineDescriptor01/VirtualMachineDescriptor01.java b/test/hotspot/jtreg/vmTestbase/nsk/aod/VirtualMachineDescriptor/VirtualMachineDescriptor01/VirtualMachineDescriptor01.java index 47f837a110f..02448528f12 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/aod/VirtualMachineDescriptor/VirtualMachineDescriptor01/VirtualMachineDescriptor01.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/aod/VirtualMachineDescriptor/VirtualMachineDescriptor01/VirtualMachineDescriptor01.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,8 +38,7 @@ * @library /vmTestbase /test/hotspot/jtreg/vmTestbase * /test/lib * @build nsk.share.aod.DummyTargetApplication - * @run main/othervm - * -XX:+UsePerfData + * @run driver * nsk.aod.VirtualMachineDescriptor.VirtualMachineDescriptor01.VirtualMachineDescriptor01 * -jdk ${test.jdk} * -javaOpts="-XX:+UsePerfData ${test.vm.opts} ${test.java.opts}" diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/aod/AODTestRunner.java b/test/hotspot/jtreg/vmTestbase/nsk/share/aod/AODTestRunner.java index 9899c762a7a..abfca89ca4d 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/aod/AODTestRunner.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/aod/AODTestRunner.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -103,9 +103,14 @@ public class AODTestRunner { /* * Create target application id required by the Utils.findVMIdUsingJPS */ + String classPath = System.getProperty("test.class.path"); + if (classPath == null) { + throw new RuntimeException("test.class.path is not set"); + } String targetAppCmd = // path to java argParser.getTestedJDK() + File.separator + "bin" + File.separator + "java " + + "-classpath " + classPath + " " + // VM property to identify VM running target application "-D" + appIdProperty + "=" + targetAppId + " " + // VM opts From fbbf2c3af34411f108bf983e52faf8f63a224a31 Mon Sep 17 00:00:00 2001 From: Shiv Shah Date: Fri, 3 Apr 2026 00:52:00 +0000 Subject: [PATCH 165/359] 8269613: vmTestbase/vm/mlvm/mixed/stress/java/findDeadlock/TestDescription.java fails with OOME in CodeCache Reviewed-by: lmesnik, epavlova --- .../mlvm/mixed/stress/java/findDeadlock/TestDescription.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/vmTestbase/vm/mlvm/mixed/stress/java/findDeadlock/TestDescription.java b/test/hotspot/jtreg/vmTestbase/vm/mlvm/mixed/stress/java/findDeadlock/TestDescription.java index ec2b2753340..ed186aa3f84 100644 --- a/test/hotspot/jtreg/vmTestbase/vm/mlvm/mixed/stress/java/findDeadlock/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/vm/mlvm/mixed/stress/java/findDeadlock/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,8 @@ * @library /vmTestbase * /test/lib * + * @requires vm.compMode != "Xcomp" + * * @comment build test class and indify classes * @build vm.mlvm.mixed.stress.java.findDeadlock.INDIFY_Test * @run driver vm.mlvm.share.IndifiedClassesBuilder From 95e90299b47c3f82c8711ba8799810fbb01ab5df Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Fri, 3 Apr 2026 03:20:38 +0000 Subject: [PATCH 166/359] 8381553: Clean up AOTCodeCache configuration checks Reviewed-by: kvn, asmehra --- src/hotspot/share/code/aotCodeCache.cpp | 386 ++++-------------- src/hotspot/share/code/aotCodeCache.hpp | 216 +++++----- .../aotCode/AOTCodeCompressedOopsTest.java | 14 +- .../JDKMethodHandlesTestRunner.java | 4 +- 4 files changed, 201 insertions(+), 419 deletions(-) diff --git a/src/hotspot/share/code/aotCodeCache.cpp b/src/hotspot/share/code/aotCodeCache.cpp index 938cf4eaa41..e3cbc3c3c8b 100644 --- a/src/hotspot/share/code/aotCodeCache.cpp +++ b/src/hotspot/share/code/aotCodeCache.cpp @@ -73,11 +73,23 @@ const char* aot_code_entry_kind_name[] = { #undef DECL_KIND_STRING }; +// Stream to printing AOTCodeCache loading failure. +// Print to error channel when -XX:AOTMode is set to "on" +static LogStream& load_failure_log() { + static LogStream err_stream(LogLevel::Error, LogTagSetMapping::tagset()); + static LogStream dbg_stream(LogLevel::Debug, LogTagSetMapping::tagset()); + if (RequireSharedSpaces) { + return err_stream; + } else { + return dbg_stream; + } +} + static void report_load_failure() { if (AbortVMOnAOTCodeFailure) { vm_exit_during_initialization("Unable to use AOT Code Cache.", nullptr); } - log_info(aot, codecache, init)("Unable to use AOT Code Cache."); + load_failure_log().print_cr("Unable to use AOT Code Cache."); AOTCodeCache::disable_caching(); } @@ -86,7 +98,7 @@ static void report_store_failure() { tty->print_cr("Unable to create AOT Code Cache."); vm_abort(false); } - log_info(aot, codecache, exit)("Unable to create AOT Code Cache."); + log_error(aot, codecache, exit)("Unable to create AOT Code Cache."); AOTCodeCache::disable_caching(); } @@ -380,110 +392,27 @@ void AOTCodeCache::init_early_c1_table() { } } -// macro to record which flags are set -- flag_type selects the -// relevant accessor e.g. set_flag, set_x86_flag, set_x86_use_flag. -// n.b. flag_enum_name and global_flag_name are both needed because we -// don't have consistent conventions for naming global flags e.g. -// EnableContended vs UseMulAddIntrinsic vs UseCRC32Intrinsics - -#define RECORD_FLAG(flag_type, flag_enum_name, global_flag_name) \ - if (global_flag_name) { \ - set_ ## flag_type ## flag(flag_enum_name); \ - } - void AOTCodeCache::Config::record(uint cpu_features_offset) { - _flags = 0; -#ifdef ASSERT - set_flag(debugVM); -#endif - RECORD_FLAG(, compressedOops, UseCompressedOops); - RECORD_FLAG(, useTLAB, UseTLAB); - if (JavaAssertions::systemClassDefault()) { - set_flag(systemClassAssertions); - } - if (JavaAssertions::userClassDefault()) { - set_flag(userClassAssertions); - } - RECORD_FLAG(, enableContendedPadding, EnableContended); - RECORD_FLAG(, restrictContendedPadding, RestrictContended); - _compressedOopShift = CompressedOops::shift(); +#define AOTCODECACHE_SAVE_VAR(type, name) _saved_ ## name = name; +#define AOTCODECACHE_SAVE_FUN(type, name, fun) _saved_ ## name = fun; + + AOTCODECACHE_CONFIGS_DO(AOTCODECACHE_SAVE_VAR, AOTCODECACHE_SAVE_FUN); + + // Special configs that cannot be checked with macros _compressedOopBase = CompressedOops::base(); - _compressedKlassShift = CompressedKlassPointers::shift(); - _contendedPaddingWidth = ContendedPaddingWidth; - _gc = (uint)Universe::heap()->kind(); - _optoLoopAlignment = (uint)OptoLoopAlignment; - _codeEntryAlignment = (uint)CodeEntryAlignment; - _allocatePrefetchLines = (uint)AllocatePrefetchLines; - _allocateInstancePrefetchLines = (uint)AllocateInstancePrefetchLines; - _allocatePrefetchDistance = (uint)AllocatePrefetchDistance; - _allocatePrefetchStepSize = (uint)AllocatePrefetchStepSize; - _use_intrinsics_flags = 0; - RECORD_FLAG(use_, useCRC32, UseCRC32Intrinsics); - RECORD_FLAG(use_, useCRC32C, UseCRC32CIntrinsics); -#ifdef COMPILER2 - _maxVectorSize = (uint)MaxVectorSize; - _arrayOperationPartialInlineSize = (uint)ArrayOperationPartialInlineSize; - RECORD_FLAG(use_, useMultiplyToLen, UseMultiplyToLenIntrinsic); - RECORD_FLAG(use_, useSquareToLen, UseSquareToLenIntrinsic); - RECORD_FLAG(use_, useMulAdd, UseMulAddIntrinsic); - RECORD_FLAG(use_, useMontgomeryMultiply, UseMontgomeryMultiplyIntrinsic); - RECORD_FLAG(use_, useMontgomerySquare, UseMontgomerySquareIntrinsic); -#endif // COMPILER2 - RECORD_FLAG(use_, useChaCha20, UseChaCha20Intrinsics); - RECORD_FLAG(use_, useDilithium, UseDilithiumIntrinsics); - RECORD_FLAG(use_, useKyber, UseKyberIntrinsics); - RECORD_FLAG(use_, useBASE64, UseBASE64Intrinsics); - RECORD_FLAG(use_, useAdler32, UseAdler32Intrinsics); - RECORD_FLAG(use_, useAES, UseAESIntrinsics); - RECORD_FLAG(use_, useAESCTR, UseAESCTRIntrinsics); - RECORD_FLAG(use_, useGHASH, UseGHASHIntrinsics); - RECORD_FLAG(use_, useMD5, UseMD5Intrinsics); - RECORD_FLAG(use_, useSHA1, UseSHA1Intrinsics); - RECORD_FLAG(use_, useSHA256, UseSHA256Intrinsics); - RECORD_FLAG(use_, useSHA512, UseSHA512Intrinsics); - RECORD_FLAG(use_, useSHA3, UseSHA3Intrinsics); - RECORD_FLAG(use_, usePoly1305, UsePoly1305Intrinsics); - RECORD_FLAG(use_, useVectorizedMismatch,UseVectorizedMismatchIntrinsic ); - RECORD_FLAG(use_, useSecondarySupersTable, UseSecondarySupersTable); + #if defined(X86) && !defined(ZERO) - _avx3threshold = (uint)AVX3Threshold; - _useAVX = (uint)UseAVX; - _x86_flags = 0; - RECORD_FLAG(x86_, x86_enableX86ECoreOpts, EnableX86ECoreOpts); - RECORD_FLAG(x86_, x86_useUnalignedLoadStores, UseUnalignedLoadStores); - RECORD_FLAG(x86_, x86_useAPX, UseAPX); - - _x86_use_intrinsics_flags = 0; - RECORD_FLAG(x86_use_, x86_useLibm, UseLibmIntrinsic); - RECORD_FLAG(x86_use_, x86_useIntPoly, UseIntPolyIntrinsics); -#endif // defined(X86) && !defined(ZERO) -#if defined(AARCH64) && !defined(ZERO) - _prefetchCopyIntervalInBytes = (uint)PrefetchCopyIntervalInBytes; - _blockZeroingLowLimit = (uint)BlockZeroingLowLimit; - _softwarePrefetchHintDistance = (uint)SoftwarePrefetchHintDistance; - _useSVE = (uint)UseSVE; - _aarch64_flags = 0; - RECORD_FLAG(aarch64_, aarch64_avoidUnalignedAccesses, AvoidUnalignedAccesses); - RECORD_FLAG(aarch64_, aarch64_useSIMDForMemoryOps, UseSIMDForMemoryOps); - RECORD_FLAG(aarch64_, aarch64_useSIMDForArrayEquals, UseSIMDForArrayEquals); - RECORD_FLAG(aarch64_, aarch64_useSIMDForSHA3, UseSIMDForSHA3Intrinsic); - RECORD_FLAG(aarch64_, aarch64_useLSE, UseLSE); - - _aarch64_use_intrinsics_flags = 0; - RECORD_FLAG(aarch64_use_, aarch64_useBlockZeroing, UseBlockZeroing); - RECORD_FLAG(aarch64_use_, aarch64_useSIMDForBigIntegerShift, UseSIMDForBigIntegerShiftIntrinsics); - RECORD_FLAG(aarch64_use_, aarch64_useSimpleArrayEquals, UseSimpleArrayEquals); - RECORD_FLAG(aarch64_use_, aarch64_useSecondarySupersCache, UseSecondarySupersCache); -#endif // defined(AARCH64) && !defined(ZERO) -#if INCLUDE_JVMCI - _enableJVMCI = (uint)EnableJVMCI; + _useUnalignedLoadStores = UseUnalignedLoadStores; #endif + +#if defined(AARCH64) && !defined(ZERO) + _avoidUnalignedAccesses = AvoidUnalignedAccesses; +#endif + _cpu_features_offset = cpu_features_offset; } -#undef RECORD_FLAG - bool AOTCodeCache::Config::verify_cpu_features(AOTCodeCache* cache) const { LogStreamHandle(Debug, aot, codecache, init) log; uint offset = _cpu_features_offset; @@ -511,271 +440,114 @@ bool AOTCodeCache::Config::verify_cpu_features(AOTCodeCache* cache) const { } } } else { - if (log.is_enabled()) { + if (load_failure_log().is_enabled()) { ResourceMark rm; // required for stringStream::as_string() stringStream ss; char* runtime_cpu_features = NEW_RESOURCE_ARRAY(char, VM_Version::cpu_features_size()); VM_Version::store_cpu_features(runtime_cpu_features); VM_Version::get_missing_features_name(cached_cpu_features_buffer, runtime_cpu_features, ss); - log.print_cr("AOT Code Cache disabled: required cpu features are missing: %s", ss.as_string()); + load_failure_log().print_cr("AOT Code Cache disabled: required cpu features are missing: %s", ss.as_string()); } return false; } return true; } -// macro to do *standard* flag eq checks -- flag_type selects the -// relevant accessor e.g. test_flag, test_x86_flag, test_x86_use_flag. -// n.b. flag_enum_name and global_flag_name are both needed because we -// don't have consistent conventions for naming global flags e.g. -// EnableContended vs UseMulAddIntrinsic vs UseCRC32Intrinsics +#define AOTCODECACHE_DISABLED_MSG "AOT Code Cache disabled: it was created with %s = " -#define CHECK_FLAG(flag_type, flag_enum_name, global_flag_name) \ - if (test_ ## flag_type ## flag(flag_enum_name) != global_flag_name) { \ - log_debug(aot, codecache, init)("AOT Code Cache disabled: it was created with " # global_flag_name " = %s vs current %s" , (global_flag_name ? "false" : "true"), (global_flag_name ? "true" : "false")); \ - return false; \ - } +// Special case, print "GC = ..." to be more understandable. +inline void log_config_mismatch(CollectedHeap::Name saved, CollectedHeap::Name current, const char* name/*unused*/) { + load_failure_log().print_cr("AOT Code Cache disabled: it was created with GC = \"%s\" vs current \"%s\"", + GCConfig::hs_err_name(saved), GCConfig::hs_err_name(current)); +} -bool AOTCodeCache::Config::verify(AOTCodeCache* cache) const { - // First checks affect all cached AOT code -#ifdef ASSERT - if (!test_flag(debugVM)) { - log_debug(aot, codecache, init)("AOT Code Cache disabled: it was created by product VM, it can't be used by debug VM"); - return false; - } -#else - if (test_flag(debugVM)) { - log_debug(aot, codecache, init)("AOT Code Cache disabled: it was created by debug VM, it can't be used by product VM"); - return false; - } +inline void log_config_mismatch(bool saved, bool current, const char* name) { + load_failure_log().print_cr(AOTCODECACHE_DISABLED_MSG "%s vs current %s", name, + saved ? "true" : "false", current ? "true" : "false"); +} + +inline void log_config_mismatch(int saved, int current, const char* name) { + load_failure_log().print_cr(AOTCODECACHE_DISABLED_MSG "%d vs current %d", name, saved, current); +} + +inline void log_config_mismatch(uint saved, uint current, const char* name) { + load_failure_log().print_cr(AOTCODECACHE_DISABLED_MSG "%u vs current %u", name, saved, current); +} + +#ifdef _LP64 +inline void log_config_mismatch(intx saved, intx current, const char* name) { + load_failure_log().print_cr(AOTCODECACHE_DISABLED_MSG "%zd vs current %zd", name, saved, current); +} + +inline void log_config_mismatch(uintx saved, uintx current, const char* name) { + load_failure_log().print_cr(AOTCODECACHE_DISABLED_MSG "%zu vs current %zu", name, saved, current); +} #endif - CollectedHeap::Name aot_gc = (CollectedHeap::Name)_gc; - if (aot_gc != Universe::heap()->kind()) { - log_debug(aot, codecache, init)("AOT Code Cache disabled: it was created with different GC: %s vs current %s", GCConfig::hs_err_name(aot_gc), GCConfig::hs_err_name()); - return false; - } - - if (_compressedKlassShift != (uint)CompressedKlassPointers::shift()) { - log_debug(aot, codecache, init)("AOT Code Cache disabled: it was created with CompressedKlassPointers::shift() = %d vs current %d", _compressedKlassShift, CompressedKlassPointers::shift()); +template +bool check_config(T saved, T current, const char* name) { + if (saved != current) { + log_config_mismatch(saved, current, name); return false; + } else { + return true; } +} +bool AOTCodeCache::Config::verify(AOTCodeCache* cache) const { // check CPU features before checking flags that may be // auto-configured in response to them if (!verify_cpu_features(cache)) { return false; } - // change to EnableContended can affect validity of nmethods - CHECK_FLAG(, enableContendedPadding, EnableContended); - // change to RestrictContended can affect validity of nmethods - CHECK_FLAG(, restrictContendedPadding, RestrictContended); - // Tests for config options which might affect validity of adapters, // stubs or nmethods. Currently we take a pessemistic stand and // drop the whole cache if any of these are changed. - // change to opto alignment can affect performance of array copy - // stubs and nmethods - if (_optoLoopAlignment != (uint)OptoLoopAlignment) { - log_debug(aot, codecache, init)("AOT Code Cache disabled: it was created with OptoLoopAlignment = %d vs current %d", (int)_optoLoopAlignment, (int)OptoLoopAlignment); - return false; - } +#define AOTCODECACHE_CHECK_VAR(type, name) \ + if (!check_config(_saved_ ## name, name, #name)) { return false; } +#define AOTCODECACHE_CHECK_FUN(type, name, fun) \ + if (!check_config(_saved_ ## name, fun, #fun)) { return false; } - // change to CodeEntryAlignment can affect performance of array - // copy stubs and nmethods - if (_codeEntryAlignment != CodeEntryAlignment) { - log_debug(aot, codecache, init)("AOT Code Cache disabled: it was created with CodeEntryAlignment = %d vs current %d", _codeEntryAlignment, CodeEntryAlignment); - return false; - } + AOTCODECACHE_CONFIGS_DO(AOTCODECACHE_CHECK_VAR, AOTCODECACHE_CHECK_FUN); - // changing Prefetch configuration can affect validity of nmethods - // and stubs - if (_allocatePrefetchLines != (uint)AllocatePrefetchLines) { - log_debug(aot, codecache, init)("AOT Code Cache disabled: it was created with = %d vs current %d", (int)_allocatePrefetchLines, (int)AllocatePrefetchLines); - return false; - } - if (_allocateInstancePrefetchLines != (uint)AllocateInstancePrefetchLines) { - log_debug(aot, codecache, init)("AOT Code Cache disabled: it was created with = %d vs current %d", (int)_allocateInstancePrefetchLines, (int)AllocateInstancePrefetchLines); - return false; - } - if (_allocatePrefetchDistance != (uint)AllocatePrefetchDistance) { - log_debug(aot, codecache, init)("AOT Code Cache disabled: it was created with = %d vs current %d", (int)_allocatePrefetchDistance, (int)AllocatePrefetchDistance); - return false; - } - if (_allocatePrefetchStepSize != (uint)AllocatePrefetchStepSize) { - log_debug(aot, codecache, init)("AOT Code Cache disabled: it was created with = %d vs current %d", (int)_allocatePrefetchStepSize, (int)AllocatePrefetchStepSize); - return false; - } + // Special configs that cannot be checked with macros - // check intrinsic use settings are compatible - - CHECK_FLAG(use_, useCRC32, UseCRC32Intrinsics); - CHECK_FLAG(use_, useCRC32C, UseCRC32CIntrinsics); - -#ifdef COMPILER2 - // change to MaxVectorSize can affect validity of array copy/fill - // stubs - if (_maxVectorSize != (uint)MaxVectorSize) { - log_debug(aot, codecache, init)("AOT Code Cache disabled: it was created with MaxVectorSize = %d vs current %d", (int)_maxVectorSize, (int)MaxVectorSize); + if ((_compressedOopBase == nullptr || CompressedOops::base() == nullptr) && (_compressedOopBase != CompressedOops::base())) { + load_failure_log().print_cr("AOT Code Cache disabled: incompatible CompressedOops::base(): %p vs current %p", + _compressedOopBase, CompressedOops::base()); return false; } - // changing ArrayOperationPartialInlineSize can affect validity of - // nmethods and stubs - if (_arrayOperationPartialInlineSize != (uint)ArrayOperationPartialInlineSize) { - log_debug(aot, codecache, init)("AOT Code Cache disabled: it was created with ArrayOperationPartialInlineSize = %d vs current %d", (int)_arrayOperationPartialInlineSize, (int)ArrayOperationPartialInlineSize); - return false; - } - CHECK_FLAG(use_, useMultiplyToLen, UseMultiplyToLenIntrinsic); - CHECK_FLAG(use_, useSquareToLen, UseSquareToLenIntrinsic); - CHECK_FLAG(use_, useMulAdd, UseMulAddIntrinsic); - CHECK_FLAG(use_, useMontgomeryMultiply,UseMontgomeryMultiplyIntrinsic); - CHECK_FLAG(use_, useMontgomerySquare, UseMontgomerySquareIntrinsic); -#endif // COMPILER2 - CHECK_FLAG(use_, useChaCha20, UseChaCha20Intrinsics); - CHECK_FLAG(use_, useDilithium, UseDilithiumIntrinsics); - CHECK_FLAG(use_, useKyber, UseKyberIntrinsics); - CHECK_FLAG(use_, useBASE64, UseBASE64Intrinsics); - CHECK_FLAG(use_, useAES, UseAESIntrinsics); - CHECK_FLAG(use_, useAESCTR, UseAESCTRIntrinsics); - CHECK_FLAG(use_, useGHASH, UseGHASHIntrinsics); - CHECK_FLAG(use_, useMD5, UseMD5Intrinsics); - CHECK_FLAG(use_, useSHA1, UseSHA1Intrinsics); - CHECK_FLAG(use_, useSHA256, UseSHA256Intrinsics); - CHECK_FLAG(use_, useSHA512, UseSHA512Intrinsics); - CHECK_FLAG(use_, useSHA3, UseSHA3Intrinsics); - CHECK_FLAG(use_, usePoly1305, UsePoly1305Intrinsics); - CHECK_FLAG(use_, useVectorizedMismatch, UseVectorizedMismatchIntrinsic); - CHECK_FLAG(use_, useSecondarySupersTable, UseSecondarySupersTable); - #if defined(X86) && !defined(ZERO) - // change to AVX3Threshold may affect validity of array copy stubs - // and nmethods - if (_avx3threshold != (uint)AVX3Threshold) { - log_debug(aot, codecache, init)("AOT Code Cache disabled: it was created with AVX3Threshold = %d vs current %d", (int)_avx3threshold, AVX3Threshold); - return false; - } - - // change to UseAVX may affect validity of array copy stubs and - // nmethods - if (_useAVX != (uint)UseAVX) { - log_debug(aot, codecache, init)("AOT Code Cache disabled: it was created with useAVX = %d vs current %d", (int)_useAVX, UseAVX); - return false; - } - - // change to EnableX86ECoreOpts may affect validity of nmethods - CHECK_FLAG(x86_, x86_enableX86ECoreOpts, EnableX86ECoreOpts); - // switching off UseUnalignedLoadStores can affect validity of fill // stubs - if (test_x86_flag(x86_useUnalignedLoadStores) && !UseUnalignedLoadStores) { - log_debug(aot, codecache, init)("AOT Code Cache disabled: it was created with UseUnalignedLoadStores = true vs current = false"); + if (_useUnalignedLoadStores && !UseUnalignedLoadStores) { + log_config_mismatch(_useUnalignedLoadStores, UseUnalignedLoadStores, "UseUnalignedLoadStores"); return false; } - - // change to UseAPX can affect validity of nmethods and stubs - CHECK_FLAG(x86_, x86_useAPX, UseAPX); - - // check x86-specific intrinsic use settings are compatible - - CHECK_FLAG(x86_use_, x86_useLibm, UseLibmIntrinsic); - CHECK_FLAG(x86_use_, x86_useIntPoly, UseIntPolyIntrinsics); #endif // defined(X86) && !defined(ZERO) #if defined(AARCH64) && !defined(ZERO) - // change to PrefetchCopyIntervalInBytes may affect validity of - // array copy stubs - if (_prefetchCopyIntervalInBytes != (uint)PrefetchCopyIntervalInBytes) { - log_debug(aot, codecache, init)("AOT Code Cache disabled: it was created with PrefetchCopyIntervalInBytes = %d vs current %d", (int)_prefetchCopyIntervalInBytes, (int)PrefetchCopyIntervalInBytes); - return false; - } - - // change to BlockZeroingLowLimit may affect validity of array fill - // stubs - if (_blockZeroingLowLimit != (uint)BlockZeroingLowLimit) { - log_debug(aot, codecache, init)("AOT Code Cache disabled: it was created with BlockZeroingLowLimit = %d vs current %d", (int)_blockZeroingLowLimit, (int)BlockZeroingLowLimit); - return false; - } - - // change to SoftwarePrefetchHintDistance may affect validity of array fill - // stubs - if (_softwarePrefetchHintDistance != (uint)SoftwarePrefetchHintDistance) { - log_debug(aot, codecache, init)("AOT Code Cache disabled: it was created with SoftwarePrefetchHintDistance = %d vs current %d", (int)_softwarePrefetchHintDistance, (int)SoftwarePrefetchHintDistance); - return false; - } - - // change to UseSVE may affect validity of stubs and nmethods - if (_useSVE != (uint)UseSVE) { - log_debug(aot, codecache, init)("AOT Code Cache disabled: it was created with UseSVE = %d vs current %d",(int)_useSVE, UseSVE); - return false; - } - // switching on AvoidUnalignedAccesses may affect validity of array // copy stubs and nmethods - if (!test_aarch64_flag(aarch64_avoidUnalignedAccesses) && AvoidUnalignedAccesses) { - log_debug(aot, codecache, init)("AOT Code Cache disabled: it was created with AvoidUnalignedAccesses = false vs current = true"); + if (!_avoidUnalignedAccesses && AvoidUnalignedAccesses) { + log_config_mismatch(_avoidUnalignedAccesses, AvoidUnalignedAccesses, "AvoidUnalignedAccesses"); return false; } - - // change to UseSIMDForMemoryOps may affect validity of array - // copy stubs and nmethods - CHECK_FLAG(aarch64_, aarch64_useSIMDForMemoryOps, UseSIMDForMemoryOps); - // change to UseSIMDForArrayEquals may affect validity of array - // copy stubs and nmethods - CHECK_FLAG(aarch64_, aarch64_useSIMDForArrayEquals, UseSIMDForArrayEquals); - // change to useSIMDForSHA3 may affect validity of SHA3 stubs - CHECK_FLAG(aarch64_, aarch64_useSIMDForSHA3, UseSIMDForSHA3Intrinsic); - // change to UseLSE may affect validity of stubs and nmethods - CHECK_FLAG(aarch64_, aarch64_useLSE, UseLSE); - - // check aarch64-specific intrinsic use settings are compatible - - CHECK_FLAG(aarch64_use_, aarch64_useBlockZeroing, UseBlockZeroing); - CHECK_FLAG(aarch64_use_, aarch64_useSIMDForBigIntegerShift, UseSIMDForBigIntegerShiftIntrinsics); - CHECK_FLAG(aarch64_use_, aarch64_useSimpleArrayEquals, UseSimpleArrayEquals); - CHECK_FLAG(aarch64_use_, aarch64_useSecondarySupersCache, UseSecondarySupersCache); #endif // defined(AARCH64) && !defined(ZERO) -#if INCLUDE_JVMCI - // change to EnableJVMCI will affect validity of adapters and - // nmethods - if (_enableJVMCI != (uint)EnableJVMCI) { - log_debug(aot, codecache, init)("AOT Code Cache disabled: it was created with EnableJVMCI = %s vs current %s", (_enableJVMCI ? "true" : "false"), (EnableJVMCI ? "true" : "false")); - return false; - } -#endif // INCLUDE_JVMCI - - // The following checks do not affect AOT adapters caching - - if (test_flag(compressedOops) != UseCompressedOops) { - log_debug(aot, codecache, init)("AOT Code Cache disabled: it was created with UseCompressedOops = %s", UseCompressedOops ? "false" : "true"); - AOTStubCaching = false; - } - if (_compressedOopShift != (uint)CompressedOops::shift()) { - log_debug(aot, codecache, init)("AOT Code Cache disabled: it was created with different CompressedOops::shift(): %d vs current %d", _compressedOopShift, CompressedOops::shift()); - AOTStubCaching = false; - } - - // This should be the last check as it only disables AOTStubCaching - if ((_compressedOopBase == nullptr || CompressedOops::base() == nullptr) && (_compressedOopBase != CompressedOops::base())) { - log_debug(aot, codecache, init)("AOTStubCaching is disabled: incompatible CompressedOops::base(): %p vs current %p", _compressedOopBase, CompressedOops::base()); - AOTStubCaching = false; - } - return true; } -#undef TEST_FLAG - bool AOTCodeCache::Header::verify(uint load_size) const { if (_version != AOT_CODE_VERSION) { - log_debug(aot, codecache, init)("AOT Code Cache disabled: different AOT Code version %d vs %d recorded in AOT Code header", AOT_CODE_VERSION, _version); + load_failure_log().print_cr("AOT Code Cache disabled: different AOT Code version %d vs %d recorded in AOT Code header", AOT_CODE_VERSION, _version); return false; } if (load_size < _cache_size) { - log_debug(aot, codecache, init)("AOT Code Cache disabled: AOT Code Cache size %d < %d recorded in AOT Code header", load_size, _cache_size); + load_failure_log().print_cr("AOT Code Cache disabled: AOT Code Cache size %d < %d recorded in AOT Code header", load_size, _cache_size); return false; } return true; diff --git a/src/hotspot/share/code/aotCodeCache.hpp b/src/hotspot/share/code/aotCodeCache.hpp index 52b0adfba48..179f131c639 100644 --- a/src/hotspot/share/code/aotCodeCache.hpp +++ b/src/hotspot/share/code/aotCodeCache.hpp @@ -25,6 +25,7 @@ #ifndef SHARE_CODE_AOTCODECACHE_HPP #define SHARE_CODE_AOTCODECACHE_HPP +#include "gc/shared/collectedHeap.hpp" #include "gc/shared/gc_globals.hpp" #include "runtime/stubInfo.hpp" @@ -163,120 +164,123 @@ public: address address_for_id(int id); }; +#define AOTCODECACHE_CONFIGS_GENERIC_DO(do_var, do_fun) \ + do_var(int, AllocateInstancePrefetchLines) /* stubs and nmethods */ \ + do_var(int, AllocatePrefetchDistance) /* stubs and nmethods */ \ + do_var(int, AllocatePrefetchLines) /* stubs and nmethods */ \ + do_var(int, AllocatePrefetchStepSize) /* stubs and nmethods */ \ + do_var(uint, CodeEntryAlignment) /* array copy stubs and nmethods */ \ + do_var(bool, UseCompressedOops) /* stubs and nmethods */ \ + do_var(bool, EnableContended) /* nmethods */ \ + do_var(intx, OptoLoopAlignment) /* array copy stubs and nmethods */ \ + do_var(bool, RestrictContended) /* nmethods */ \ + do_var(bool, UseAESCTRIntrinsics) \ + do_var(bool, UseAESIntrinsics) \ + do_var(bool, UseBASE64Intrinsics) \ + do_var(bool, UseChaCha20Intrinsics) \ + do_var(bool, UseCRC32CIntrinsics) \ + do_var(bool, UseCRC32Intrinsics) \ + do_var(bool, UseDilithiumIntrinsics) \ + do_var(bool, UseGHASHIntrinsics) \ + do_var(bool, UseKyberIntrinsics) \ + do_var(bool, UseMD5Intrinsics) \ + do_var(bool, UsePoly1305Intrinsics) \ + do_var(bool, UseSecondarySupersTable) \ + do_var(bool, UseSHA1Intrinsics) \ + do_var(bool, UseSHA256Intrinsics) \ + do_var(bool, UseSHA3Intrinsics) \ + do_var(bool, UseSHA512Intrinsics) \ + do_var(bool, UseVectorizedMismatchIntrinsic) \ + do_fun(int, CompressedKlassPointers_shift, CompressedKlassPointers::shift()) \ + do_fun(int, CompressedOops_shift, CompressedOops::shift()) \ + do_fun(bool, JavaAssertions_systemClassDefault, JavaAssertions::systemClassDefault()) \ + do_fun(bool, JavaAssertions_userClassDefault, JavaAssertions::userClassDefault()) \ + do_fun(CollectedHeap::Name, Universe_heap_kind, Universe::heap()->kind()) \ + // END + +#ifdef COMPILER2 +#define AOTCODECACHE_CONFIGS_COMPILER2_DO(do_var, do_fun) \ + do_var(intx, ArrayOperationPartialInlineSize) /* array copy stubs and nmethods */ \ + do_var(intx, MaxVectorSize) /* array copy/fill stubs */ \ + do_var(bool, UseMontgomeryMultiplyIntrinsic) \ + do_var(bool, UseMontgomerySquareIntrinsic) \ + do_var(bool, UseMulAddIntrinsic) \ + do_var(bool, UseMultiplyToLenIntrinsic) \ + do_var(bool, UseSquareToLenIntrinsic) \ + // END +#else +#define AOTCODECACHE_CONFIGS_COMPILER2_DO(do_var, do_fun) +#endif + +#if INCLUDE_JVMCI +#define AOTCODECACHE_CONFIGS_JVMCI_DO(do_var, do_fun) \ + do_var(bool, EnableJVMCI) /* adapters and nmethods */ \ + // END +#else +#define AOTCODECACHE_CONFIGS_JVMCI_DO(do_var, do_fun) +#endif + +#if defined(AARCH64) && !defined(ZERO) +#define AOTCODECACHE_CONFIGS_AARCH64_DO(do_var, do_fun) \ + do_var(intx, BlockZeroingLowLimit) /* array fill stubs */ \ + do_var(intx, PrefetchCopyIntervalInBytes) /* array copy stubs */ \ + do_var(int, SoftwarePrefetchHintDistance) /* array fill stubs */ \ + do_var(bool, UseBlockZeroing) \ + do_var(bool, UseLSE) /* stubs and nmethods */ \ + do_var(uint, UseSVE) /* stubs and nmethods */ \ + do_var(bool, UseSecondarySupersCache) \ + do_var(bool, UseSIMDForArrayEquals) /* array copy stubs and nmethods */ \ + do_var(bool, UseSIMDForBigIntegerShiftIntrinsics) \ + do_var(bool, UseSIMDForMemoryOps) /* array copy stubs and nmethods */ \ + do_var(bool, UseSIMDForSHA3Intrinsic) /* SHA3 stubs */ \ + do_var(bool, UseSimpleArrayEquals) \ + // END +#else +#define AOTCODECACHE_CONFIGS_AARCH64_DO(do_var, do_fun) +#endif + +#if defined(X86) && !defined(ZERO) +#define AOTCODECACHE_CONFIGS_X86_DO(do_var, do_fun) \ + do_var(int, AVX3Threshold) /* array copy stubs and nmethods */ \ + do_var(bool, EnableX86ECoreOpts) /* nmethods */ \ + do_var(int, UseAVX) /* array copy stubs and nmethods */ \ + do_var(bool, UseAPX) /* nmethods and stubs */ \ + do_var(bool, UseLibmIntrinsic) \ + do_var(bool, UseIntPolyIntrinsics) \ + // END +#else +#define AOTCODECACHE_CONFIGS_X86_DO(do_var, do_fun) +#endif + +#define AOTCODECACHE_CONFIGS_DO(do_var, do_fun) \ + AOTCODECACHE_CONFIGS_GENERIC_DO(do_var, do_fun) \ + AOTCODECACHE_CONFIGS_COMPILER2_DO(do_var, do_fun) \ + AOTCODECACHE_CONFIGS_JVMCI_DO(do_var, do_fun) \ + AOTCODECACHE_CONFIGS_AARCH64_DO(do_var, do_fun) \ + AOTCODECACHE_CONFIGS_X86_DO(do_var, do_fun) \ + // END + +#define AOTCODECACHE_DECLARE_VAR(type, name) type _saved_ ## name; +#define AOTCODECACHE_DECLARE_FUN(type, name, func) type _saved_ ## name; + class AOTCodeCache : public CHeapObj { // Classes used to describe AOT code cache. protected: class Config { + AOTCODECACHE_CONFIGS_DO(AOTCODECACHE_DECLARE_VAR, AOTCODECACHE_DECLARE_FUN) + + // Special configs that cannot be checked with macros address _compressedOopBase; - uint _compressedOopShift; - uint _compressedKlassShift; - uint _contendedPaddingWidth; - uint _gc; - uint _optoLoopAlignment; - uint _codeEntryAlignment; - uint _allocatePrefetchLines; - uint _allocateInstancePrefetchLines; - uint _allocatePrefetchDistance; - uint _allocatePrefetchStepSize; -#ifdef COMPILER2 - uint _maxVectorSize; - uint _arrayOperationPartialInlineSize; -#endif // COMPILER2 - enum Flags { - none = 0, - debugVM = 1, - compressedOops = 2, - useTLAB = 4, - systemClassAssertions = 8, - userClassAssertions = 16, - enableContendedPadding = 32, - restrictContendedPadding = 64 - }; - uint _flags; - enum IntrinsicsUseFlags { - use_none = 0, - useCRC32 = 1 << 0, - useCRC32C = 1 << 1, - useMultiplyToLen = 1 << 2, - useSquareToLen = 1 << 3, - useMulAdd = 1 << 4, - useMontgomeryMultiply = 1 << 5, - useMontgomerySquare = 1 << 6, - useChaCha20 = 1 << 7, - useDilithium = 1 << 8, - useKyber = 1 << 9, - useBASE64 = 1 << 10, - useAdler32 = 1 << 11, - useAES = 1 << 12, - useAESCTR = 1 << 13, - useGHASH = 1 << 14, - useMD5 = 1 << 15, - useSHA1 = 1 << 16, - useSHA256 = 1 << 17, - useSHA512 = 1 << 18, - useSHA3 = 1 << 19, - usePoly1305 = 1 << 20, - useVectorizedMismatch = 1 << 21, - useSecondarySupersTable = 1 << 22, - }; - uint _use_intrinsics_flags; - bool test_flag(enum Flags flag) const { return (_flags & flag) != 0; } - bool test_use_flag(enum IntrinsicsUseFlags flag) const { return (_use_intrinsics_flags & flag) != 0; } - void set_flag(enum Flags flag) { _flags |= flag; } - void set_use_flag(enum IntrinsicsUseFlags flag) { _use_intrinsics_flags |= flag; } + #if defined(X86) && !defined(ZERO) - uint _avx3threshold; - uint _useAVX; - enum X86Flags { - x86_none = 0, - x86_enableX86ECoreOpts = 1, - x86_useUnalignedLoadStores = 2, - x86_useAPX = 4 - }; - uint _x86_flags; - enum X86IntrinsicsUseFlags { - x86_use_none = 0, - x86_useLibm = 1 << 1, - x86_useIntPoly = 1 << 2, - }; - uint _x86_use_intrinsics_flags; - bool test_x86_flag(enum X86Flags flag) const { return (_x86_flags & flag) != 0; } - bool test_x86_use_flag(enum X86IntrinsicsUseFlags flag) const { return (_x86_use_intrinsics_flags & flag) != 0; } - void set_x86_flag(enum X86Flags flag) { _x86_flags |= flag; } - void set_x86_use_flag(enum X86IntrinsicsUseFlags flag) { _x86_use_intrinsics_flags |= flag; } -#endif // defined(X86) && !defined(ZERO) + bool _useUnalignedLoadStores; +#endif + #if defined(AARCH64) && !defined(ZERO) - // this is global but x86 does not use it and aarch64 does - uint _prefetchCopyIntervalInBytes; - uint _blockZeroingLowLimit; - uint _softwarePrefetchHintDistance; - uint _useSVE; - enum AArch64Flags { - aarch64_none = 0, - aarch64_avoidUnalignedAccesses = 1, - aarch64_useSIMDForMemoryOps = 2, - aarch64_useSIMDForArrayEquals = 4, - aarch64_useSIMDForSHA3 = 8, - aarch64_useLSE = 16, - }; - uint _aarch64_flags; - enum AArch64IntrinsicsUseFlags { - aarch64_use_none = 0, - aarch64_useBlockZeroing = 1 << 0, - aarch64_useSIMDForBigIntegerShift = 1 << 1, - aarch64_useSimpleArrayEquals = 1 << 2, - aarch64_useSecondarySupersCache = 1 << 3, - }; - uint _aarch64_use_intrinsics_flags; - bool test_aarch64_flag(enum AArch64Flags flag) const { return (_aarch64_flags & flag) != 0; } - bool test_aarch64_use_flag(enum AArch64IntrinsicsUseFlags flag) const { return (_aarch64_use_intrinsics_flags & flag) != 0; } - void set_aarch64_flag(enum AArch64Flags flag) { _aarch64_flags |= flag; } - void set_aarch64_use_flag(enum AArch64IntrinsicsUseFlags flag) { _aarch64_use_intrinsics_flags |= flag; } -#endif // defined(AARCH64) && !defined(ZERO) -#if INCLUDE_JVMCI - uint _enableJVMCI; -#endif // INCLUDE_JVMCI + bool _avoidUnalignedAccesses; +#endif + uint _cpu_features_offset; // offset in the cache where cpu features are stored public: void record(uint cpu_features_offset); diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeCompressedOopsTest.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeCompressedOopsTest.java index 09290960d2f..3b9458c14da 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeCompressedOopsTest.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeCompressedOopsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -201,12 +201,18 @@ public class AOTCodeCompressedOopsTest { if (aotCacheShift == -1 || currentShift == -1 || aotCacheBase == -1 || currentBase == -1) { throw new RuntimeException("Failed to find CompressedOops settings"); } + + // Changes in compressed oop encoding could randomly affect flags like AllocatePrefetchDistance + // due to the OS-assigned range of the Java heap. If that happens, the exact error message may vary + String disabledMsg = "AOT Code Cache disabled:"; if (aotCacheShift != currentShift) { - out.shouldContain("AOT Code Cache disabled: it was created with different CompressedOops::shift()"); + out.shouldContain(disabledMsg); } else if ((aotCacheBase == 0 || currentBase == 0) && (aotCacheBase != currentBase)) { - out.shouldContain("AOTStubCaching is disabled: incompatible CompressedOops::base()"); + out.shouldContain(disabledMsg); } else { - out.shouldMatch("Read \\d+ entries table at offset \\d+ from AOT Code Cache"); + if (!out.contains(disabledMsg)) { + out.shouldMatch("Read \\d+ entries table at offset \\d+ from AOT Code Cache"); + } } } } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/methodHandles/JDKMethodHandlesTestRunner.java b/test/hotspot/jtreg/runtime/cds/appcds/methodHandles/JDKMethodHandlesTestRunner.java index 19ab392c036..d9e1b15602c 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/methodHandles/JDKMethodHandlesTestRunner.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/methodHandles/JDKMethodHandlesTestRunner.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -91,7 +91,7 @@ public class JDKMethodHandlesTestRunner { public void checkExecution(OutputAnalyzer out, RunMode runMode) throws Exception { out.shouldHaveExitValue(0); if (runMode.isProductionRun()) { - out.shouldMatch(".class.load. test.java.lang.invoke." + testClassName + + out.shouldMatch(".class.load.* test.java.lang.invoke." + testClassName + "[$][$]Lambda.*/0x.*source:.*shared.*objects.*file"); } } From 4253db22526da9997f3b0140995cac09c41aeb22 Mon Sep 17 00:00:00 2001 From: Dean Long Date: Fri, 3 Apr 2026 04:08:21 +0000 Subject: [PATCH 167/359] 8350208: CTW: GraphKit::add_safepoint_edges asserts "not enough operands for reexecution" Co-authored-by: Quan Anh Mai Reviewed-by: mhaessig, vlivanov --- src/hotspot/share/opto/doCall.cpp | 15 +-- src/hotspot/share/opto/parse.hpp | 6 +- src/hotspot/share/opto/parse1.cpp | 11 +- .../TestDebugDuringExceptionCatching.java | 126 ++++++++++++++++++ .../lang/invoke/lib/InstructionHelper.java | 25 +++- 5 files changed, 166 insertions(+), 17 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/exceptions/TestDebugDuringExceptionCatching.java diff --git a/src/hotspot/share/opto/doCall.cpp b/src/hotspot/share/opto/doCall.cpp index e4418631d17..9a1da726f00 100644 --- a/src/hotspot/share/opto/doCall.cpp +++ b/src/hotspot/share/opto/doCall.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2026, Oracle and/or its affiliates. All rights reserved. * 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 "opto/callGenerator.hpp" #include "opto/castnode.hpp" #include "opto/cfgnode.hpp" +#include "opto/graphKit.hpp" #include "opto/mulnode.hpp" #include "opto/parse.hpp" #include "opto/rootnode.hpp" @@ -909,8 +910,7 @@ void Parse::catch_call_exceptions(ciExceptionHandlerStream& handlers) { if (handler_bci < 0) { // merge with corresponding rethrow node throw_to_exit(make_exception_state(ex_oop)); } else { // Else jump to corresponding handle - push_ex_oop(ex_oop); // Clear stack and push just the oop. - merge_exception(handler_bci); + push_and_merge_exception(handler_bci, ex_oop); } } @@ -1008,13 +1008,10 @@ void Parse::catch_inline_exceptions(SafePointNode* ex_map) { int handler_bci = handler->handler_bci(); if (remaining == 1) { - push_ex_oop(ex_node); // Push exception oop for handler if (PrintOpto && WizardMode) { tty->print_cr(" Catching every inline exception bci:%d -> handler_bci:%d", bci(), handler_bci); } - // If this is a backwards branch in the bytecodes, add safepoint - maybe_add_safepoint(handler_bci); - merge_exception(handler_bci); // jump to handler + push_and_merge_exception(handler_bci, ex_node); // jump to handler return; // No more handling to be done here! } @@ -1039,15 +1036,13 @@ void Parse::catch_inline_exceptions(SafePointNode* ex_map) { const TypeInstPtr* tinst = TypeOopPtr::make_from_klass_unique(klass)->cast_to_ptr_type(TypePtr::NotNull)->is_instptr(); assert(klass->has_subklass() || tinst->klass_is_exact(), "lost exactness"); Node* ex_oop = _gvn.transform(new CheckCastPPNode(control(), ex_node, tinst)); - push_ex_oop(ex_oop); // Push exception oop for handler if (PrintOpto && WizardMode) { tty->print(" Catching inline exception bci:%d -> handler_bci:%d -- ", bci(), handler_bci); klass->print_name(); tty->cr(); } // If this is a backwards branch in the bytecodes, add safepoint - maybe_add_safepoint(handler_bci); - merge_exception(handler_bci); + push_and_merge_exception(handler_bci, ex_oop); } set_control(not_subtype_ctrl); diff --git a/src/hotspot/share/opto/parse.hpp b/src/hotspot/share/opto/parse.hpp index 397a7796f88..42f44f0f7ea 100644 --- a/src/hotspot/share/opto/parse.hpp +++ b/src/hotspot/share/opto/parse.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -474,8 +474,8 @@ class Parse : public GraphKit { void merge( int target_bci); // Same as plain merge, except that it allocates a new path number. void merge_new_path( int target_bci); - // Merge the current mapping into an exception handler. - void merge_exception(int target_bci); + // Push the exception oop and merge the current mapping into an exception handler. + void push_and_merge_exception(int target_bci, Node* ex_oop); // Helper: Merge the current mapping into the given basic block void merge_common(Block* target, int pnum); // Helper functions for merging individual cells. diff --git a/src/hotspot/share/opto/parse1.cpp b/src/hotspot/share/opto/parse1.cpp index 647e8515b30..683633f6355 100644 --- a/src/hotspot/share/opto/parse1.cpp +++ b/src/hotspot/share/opto/parse1.cpp @@ -1651,9 +1651,14 @@ void Parse::merge_new_path(int target_bci) { } //-------------------------merge_exception------------------------------------- -// Merge the current mapping into the basic block starting at bci -// The ex_oop must be pushed on the stack, unlike throw_to_exit. -void Parse::merge_exception(int target_bci) { +// Push the given ex_oop onto the stack, then merge the current mapping into +// the basic block starting at target_bci. +void Parse::push_and_merge_exception(int target_bci, Node* ex_oop) { + // Add the safepoint before trimming the stack and pushing the exception oop. + // We could add the safepoint after, but then the bci would also need to be + // advanced to target_bci first, so the stack state matches. + maybe_add_safepoint(target_bci); + push_ex_oop(ex_oop); // Push exception oop for handler #ifdef ASSERT if (target_bci <= bci()) { C->set_exception_backedge(); diff --git a/test/hotspot/jtreg/compiler/exceptions/TestDebugDuringExceptionCatching.java b/test/hotspot/jtreg/compiler/exceptions/TestDebugDuringExceptionCatching.java new file mode 100644 index 00000000000..999c73fb73a --- /dev/null +++ b/test/hotspot/jtreg/compiler/exceptions/TestDebugDuringExceptionCatching.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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.exceptions; + +import compiler.lib.ir_framework.Run; +import compiler.lib.ir_framework.Test; +import compiler.lib.ir_framework.TestFramework; + +import java.lang.classfile.Label; +import java.lang.constant.ClassDesc; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; + +import jdk.test.lib.Asserts; +import test.java.lang.invoke.lib.InstructionHelper; + +/** + * @test + * @bug 8350208 + * @summary Safepoints added during the processing of exception handlers should never reexecute + * @library /test/lib /test/jdk/java/lang/invoke/common / + * @build test.java.lang.invoke.lib.InstructionHelper + * + * @run main/othervm ${test.main.class} + */ +public class TestDebugDuringExceptionCatching { + + public static class V { + int v; + } + + static final int ITERATIONS = 100; + static final RuntimeException EXCEPTION = new RuntimeException(); + + /** + * Construct something that looks like this: + *
{@code
+     * int snippet(V v) {
+     *     int i = 0;
+     *     LoopHead: {
+     *         if (i >= 100) {
+     *             goto LoopEnd;
+     *         }
+     *         i++;
+     *         try {
+     *             v.v = 1;
+     *         } catch (Throwable) {
+     *             // Not really, the LoopHead is the exception Handler
+     *             goto LoopHead;
+     *         }
+     *     }
+     *     LoopEnd:
+     *     return i;
+     * }
+     * }
+ */ + static final MethodHandle SNIPPET_HANDLE; + static final ClassDesc CLASS_DESC = TestDebugDuringExceptionCatching.class.describeConstable().get(); + static { + SNIPPET_HANDLE = InstructionHelper.buildMethodHandle(MethodHandles.lookup(), + "snippet", + MethodType.methodType(int.class, V.class), + CODE -> { + Label loopHead = CODE.newLabel(); + Label loopEnd = CODE.newLabel(); + Label tryStart = CODE.newLabel(); + Label tryEnd = CODE.newLabel(); + CODE. + iconst_0(). + istore(1). + // The loop head should have a RuntimeException as the sole element on the stack + getstatic(CLASS_DESC, "EXCEPTION", RuntimeException.class.describeConstable().get()). + labelBinding(loopHead). + pop(). + iload(1). + ldc(ITERATIONS). + if_icmpge(loopEnd). + iinc(1, 1). + aload(0). + iconst_1(). + labelBinding(tryStart). + putfield(V.class.describeConstable().get(), "v", int.class.describeConstable().get()). + labelBinding(tryEnd). + // The stack is empty here + labelBinding(loopEnd). + iload(1). + ireturn(); + CODE.exceptionCatchAll(tryStart, tryEnd, loopHead); + }); + } + + @Test + private static int testBackwardHandler(V v) throws Throwable { + return (int) SNIPPET_HANDLE.invokeExact(v); + } + + @Run(test = "testBackwardHandler") + public void run() throws Throwable { + Asserts.assertEQ(ITERATIONS, testBackwardHandler(null)); + } + + public static void main(String[] args) { + TestFramework.run(); + } +} diff --git a/test/jdk/java/lang/invoke/common/test/java/lang/invoke/lib/InstructionHelper.java b/test/jdk/java/lang/invoke/common/test/java/lang/invoke/lib/InstructionHelper.java index 123cccd53e7..c7185f691b2 100644 --- a/test/jdk/java/lang/invoke/common/test/java/lang/invoke/lib/InstructionHelper.java +++ b/test/jdk/java/lang/invoke/common/test/java/lang/invoke/lib/InstructionHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2026, Oracle and/or its affiliates. All rights reserved. * 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 test.java.lang.invoke.lib; import java.lang.classfile.ClassBuilder; import java.lang.classfile.ClassFile; +import java.lang.classfile.CodeBuilder; import java.lang.classfile.TypeKind; import java.lang.constant.*; @@ -32,6 +33,7 @@ import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Consumer; import static java.lang.invoke.MethodType.fromMethodDescriptorString; @@ -135,4 +137,25 @@ public class InstructionHelper { String classDescStr = sb.insert(sb.length() - 1, suffix).toString(); return ClassDesc.ofDescriptor(classDescStr); } + + public static MethodHandle buildMethodHandle(MethodHandles.Lookup l, String methodName, MethodType methodType, Consumer builder) { + ClassDesc genClassDesc = classDesc(l.lookupClass(), "$Code_" + COUNT.getAndIncrement()); + return buildMethodHandle(l, genClassDesc, methodName, methodType, builder); + } + + private static MethodHandle buildMethodHandle(MethodHandles.Lookup l, ClassDesc classDesc, String methodName, MethodType methodType, Consumer builder) { + try { + byte[] bytes = ClassFile.of().build(classDesc, classBuilder -> { + classBuilder.withMethod(methodName, + MethodTypeDesc.ofDescriptor(methodType.toMethodDescriptorString()), + ClassFile.ACC_PUBLIC + ClassFile.ACC_STATIC, + methodBuilder -> methodBuilder.withCode(builder)); + }); + Class clazz = l.defineClass(bytes); + return l.findStatic(clazz, methodName, methodType); + } catch (Throwable t) { + t.printStackTrace(); + throw new RuntimeException("Failed to buildMethodHandle: " + methodName + " type " + methodType); + } + } } From 4bb7204fa91cc86daca35f816265e2258bd95a7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Jeli=C5=84ski?= Date: Fri, 3 Apr 2026 05:48:24 +0000 Subject: [PATCH 168/359] 8377181: HttpClient may leak closed QUIC connection objects Reviewed-by: dfuchs --- .../http/quic/ConnectionTerminatorImpl.java | 8 +++++- .../net/http/quic/PeerConnIdManager.java | 25 ++++++++++++++++--- .../net/http/quic/QuicConnectionImpl.java | 4 +++ .../internal/net/http/quic/QuicEndpoint.java | 12 +++++---- .../net/httpclient/CancelRequestTest.java | 2 +- .../httpclient/http3/H3ErrorHandlingTest.java | 2 +- 6 files changed, 41 insertions(+), 12 deletions(-) diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/quic/ConnectionTerminatorImpl.java b/src/java.net.http/share/classes/jdk/internal/net/http/quic/ConnectionTerminatorImpl.java index 5e2384dce27..3fc013b4fde 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/quic/ConnectionTerminatorImpl.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/quic/ConnectionTerminatorImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -203,6 +203,9 @@ final class ConnectionTerminatorImpl implements ConnectionTerminator { // an endpoint has been established (which is OK) return; } + // close the connection ID managers; any in-flight connection ID changes should be ignored. + connection.localConnectionIdManager().close(); + connection.peerConnectionIdManager().close(); endpoint.removeConnection(this.connection); } @@ -434,6 +437,9 @@ final class ConnectionTerminatorImpl implements ConnectionTerminator { final QuicPacket packet = connection.newQuicPacket(keySpace, List.of(toSend)); final ProtectionRecord protectionRecord = ProtectionRecord.single(packet, connection::allocateDatagramForEncryption); + // close the connection ID managers; any in-flight connection ID changes should be ignored. + connection.localConnectionIdManager().close(); + connection.peerConnectionIdManager().close(); // while sending the packet containing the CONNECTION_CLOSE frame, the pushDatagram will // remap the QuicConnectionImpl in QuicEndpoint. connection.pushDatagram(protectionRecord); diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/quic/PeerConnIdManager.java b/src/java.net.http/share/classes/jdk/internal/net/http/quic/PeerConnIdManager.java index 2bc759a920a..0646026e28b 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/quic/PeerConnIdManager.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/quic/PeerConnIdManager.java @@ -65,6 +65,7 @@ final class PeerConnIdManager { private final QuicConnectionImpl connection; private final String logTag; private final boolean isClient; + private boolean closed; // when true, no more reset tokens are registered private enum State { INITIAL_PKT_NOT_RECEIVED_FROM_PEER, @@ -267,6 +268,7 @@ final class PeerConnIdManager { if (handshakeConnId == null) { throw new IllegalStateException("No handshake peer connection available"); } + if (closed) return; // recreate the conn id with the stateless token this.peerConnectionIds.put(0L, new PeerConnectionId(handshakeConnId.asReadOnlyBuffer(), statelessResetToken)); @@ -283,6 +285,10 @@ final class PeerConnIdManager { public List activeResetTokens() { lock.lock(); try { + // this method is currently only used to remove a connection from the endpoint + // after the connection is closed. + // The below assert can be removed if the method is needed elsewhere. + assert closed; // we only support one active connection ID at the time PeerConnectionId cid = peerConnectionIds.get(activeConnIdSeq); byte[] statelessResetToken = null; @@ -305,7 +311,7 @@ final class PeerConnIdManager { QuicConnectionId getPeerConnId() { lock.lock(); try { - if (activeConnIdSeq < largestReceivedRetirePriorTo) { + if (activeConnIdSeq < largestReceivedRetirePriorTo && !closed) { // stop using the old connection ID switchConnectionId(); } @@ -496,9 +502,11 @@ final class PeerConnIdManager { // connection ids. It does however store the peer-issued stateless reset token of a // peer connection id, so we let the endpoint know that the stateless reset token needs // to be forgotten since the corresponding peer connection id is being retired - final byte[] resetTokenToForget = entry.getValue().getStatelessResetToken(); - if (resetTokenToForget != null) { - this.connection.endpoint().forgetStatelessResetToken(resetTokenToForget); + if (seqNumToRetire == activeConnIdSeq) { + final byte[] resetTokenToForget = entry.getValue().getStatelessResetToken(); + if (resetTokenToForget != null) { + this.connection.endpoint().forgetStatelessResetToken(resetTokenToForget); + } } } for (Iterator iterator = gaps.iterator(); iterator.hasNext(); ) { @@ -540,4 +548,13 @@ final class PeerConnIdManager { lock.unlock(); } } + + public void close() { + lock.lock(); + try { + closed = true; + } finally { + lock.unlock(); + } + } } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicConnectionImpl.java b/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicConnectionImpl.java index 41b814a551c..b13d49ead7d 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicConnectionImpl.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicConnectionImpl.java @@ -1758,6 +1758,10 @@ public class QuicConnectionImpl extends QuicConnection implements QuicPacketRece return localConnIdManager; } + PeerConnIdManager peerConnectionIdManager() { + return peerConnIdManager; + } + /** * {@return the local connection id} */ diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicEndpoint.java b/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicEndpoint.java index ef342d4cb56..3dee814e1f1 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicEndpoint.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/quic/QuicEndpoint.java @@ -1532,12 +1532,16 @@ public abstract sealed class QuicEndpoint implements AutoCloseable */ void removeConnection(final QuicPacketReceiver connection) { if (debug.on()) debug.log("removing connection " + connection); - // remove the connection completely - connection.connectionIds().forEach(connections::remove); - assert !connections.containsValue(connection) : connection; // remove references to this connection from the map which holds the peer issued // reset tokens dropPeerIssuedResetTokensFor(connection); + // remove the connection completely + connection.connectionIds().forEach(connections::remove); + assert !connections.containsValue(connection) : connection; + // Check that if there are no connections, there are no reset tokens either. + // This is safe because connections are added before reset tokens and removed after, + // except when we're closing the endpoint and don't bother with removing tokens. + assert peerIssuedResetTokens.isEmpty() || !connections.isEmpty() || closed : peerIssuedResetTokens; } /** @@ -1587,7 +1591,6 @@ public abstract sealed class QuicEndpoint implements AutoCloseable if (closed) return; final long idleTimeout = connection.peerPtoMs() * 3; // 3 PTO - connection.localConnectionIdManager().close(); DrainingConnection draining = new DrainingConnection(connection.connectionIds(), connection.activeResetTokens(), idleTimeout); // we can ignore stateless reset in the draining state. @@ -1626,7 +1629,6 @@ public abstract sealed class QuicEndpoint implements AutoCloseable closingDatagram.flip(); final long idleTimeout = connection.peerPtoMs() * 3; // 3 PTO - connection.localConnectionIdManager().close(); var closingConnection = new ClosingConnection(connection.connectionIds(), connection.activeResetTokens(), idleTimeout, datagram); remapPeerIssuedResetToken(closingConnection); diff --git a/test/jdk/java/net/httpclient/CancelRequestTest.java b/test/jdk/java/net/httpclient/CancelRequestTest.java index df808ad2dab..dcb60a55061 100644 --- a/test/jdk/java/net/httpclient/CancelRequestTest.java +++ b/test/jdk/java/net/httpclient/CancelRequestTest.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8245462 8229822 8254786 8297075 8297149 8298340 8302635 + * @bug 8245462 8229822 8254786 8297075 8297149 8298340 8302635 8377181 * @summary Tests cancelling the request. * @library /test/lib /test/jdk/java/net/httpclient/lib * @key randomness diff --git a/test/jdk/java/net/httpclient/http3/H3ErrorHandlingTest.java b/test/jdk/java/net/httpclient/http3/H3ErrorHandlingTest.java index 8dfef7417e3..8e20eac95fa 100644 --- a/test/jdk/java/net/httpclient/http3/H3ErrorHandlingTest.java +++ b/test/jdk/java/net/httpclient/http3/H3ErrorHandlingTest.java @@ -71,7 +71,7 @@ import static org.junit.jupiter.api.Assertions.*; /* * @test - * @bug 8373409 + * @bug 8373409 8377181 * @key intermittent * @comment testResetControlStream may fail if the client doesn't read the stream type * before the stream is reset, From f8ca6f6f09908c5106d262cfaaf82e88f37e9a32 Mon Sep 17 00:00:00 2001 From: Dingli Zhang Date: Fri, 3 Apr 2026 06:15:19 +0000 Subject: [PATCH 169/359] 8381554: RISC-V: Small refactoring for cmp_klass_compressed macro-assembler routine Reviewed-by: fyang, gcao, wenanjian --- .../riscv/c1_LIRAssembler_arraycopy_riscv.cpp | 52 ++++++++----------- .../riscv/c1_LIRAssembler_arraycopy_riscv.hpp | 3 +- .../cpu/riscv/macroAssembler_riscv.cpp | 25 ++++++--- .../cpu/riscv/macroAssembler_riscv.hpp | 9 +++- 4 files changed, 49 insertions(+), 40 deletions(-) diff --git a/src/hotspot/cpu/riscv/c1_LIRAssembler_arraycopy_riscv.cpp b/src/hotspot/cpu/riscv/c1_LIRAssembler_arraycopy_riscv.cpp index 58eb1a55553..8aced227a06 100644 --- a/src/hotspot/cpu/riscv/c1_LIRAssembler_arraycopy_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_LIRAssembler_arraycopy_riscv.cpp @@ -240,35 +240,6 @@ void LIR_Assembler::arraycopy_type_check(Register src, Register src_pos, Registe } } -void LIR_Assembler::arraycopy_assert(Register src, Register dst, Register tmp, ciArrayKlass *default_type, int flags) { - assert(default_type != nullptr, "null default_type!"); - BasicType basic_type = default_type->element_type()->basic_type(); - if (basic_type == T_ARRAY) { basic_type = T_OBJECT; } - if (basic_type != T_OBJECT || !(flags & LIR_OpArrayCopy::type_check)) { - // Sanity check the known type with the incoming class. For the - // primitive case the types must match exactly with src.klass and - // dst.klass each exactly matching the default type. For the - // object array case, if no type check is needed then either the - // dst type is exactly the expected type and the src type is a - // subtype which we can't check or src is the same array as dst - // but not necessarily exactly of type default_type. - Label known_ok, halt; - __ mov_metadata(tmp, default_type->constant_encoding()); - __ encode_klass_not_null(tmp); - - if (basic_type != T_OBJECT) { - __ cmp_klass_compressed(dst, tmp, t0, halt, false); - __ cmp_klass_compressed(src, tmp, t0, known_ok, true); - } else { - __ cmp_klass_compressed(dst, tmp, t0, known_ok, true); - __ beq(src, dst, known_ok); - } - __ bind(halt); - __ stop("incorrect type information in arraycopy"); - __ bind(known_ok); - } -} - void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) { ciArrayKlass *default_type = op->expected_type(); Register src = op->src()->as_register(); @@ -299,7 +270,28 @@ void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) { } #ifdef ASSERT - arraycopy_assert(src, dst, tmp, default_type, flags); + if (basic_type != T_OBJECT || !(flags & LIR_OpArrayCopy::type_check)) { + // Sanity check the known type with the incoming class. For the + // primitive case the types must match exactly with src.klass and + // dst.klass each exactly matching the default type. For the + // object array case, if no type check is needed then either the + // dst type is exactly the expected type and the src type is a + // subtype which we can't check or src is the same array as dst + // but not necessarily exactly of type default_type. + Label known_ok, halt; + __ mov_metadata(tmp, default_type->constant_encoding()); + + if (basic_type != T_OBJECT) { + __ cmp_klass_bne(dst, tmp, t0, t1, halt); + __ cmp_klass_beq(src, tmp, t0, t1, known_ok); + } else { + __ cmp_klass_beq(dst, tmp, t0, t1, known_ok); + __ beq(src, dst, known_ok); + } + __ bind(halt); + __ stop("incorrect type information in arraycopy"); + __ bind(known_ok); + } #endif #ifndef PRODUCT diff --git a/src/hotspot/cpu/riscv/c1_LIRAssembler_arraycopy_riscv.hpp b/src/hotspot/cpu/riscv/c1_LIRAssembler_arraycopy_riscv.hpp index 06a0f248ca6..b5452f3e4cd 100644 --- a/src/hotspot/cpu/riscv/c1_LIRAssembler_arraycopy_riscv.hpp +++ b/src/hotspot/cpu/riscv/c1_LIRAssembler_arraycopy_riscv.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, 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. * @@ -39,7 +39,6 @@ void arraycopy_type_check(Register src, Register src_pos, Register length, Register dst, Register dst_pos, Register tmp, CodeStub *stub, BasicType basic_type, int flags); - void arraycopy_assert(Register src, Register dst, Register tmp, ciArrayKlass *default_type, int flags); void arraycopy_prepare_params(Register src, Register src_pos, Register length, Register dst, Register dst_pos, BasicType basic_type); void arraycopy_checkcast_prepare_params(Register src, Register src_pos, Register length, diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index b0305fa2977..d031161db87 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -3511,17 +3511,30 @@ void MacroAssembler::orptr(Address adr, RegisterOrConstant src, Register tmp1, R sd(tmp1, adr); } -void MacroAssembler::cmp_klass_compressed(Register oop, Register trial_klass, Register tmp, Label &L, bool equal) { +void MacroAssembler::cmp_klass_beq(Register obj, Register klass, + Register tmp1, Register tmp2, + Label &L, bool is_far) { + assert_different_registers(obj, klass, tmp1, tmp2); if (UseCompactObjectHeaders) { - load_narrow_klass_compact(tmp, oop); + load_narrow_klass_compact(tmp1, obj); } else { - lwu(tmp, Address(oop, oopDesc::klass_offset_in_bytes())); + lwu(tmp1, Address(obj, oopDesc::klass_offset_in_bytes())); } - if (equal) { - beq(trial_klass, tmp, L); + decode_klass_not_null(tmp1, tmp2); + beq(klass, tmp1, L, is_far); +} + +void MacroAssembler::cmp_klass_bne(Register obj, Register klass, + Register tmp1, Register tmp2, + Label &L, bool is_far) { + assert_different_registers(obj, klass, tmp1, tmp2); + if (UseCompactObjectHeaders) { + load_narrow_klass_compact(tmp1, obj); } else { - bne(trial_klass, tmp, L); + lwu(tmp1, Address(obj, oopDesc::klass_offset_in_bytes())); } + decode_klass_not_null(tmp1, tmp2); + bne(klass, tmp1, L, is_far); } // Move an oop into a register. diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp index f5e985c28a2..95821c29eec 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved. * Copyright (c) 2020, 2024, Huawei Technologies Co., Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -198,7 +198,12 @@ class MacroAssembler: public Assembler { void load_klass(Register dst, Register src, Register tmp = t0); void load_narrow_klass_compact(Register dst, Register src); void store_klass(Register dst, Register src, Register tmp = t0); - void cmp_klass_compressed(Register oop, Register trial_klass, Register tmp, Label &L, bool equal); + void cmp_klass_beq(Register obj, Register klass, + Register tmp1, Register tmp2, + Label &L, bool is_far = false); + void cmp_klass_bne(Register obj, Register klass, + Register tmp1, Register tmp2, + Label &L, bool is_far = false); void encode_klass_not_null(Register r, Register tmp = t0); void decode_klass_not_null(Register r, Register tmp = t0); From 4a4701106c68aee7ba33c41d1e4f72d72ac1a3d6 Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Fri, 3 Apr 2026 12:39:49 +0000 Subject: [PATCH 170/359] 8369699: Template Framework Library: add VectorAPI types and operations Reviewed-by: mhaessig, vlivanov, galder --- .../jtreg/compiler/igvn/ExpressionFuzzer.java | 9 +- .../library/CodeGenerationDataNameType.java | 78 ++- .../library/Expression.java | 68 ++- .../library/Operations.java | 548 +++++++++++++++++- .../library/PrimitiveType.java | 17 + .../lib/template_framework/library/Utils.java | 41 ++ .../library/VectorType.java | 237 ++++++++ .../vectorapi/VectorExpressionFuzzer.java | 345 +++++++++++ .../examples/TestExpressions.java | 21 +- .../examples/TestPrimitiveTypes.java | 12 + .../examples/TestVectorTypes.java | 134 +++++ 11 files changed, 1479 insertions(+), 31 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/lib/template_framework/library/Utils.java create mode 100644 test/hotspot/jtreg/compiler/lib/template_framework/library/VectorType.java create mode 100644 test/hotspot/jtreg/compiler/vectorapi/VectorExpressionFuzzer.java create mode 100644 test/hotspot/jtreg/testlibrary_tests/template_framework/examples/TestVectorTypes.java diff --git a/test/hotspot/jtreg/compiler/igvn/ExpressionFuzzer.java b/test/hotspot/jtreg/compiler/igvn/ExpressionFuzzer.java index 33be24a0367..dfb2ec1405c 100644 --- a/test/hotspot/jtreg/compiler/igvn/ExpressionFuzzer.java +++ b/test/hotspot/jtreg/compiler/igvn/ExpressionFuzzer.java @@ -30,7 +30,7 @@ * @modules jdk.incubator.vector * @library /test/lib / * @compile ../lib/verify/Verify.java - * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:CompileTaskTimeout=10000 compiler.igvn.ExpressionFuzzer + * @run driver compiler.igvn.ExpressionFuzzer */ package compiler.igvn; @@ -73,6 +73,10 @@ import static compiler.lib.template_framework.library.CodeGenerationDataNameType // - Some basic IR tests to ensure that the constraints / checksum mechanics work. // We may even have to add some IGVN optimizations to be able to better observe things right. // - Lower the CompileTaskTimeout, if possible. It is chosen conservatively (rather high) for now. +// - I also had to exclude the compilation of the following method. It would lead to compilation +// timeouts and even compilation memory limit reached. It is a really large method, so I'm not +// sure if that is to be expected, or if we could still improve the situation. +// compiler.lib.template_framework.library.Operations::generateVectorOperations public class ExpressionFuzzer { private static final Random RANDOM = Utils.getRandomInstance(); @@ -93,7 +97,8 @@ public class ExpressionFuzzer { comp.invoke("compiler.igvn.templated.ExpressionFuzzerInnerTest", "main", new Object[] {new String[] { "--add-modules=jdk.incubator.vector", "--add-opens", "jdk.incubator.vector/jdk.incubator.vector=ALL-UNNAMED", - "--add-opens", "java.base/java.lang=ALL-UNNAMED" + "--add-opens", "java.base/java.lang=ALL-UNNAMED", + "-XX:+IgnoreUnrecognizedVMOptions", "-XX:CompileTaskTimeout=10000" }}); } diff --git a/test/hotspot/jtreg/compiler/lib/template_framework/library/CodeGenerationDataNameType.java b/test/hotspot/jtreg/compiler/lib/template_framework/library/CodeGenerationDataNameType.java index b461e3e857f..33eba66cd8c 100644 --- a/test/hotspot/jtreg/compiler/lib/template_framework/library/CodeGenerationDataNameType.java +++ b/test/hotspot/jtreg/compiler/lib/template_framework/library/CodeGenerationDataNameType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -132,6 +132,14 @@ public interface CodeGenerationDataNameType extends DataName.Type { longs() ); + /** + * List of {@link PrimitiveType}s (int, long). + */ + List INT_LONG_TYPES = List.of( + ints(), + longs() + ); + /** * List of all subword {@link PrimitiveType}s (byte, char, short). */ @@ -176,4 +184,72 @@ public interface CodeGenerationDataNameType extends DataName.Type { booleans(), float16() ); + + List VECTOR_BYTE_VECTOR_TYPES = List.of( + VectorType.BYTE_64, + VectorType.BYTE_128, + VectorType.BYTE_256, + VectorType.BYTE_512 + ); + + List VECTOR_SHORT_VECTOR_TYPES = List.of( + VectorType.SHORT_64, + VectorType.SHORT_128, + VectorType.SHORT_256, + VectorType.SHORT_512 + ); + + List VECTOR_INT_VECTOR_TYPES = List.of( + VectorType.INT_64, + VectorType.INT_128, + VectorType.INT_256, + VectorType.INT_512 + ); + + List VECTOR_LONG_VECTOR_TYPES = List.of( + VectorType.LONG_64, + VectorType.LONG_128, + VectorType.LONG_256, + VectorType.LONG_512 + ); + + List VECTOR_FLOAT_VECTOR_TYPES = List.of( + VectorType.FLOAT_64, + VectorType.FLOAT_128, + VectorType.FLOAT_256, + VectorType.FLOAT_512 + ); + + List VECTOR_DOUBLE_VECTOR_TYPES = List.of( + VectorType.DOUBLE_64, + VectorType.DOUBLE_128, + VectorType.DOUBLE_256, + VectorType.DOUBLE_512 + ); + + List VECTOR_VECTOR_TYPES = Utils.concat( + VECTOR_BYTE_VECTOR_TYPES, + VECTOR_SHORT_VECTOR_TYPES, + VECTOR_INT_VECTOR_TYPES, + VECTOR_LONG_VECTOR_TYPES, + VECTOR_FLOAT_VECTOR_TYPES, + VECTOR_DOUBLE_VECTOR_TYPES + ); + + List VECTOR_MASK_TYPES = + VECTOR_VECTOR_TYPES.stream().map(t -> t.maskType).toList(); + + List VECTOR_SHUFFLE_TYPES = + VECTOR_VECTOR_TYPES.stream().map(t -> t.shuffleType).toList(); + + List VECTOR_TYPES = Utils.concat( + VECTOR_VECTOR_TYPES, + VECTOR_MASK_TYPES, + VECTOR_SHUFFLE_TYPES + ); + + List ALL_TYPES = Utils.concat( + SCALAR_NUMERIC_TYPES, + VECTOR_TYPES + ); } diff --git a/test/hotspot/jtreg/compiler/lib/template_framework/library/Expression.java b/test/hotspot/jtreg/compiler/lib/template_framework/library/Expression.java index 37ad4debde6..f3e7b6ed0d3 100644 --- a/test/hotspot/jtreg/compiler/lib/template_framework/library/Expression.java +++ b/test/hotspot/jtreg/compiler/lib/template_framework/library/Expression.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -332,6 +332,72 @@ public class Expression { return new Expression(returnType, List.of(t0, t1, t2, t3), List.of(s0, s1, s2, s3, s4), info); } + /** + * Creates a new Expression with 5 arguments. + * + * @param returnType The return type of the {@link Expression}. + * @param s0 The first string, to be placed before {@code t0}. + * @param t0 The type of the first argument. + * @param s1 The second string, to be placed before {@code t1}. + * @param t1 The type of the second argument. + * @param s2 The third string, to be placed before {@code t2}. + * @param t2 The type of the third argument. + * @param s3 The fourth string, to be placed before {@code t3}. + * @param t3 The type of the fourth argument. + * @param s4 The fifth string, to be placed before {@code t4}. + * @param t4 The type of the fifth argument. + * @param s5 The last string, finishing the {@link Expression}. + * @return the new {@link Expression}. + */ + public static Expression make(CodeGenerationDataNameType returnType, + String s0, + CodeGenerationDataNameType t0, + String s1, + CodeGenerationDataNameType t1, + String s2, + CodeGenerationDataNameType t2, + String s3, + CodeGenerationDataNameType t3, + String s4, + CodeGenerationDataNameType t4, + String s5) { + return make(returnType, s0, t0, s1, t1, s2, t2, s3, t3, s4, t4, s5, new Info()); + } + + /** + * Creates a new Expression with 5 arguments. + * + * @param returnType The return type of the {@link Expression}. + * @param s0 The first string, to be placed before {@code t0}. + * @param t0 The type of the first argument. + * @param s1 The second string, to be placed before {@code t1}. + * @param t1 The type of the second argument. + * @param s2 The third string, to be placed before {@code t2}. + * @param t2 The type of the third argument. + * @param s3 The fourth string, to be placed before {@code t3}. + * @param t3 The type of the fourth argument. + * @param s4 The fifth string, to be placed before {@code t4}. + * @param t4 The type of the fifth argument. + * @param s5 The last string, finishing the {@link Expression}. + * @param info Additional information about the {@link Expression}. + * @return the new {@link Expression}. + */ + public static Expression make(CodeGenerationDataNameType returnType, + String s0, + CodeGenerationDataNameType t0, + String s1, + CodeGenerationDataNameType t1, + String s2, + CodeGenerationDataNameType t2, + String s3, + CodeGenerationDataNameType t3, + String s4, + CodeGenerationDataNameType t4, + String s5, + Info info) { + return new Expression(returnType, List.of(t0, t1, t2, t3, t4), List.of(s0, s1, s2, s3, s4, s5), info); + } + /** * Creates a {@link TemplateToken} for the use in a {@link Template} by applying the * {@code arguments} to the {@link Expression}. It is the users responsibility to diff --git a/test/hotspot/jtreg/compiler/lib/template_framework/library/Operations.java b/test/hotspot/jtreg/compiler/lib/template_framework/library/Operations.java index 2ea251cc5e5..4c598506e70 100644 --- a/test/hotspot/jtreg/compiler/lib/template_framework/library/Operations.java +++ b/test/hotspot/jtreg/compiler/lib/template_framework/library/Operations.java @@ -24,11 +24,8 @@ package compiler.lib.template_framework.library; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; import static compiler.lib.template_framework.library.PrimitiveType.BYTES; import static compiler.lib.template_framework.library.PrimitiveType.SHORTS; @@ -39,6 +36,10 @@ import static compiler.lib.template_framework.library.PrimitiveType.FLOATS; import static compiler.lib.template_framework.library.PrimitiveType.DOUBLES; import static compiler.lib.template_framework.library.PrimitiveType.BOOLEANS; import static compiler.lib.template_framework.library.Float16Type.FLOAT16; +import static compiler.lib.template_framework.library.CodeGenerationDataNameType.PRIMITIVE_TYPES; +import static compiler.lib.template_framework.library.CodeGenerationDataNameType.INTEGRAL_TYPES; +import static compiler.lib.template_framework.library.CodeGenerationDataNameType.FLOATING_TYPES; +import static compiler.lib.template_framework.library.CodeGenerationDataNameType.INT_LONG_TYPES; /** * This class provides various lists of {@link Expression}s, that represent Java operators or library @@ -51,27 +52,8 @@ public final class Operations { private static Expression.Info WITH_ARITHMETIC_EXCEPTION = new Expression.Info().withExceptions(Set.of("ArithmeticException")); private static Expression.Info WITH_NONDETERMINISTIC_RESULT = new Expression.Info().withNondeterministicResult(); - - - /** - * Provides a lits of operations on {@link PrimitiveType}s, such as arithmetic, logical, - * and cast operations. - */ - public static final List PRIMITIVE_OPERATIONS = generatePrimitiveOperations(); - - public static final List FLOAT16_OPERATIONS = generateFloat16Operations(); - - public static final List SCALAR_NUMERIC_OPERATIONS = concat( - PRIMITIVE_OPERATIONS, - FLOAT16_OPERATIONS - ); - - @SafeVarargs - private static List concat(List... lists) { - return Arrays.stream(lists) - .flatMap(List::stream) - .collect(Collectors.toList()); - } + private static Expression.Info WITH_ILLEGAL_ARGUMENT_EXCEPTION = new Expression.Info().withExceptions(Set.of("IllegalArgumentException")); + private static Expression.Info WITH_OUT_OF_BOUNDS_EXCEPTION = new Expression.Info().withExceptions(Set.of("IndexOutOfBoundsException")); private static void addComparisonOperations(List ops, String operatorName, CodeGenerationDataNameType type) { for (String mask : List.of("==", "!=", "<", ">", "<=", ">=")) { @@ -332,4 +314,522 @@ public final class Operations { // Make sure the list is not modifiable. return List.copyOf(ops); } + + private enum VOPType { + UNARY, + BINARY, + ASSOCIATIVE, // Binary and associative - safe for reductions of any type + INTEGRAL_ASSOCIATIVE, // Binary - but only safe for integral reductions + TERNARY + } + private record VOP(String name, VOPType type, List elementTypes, boolean isDeterministic) { + VOP(String name, VOPType type, List elementTypes) { + this(name, type, elementTypes, true); + } + } + + // TODO: consider enforcing precision instead of just blanket non-determinism + // We could annotate the exact ulp, and so if some test can use it: great + // But if a test is just interested in determinism, they are still + // non-deterministic. + private static final List VECTOR_OPS = List.of( + new VOP("ABS", VOPType.UNARY, PRIMITIVE_TYPES), + new VOP("ACOS", VOPType.UNARY, FLOATING_TYPES, false), // 1 ulp + new VOP("ADD", VOPType.INTEGRAL_ASSOCIATIVE, PRIMITIVE_TYPES), + new VOP("AND", VOPType.ASSOCIATIVE, INTEGRAL_TYPES), + new VOP("AND_NOT", VOPType.BINARY, INTEGRAL_TYPES), + new VOP("ASHR", VOPType.BINARY, INTEGRAL_TYPES), + new VOP("ASIN", VOPType.UNARY, FLOATING_TYPES, false), // 1 ulp + new VOP("ATAN", VOPType.UNARY, FLOATING_TYPES, false), // 1 ulp + new VOP("ATAN2", VOPType.BINARY, FLOATING_TYPES, false), // 2 ulp + new VOP("BIT_COUNT", VOPType.UNARY, INTEGRAL_TYPES), + new VOP("BITWISE_BLEND", VOPType.TERNARY, INTEGRAL_TYPES), + new VOP("CBRT", VOPType.UNARY, FLOATING_TYPES, false), // 1 ulp + new VOP("COMPRESS_BITS", VOPType.BINARY, INT_LONG_TYPES), + new VOP("COS", VOPType.UNARY, FLOATING_TYPES, false), // 1 ulp + new VOP("COSH", VOPType.UNARY, FLOATING_TYPES, false), // 2.5 ulp + new VOP("DIV", VOPType.BINARY, FLOATING_TYPES), + new VOP("EXP", VOPType.UNARY, FLOATING_TYPES, false), // 1 ulp + new VOP("EXPAND_BITS", VOPType.BINARY, INT_LONG_TYPES), + new VOP("EXPM1", VOPType.UNARY, FLOATING_TYPES, false), // 1 ulp + new VOP("FIRST_NONZERO", VOPType.ASSOCIATIVE, PRIMITIVE_TYPES), + new VOP("FMA", VOPType.TERNARY, FLOATING_TYPES), + new VOP("HYPOT", VOPType.BINARY, FLOATING_TYPES, false), // 1.5 ulp + new VOP("LEADING_ZEROS_COUNT", VOPType.UNARY, INTEGRAL_TYPES), + new VOP("LOG", VOPType.UNARY, FLOATING_TYPES, false), // 1 ulp + new VOP("LOG10", VOPType.UNARY, FLOATING_TYPES, false), // 1 ulp + new VOP("LOG1P", VOPType.UNARY, FLOATING_TYPES, false), // 1 ulp + new VOP("LSHL", VOPType.BINARY, INTEGRAL_TYPES), + new VOP("LSHR", VOPType.BINARY, INTEGRAL_TYPES), + new VOP("MIN", VOPType.ASSOCIATIVE, PRIMITIVE_TYPES), + new VOP("MAX", VOPType.ASSOCIATIVE, PRIMITIVE_TYPES), + new VOP("MUL", VOPType.INTEGRAL_ASSOCIATIVE, PRIMITIVE_TYPES), + new VOP("NEG", VOPType.UNARY, PRIMITIVE_TYPES), + new VOP("NOT", VOPType.UNARY, INTEGRAL_TYPES), + new VOP("OR", VOPType.ASSOCIATIVE, INTEGRAL_TYPES), + new VOP("POW", VOPType.BINARY, FLOATING_TYPES, false), // 1 ulp + new VOP("REVERSE", VOPType.UNARY, INTEGRAL_TYPES), + new VOP("REVERSE_BYTES", VOPType.UNARY, INTEGRAL_TYPES), + new VOP("ROL", VOPType.BINARY, INTEGRAL_TYPES), + new VOP("ROR", VOPType.BINARY, INTEGRAL_TYPES), + new VOP("SADD", VOPType.BINARY, INTEGRAL_TYPES), + new VOP("SIN", VOPType.UNARY, FLOATING_TYPES, false), // 1 ulp + new VOP("SINH", VOPType.UNARY, FLOATING_TYPES, false), // 2.5 ulp + new VOP("SQRT", VOPType.UNARY, FLOATING_TYPES), + new VOP("SSUB", VOPType.BINARY, INTEGRAL_TYPES), + new VOP("SUADD", VOPType.BINARY, INTEGRAL_TYPES), + new VOP("SUB", VOPType.BINARY, PRIMITIVE_TYPES), + new VOP("SUSUB", VOPType.BINARY, INTEGRAL_TYPES), + new VOP("TAN", VOPType.UNARY, FLOATING_TYPES, false), // 1.25 ulp + new VOP("TANH", VOPType.UNARY, FLOATING_TYPES, false), // 2.5 ulp + new VOP("TRAILING_ZEROS_COUNT", VOPType.UNARY, INTEGRAL_TYPES), + new VOP("UMAX", VOPType.ASSOCIATIVE, INTEGRAL_TYPES), + new VOP("UMIN", VOPType.ASSOCIATIVE, INTEGRAL_TYPES), + new VOP("XOR", VOPType.ASSOCIATIVE, INTEGRAL_TYPES), + new VOP("ZOMO", VOPType.UNARY, INTEGRAL_TYPES) + ); + + private static final List VECTOR_CMP = List.of( + new VOP("EQ", VOPType.ASSOCIATIVE, PRIMITIVE_TYPES), + new VOP("GE", VOPType.ASSOCIATIVE, PRIMITIVE_TYPES), + new VOP("GT", VOPType.ASSOCIATIVE, PRIMITIVE_TYPES), + new VOP("LE", VOPType.ASSOCIATIVE, PRIMITIVE_TYPES), + new VOP("LT", VOPType.ASSOCIATIVE, PRIMITIVE_TYPES), + new VOP("NE", VOPType.ASSOCIATIVE, PRIMITIVE_TYPES), + new VOP("UGE", VOPType.ASSOCIATIVE, INTEGRAL_TYPES), + new VOP("UGT", VOPType.ASSOCIATIVE, INTEGRAL_TYPES), + new VOP("ULE", VOPType.ASSOCIATIVE, INTEGRAL_TYPES), + new VOP("ULT", VOPType.ASSOCIATIVE, INTEGRAL_TYPES) + ); + + private static final List VECTOR_TEST = List.of( + new VOP("IS_DEFAULT", VOPType.UNARY, PRIMITIVE_TYPES), + new VOP("IS_NEGATIVE", VOPType.UNARY, PRIMITIVE_TYPES), + new VOP("IS_FINITE", VOPType.UNARY, FLOATING_TYPES), + new VOP("IS_NAN", VOPType.UNARY, FLOATING_TYPES), + new VOP("IS_INFINITE", VOPType.UNARY, FLOATING_TYPES) + ); + + // TODO: Conversion VectorOperators -> convertShape + + private static List generateVectorOperations() { + List ops = new ArrayList<>(); + + for (var type : CodeGenerationDataNameType.VECTOR_VECTOR_TYPES) { + // ----------------- IntVector, FloatVector, ... -------------------- + ops.add(Expression.make(type, "", type, ".abs()")); + ops.add(Expression.make(type, "", type, ".add(", type.elementType, ")")); + ops.add(Expression.make(type, "", type, ".add(", type.elementType, ", ", type.maskType, ")")); + ops.add(Expression.make(type, "", type, ".add(", type, ")")); + ops.add(Expression.make(type, "", type, ".add(", type, ", ", type.maskType, ")")); + + // If VLENGTH*scale overflows, then a IllegalArgumentException is thrown. + ops.add(Expression.make(type, "", type, ".addIndex(1)")); + ops.add(Expression.make(type, "", type, ".addIndex(", INTS, ")", WITH_ILLEGAL_ARGUMENT_EXCEPTION)); + + if (!type.elementType.isFloating()) { + ops.add(Expression.make(type, "", type, ".and(", type.elementType, ")")); + ops.add(Expression.make(type, "", type, ".and(", type, ")")); + ops.add(Expression.make(type, "", type, ".bitwiseBlend(", type.elementType, ", ", type.elementType, ")")); + ops.add(Expression.make(type, "", type, ".bitwiseBlend(", type.elementType, ", ", type, ")")); + ops.add(Expression.make(type, "", type, ".bitwiseBlend(", type, ", ", type.elementType, ")")); + ops.add(Expression.make(type, "", type, ".bitwiseBlend(", type, ", ", type, ")")); + ops.add(Expression.make(type, "", type, ".not()")); + ops.add(Expression.make(type, "", type, ".or(", type.elementType, ")")); + ops.add(Expression.make(type, "", type, ".or(", type, ")")); + } + + ops.add(Expression.make(type, "", type, ".blend(", type.elementType, ", ", type.maskType, ")")); + ops.add(Expression.make(type, "", type, ".blend(", LONGS, ", ", type.maskType, ")", WITH_ILLEGAL_ARGUMENT_EXCEPTION)); + ops.add(Expression.make(type, "", type, ".blend(", type, ", ", type.maskType, ")")); + + ops.add(Expression.make(type, type.name() + ".broadcast(" + type.speciesName + ", ", type.elementType, ")")); + ops.add(Expression.make(type, type.name() + ".broadcast(" + type.speciesName + ", ", LONGS, ")", WITH_ILLEGAL_ARGUMENT_EXCEPTION)); + + for (var type2 : CodeGenerationDataNameType.VECTOR_VECTOR_TYPES) { + ops.add(Expression.make(type, "((" + type.name() + ")", type2 , ".castShape(" + type.speciesName + ", 0))")); + ops.add(Expression.make(type, "((" + type.name() + ")", type2 , ".castShape(" + type.speciesName + ", ", INTS, "))", WITH_OUT_OF_BOUNDS_EXCEPTION)); + } + + // skip check + + for (VOP cmp : VECTOR_CMP) { + if (cmp.elementTypes().contains(type.elementType)) { + ops.add(Expression.make(type.maskType, "", type, ".compare(VectorOperators." + cmp.name() + ", ", type.elementType, ")")); + ops.add(Expression.make(type.maskType, "", type, ".compare(VectorOperators." + cmp.name() + ", ", type.elementType, ", ", type.maskType, ")")); + ops.add(Expression.make(type.maskType, "", type, ".compare(VectorOperators." + cmp.name() + ", ", LONGS, ")", WITH_ILLEGAL_ARGUMENT_EXCEPTION)); + ops.add(Expression.make(type.maskType, "", type, ".compare(VectorOperators." + cmp.name() + ", ", LONGS, ", ", type.maskType, ")", WITH_ILLEGAL_ARGUMENT_EXCEPTION)); + ops.add(Expression.make(type.maskType, "", type, ".compare(VectorOperators." + cmp.name() + ", ", type, ")")); + } + } + + ops.add(Expression.make(type, "", type, ".compress(", type.maskType, ")")); + + for (var type2 : CodeGenerationDataNameType.VECTOR_VECTOR_TYPES) { + // "convert" keeps the same shape, i.e. length of the vector in bits. + if (type.byteSize() == type2.byteSize()) { + ops.add(Expression.make(type, + "((" + type.name() + ")", + type2, + ".convert(VectorOperators.Conversion.ofCast(" + + type2.elementType.name() + ".class, " + + type.elementType.name() + ".class), 0))")); + ops.add(Expression.make(type, + "((" + type.name() + ")", + type2, + ".convert(VectorOperators.Conversion.ofCast(" + + type2.elementType.name() + ".class, " + + type.elementType.name() + ".class),", + INTS, // part + "))", WITH_OUT_OF_BOUNDS_EXCEPTION)); + } + + // Reinterpretation FROM floating is not safe, because of different NaN encodings, i.e. + // we will not get deterministic results. + var reinterpretInfo = type2.elementType.isFloating() ? WITH_NONDETERMINISTIC_RESULT : new Expression.Info(); + + // The following "reinterpret" operations require same input and output shape. + if (type.byteSize() == type2.byteSize()) { + ops.add(Expression.make(type, + "((" + type.name() + ")", + type2, + ".convert(VectorOperators.Conversion.ofReinterpret(" + + type2.elementType.name() + ".class, " + + type.elementType.name() + ".class), 0))", reinterpretInfo)); + ops.add(Expression.make(type, + "((" + type.name() + ")", + type2, + ".convert(VectorOperators.Conversion.ofReinterpret(" + + type2.elementType.name() + ".class, " + + type.elementType.name() + ".class),", + INTS, // part + "))", reinterpretInfo.combineWith(WITH_OUT_OF_BOUNDS_EXCEPTION))); + if (type.elementType == BYTES) { + ops.add(Expression.make(type, "", type2, ".reinterpretAsBytes()", reinterpretInfo)); + } + if (type.elementType == SHORTS) { + ops.add(Expression.make(type, "", type2, ".reinterpretAsShorts()", reinterpretInfo)); + } + if (type.elementType == INTS) { + ops.add(Expression.make(type, "", type2, ".reinterpretAsInts()", reinterpretInfo)); + } + if (type.elementType == LONGS) { + ops.add(Expression.make(type, "", type2, ".reinterpretAsLongs()", reinterpretInfo)); + } + if (type.elementType == FLOATS) { + ops.add(Expression.make(type, "", type2, ".reinterpretAsFloats()", reinterpretInfo)); + } + if (type.elementType == DOUBLES) { + ops.add(Expression.make(type, "", type2, ".reinterpretAsDoubles()", reinterpretInfo)); + } + if (type.elementType.isFloating() && type.elementType.byteSize() == type2.elementType.byteSize()) { + ops.add(Expression.make(type, "", type2, ".viewAsFloatingLanes()", reinterpretInfo)); + } + if (!type.elementType.isFloating() && type.elementType.byteSize() == type2.elementType.byteSize()) { + ops.add(Expression.make(type, "", type2, ".viewAsIntegralLanes()", reinterpretInfo)); + } + } + + // reinterpretShape + if (type2.byteSize() >= type.byteSize()) { + // Output overflows, is truncated (Expansion): part >= 0 + int partMask = type2.byteSize() / type.byteSize() - 1; + ops.add(Expression.make(type, + "((" + type.name() + ")", + type2, + ".reinterpretShape(" + type.speciesName + ", ", + INTS, " & " + partMask + "))", reinterpretInfo)); + } else { + // Logical output too small to fill output vector (Contraction): part <= 0 + int partMask = type.byteSize() / type2.byteSize() - 1; + ops.add(Expression.make(type, + "((" + type.name() + ")", + type2, + ".reinterpretShape(" + type.speciesName + ", " + + "-(", INTS, " & " + partMask + ")))", reinterpretInfo)); + } + + // convertShape - Cast/Reinterpret + ops.add(Expression.make(type, + "((" + type.name() + ")", + type2, + ".convertShape(VectorOperators.Conversion.ofCast(" + + type2.elementType.name() + ".class, " + + type.elementType.name() + ".class), " + + type.speciesName + ", ", + INTS, // part + "))", WITH_OUT_OF_BOUNDS_EXCEPTION)); + ops.add(Expression.make(type, + "((" + type.name() + ")", + type2, + ".convertShape(VectorOperators.Conversion.ofReinterpret(" + + type2.elementType.name() + ".class, " + + type.elementType.name() + ".class), " + + type.speciesName + ", ", + INTS, // part + "))", reinterpretInfo.combineWith(WITH_OUT_OF_BOUNDS_EXCEPTION))); + // Compute size of logical output, before it is "fit" into the output vector. + // Each element is cast/reinterpret individually, and so the logical output + // has the lane count of the input vector, and the element size that of the output element size. + // Note: reinterpret of float -> long means we expand each element from 4->8 bytes, and so + // we take the lower 4 bytes from the float and add 4 bytes of zero padding. + int conversionLogicalByteSize = type2.length * type.elementType.byteSize(); + if (conversionLogicalByteSize >= type.byteSize()) { + // Output overflows, is truncated (Expansion): part >= 0 + int partMask = conversionLogicalByteSize / type.byteSize() - 1; + ops.add(Expression.make(type, + "((" + type.name() + ")", + type2, + ".convertShape(VectorOperators.Conversion.ofCast(" + + type2.elementType.name() + ".class, " + + type.elementType.name() + ".class), " + + type.speciesName + ", ", + INTS, " & " + partMask + "))")); + ops.add(Expression.make(type, + "((" + type.name() + ")", + type2, + ".convertShape(VectorOperators.Conversion.ofReinterpret(" + + type2.elementType.name() + ".class, " + + type.elementType.name() + ".class), " + + type.speciesName + ", ", + INTS, " & " + partMask + "))", reinterpretInfo)); + } else { + // Logical output too small to fill output vector (Contraction): part <= 0 + int partMask = type.byteSize() / conversionLogicalByteSize - 1; + ops.add(Expression.make(type, + "((" + type.name() + ")", + type2, + ".convertShape(VectorOperators.Conversion.ofCast(" + + type2.elementType.name() + ".class, " + + type.elementType.name() + ".class), " + + type.speciesName + ", " + + "-(", INTS, " & " + partMask + ")))")); + ops.add(Expression.make(type, + "((" + type.name() + ")", + type2, + ".convertShape(VectorOperators.Conversion.ofReinterpret(" + + type2.elementType.name() + ".class, " + + type.elementType.name() + ".class), " + + type.speciesName + ", " + + "-(", INTS, " & " + partMask + ")))", reinterpretInfo)); + } + // TODO: convertShape - using VectorOperators.I2S,REINTERPRET_I2F,ZERO_EXTEND_B2I etc. + } + + ops.add(Expression.make(type, "", type, ".div(", type.elementType, ")", WITH_ARITHMETIC_EXCEPTION)); + ops.add(Expression.make(type, "", type, ".div(", type.elementType, ", ", type.maskType, ")", WITH_ARITHMETIC_EXCEPTION)); + ops.add(Expression.make(type, "", type, ".div(", type, ")", WITH_ARITHMETIC_EXCEPTION)); + ops.add(Expression.make(type, "", type, ".div(", type, ", ", type.maskType, ")", WITH_ARITHMETIC_EXCEPTION)); + + ops.add(Expression.make(type.maskType, "", type, ".eq(", type.elementType, ")")); + ops.add(Expression.make(type.maskType, "", type, ".eq(", type, ")")); + // skip equals + ops.add(Expression.make(type, "", type, ".expand(", type.maskType, ")")); + // skip fromArray + // skip fromMemorySegment + // skip hashCode + // skip intoArray + // skip intoMemorySegment + // TODO: memory accesses. It is not clear yet if these are to be modeled as Expressions, or rather statements. + ops.add(Expression.make(type.elementType, "", type, ".lane(", INTS, " & " + (type.length-1) + ")")); + ops.add(Expression.make(type.elementType, "", type, ".lane(", INTS, ")", WITH_ILLEGAL_ARGUMENT_EXCEPTION)); + + for (VOP vop : VECTOR_OPS) { + var vopInfo = vop.isDeterministic ? new Expression.Info() : WITH_NONDETERMINISTIC_RESULT; + if (vop.elementTypes().contains(type.elementType)) { + switch(vop.type()) { + case VOPType.UNARY: + ops.add(Expression.make(type, "", type, ".lanewise(VectorOperators." + vop.name() + ")", vopInfo)); + ops.add(Expression.make(type, "", type, ".lanewise(VectorOperators." + vop.name() + ", ", type.maskType, ")", vopInfo)); + break; + case VOPType.ASSOCIATIVE: + case VOPType.INTEGRAL_ASSOCIATIVE: + if (vop.type() == VOPType.ASSOCIATIVE || !type.elementType.isFloating()) { + ops.add(Expression.make(type.elementType, "", type, ".reduceLanes(VectorOperators." + vop.name() + ")", vopInfo)); + ops.add(Expression.make(type.elementType, "", type, ".reduceLanes(VectorOperators." + vop.name() + ", ", type.maskType, ")", vopInfo)); + } + // fall-through + case VOPType.BINARY: + ops.add(Expression.make(type, "", type, ".lanewise(VectorOperators." + vop.name() + ", ", type.elementType, ")", vopInfo)); + ops.add(Expression.make(type, "", type, ".lanewise(VectorOperators." + vop.name() + ", ", type.elementType, ", ", type.maskType, ")", vopInfo)); + ops.add(Expression.make(type, "", type, ".lanewise(VectorOperators." + vop.name() + ", ", LONGS, ")", vopInfo.combineWith(WITH_ILLEGAL_ARGUMENT_EXCEPTION))); + ops.add(Expression.make(type, "", type, ".lanewise(VectorOperators." + vop.name() + ", ", LONGS, ", ", type.maskType, ")", vopInfo.combineWith(WITH_ILLEGAL_ARGUMENT_EXCEPTION))); + ops.add(Expression.make(type, "", type, ".lanewise(VectorOperators." + vop.name() + ", ", type, ")", vopInfo)); + ops.add(Expression.make(type, "", type, ".lanewise(VectorOperators." + vop.name() + ", ", type, ", ", type.maskType, ")", vopInfo)); + break; + case VOPType.TERNARY: + ops.add(Expression.make(type, "", type, ".lanewise(VectorOperators." + vop.name() + ", ", type.elementType, ", ", type.elementType, ")", vopInfo)); + ops.add(Expression.make(type, "", type, ".lanewise(VectorOperators." + vop.name() + ", ", type.elementType, ", ", type.elementType, ", ", type.maskType, ")", vopInfo)); + ops.add(Expression.make(type, "", type, ".lanewise(VectorOperators." + vop.name() + ", ", type.elementType, ", ", type, ")", vopInfo)); + ops.add(Expression.make(type, "", type, ".lanewise(VectorOperators." + vop.name() + ", ", type.elementType, ", ", type, ", ", type.maskType, ")", vopInfo)); + ops.add(Expression.make(type, "", type, ".lanewise(VectorOperators." + vop.name() + ", ", type, ", ", type.elementType, ")", vopInfo)); + ops.add(Expression.make(type, "", type, ".lanewise(VectorOperators." + vop.name() + ", ", type, ", ", type.elementType, ", ", type.maskType, ")", vopInfo)); + ops.add(Expression.make(type, "", type, ".lanewise(VectorOperators." + vop.name() + ", ", type, ", ", type, ")", vopInfo)); + ops.add(Expression.make(type, "", type, ".lanewise(VectorOperators." + vop.name() + ", ", type, ", ", type, ", ", type.maskType, ")", vopInfo)); + break; + } + } + } + + ops.add(Expression.make(type.maskType, "", type, ".lt(", type.elementType, ")")); + ops.add(Expression.make(type.maskType, "", type, ".lt(", type, ")")); + + ops.add(Expression.make(type.maskType, "", type, ".maskAll(", BOOLEANS, ")")); + + ops.add(Expression.make(type, "", type, ".max(", type.elementType, ")")); + ops.add(Expression.make(type, "", type, ".max(", type, ")")); + ops.add(Expression.make(type, "", type, ".min(", type.elementType, ")")); + ops.add(Expression.make(type, "", type, ".min(", type, ")")); + + ops.add(Expression.make(type, "", type, ".mul(", type.elementType, ")")); + ops.add(Expression.make(type, "", type, ".mul(", type.elementType, ", ", type.maskType, ")")); + ops.add(Expression.make(type, "", type, ".mul(", type, ")")); + ops.add(Expression.make(type, "", type, ".mul(", type, ", ", type.maskType, ")")); + + ops.add(Expression.make(type, "", type, ".neg()")); + + ops.add(Expression.make(type, "", type, ".rearrange(", type.shuffleType, ")")); + ops.add(Expression.make(type, "", type, ".rearrange(", type.shuffleType, ", ", type, ")")); + ops.add(Expression.make(type, "", type, ".rearrange(", type.shuffleType, ", ", type.maskType, ")")); + + ops.add(Expression.make(type, "", type, ".selectFrom(", type, ")")); + ops.add(Expression.make(type, "", type, ".selectFrom(", type, ", ", type, ")")); + ops.add(Expression.make(type, "", type, ".selectFrom(", type, ", ", type.maskType, ")")); + + ops.add(Expression.make(type, "", type, ".slice(", INTS, ")", WITH_OUT_OF_BOUNDS_EXCEPTION)); + ops.add(Expression.make(type, "", type, ".slice(", INTS, ", ", type, ")", WITH_OUT_OF_BOUNDS_EXCEPTION)); + ops.add(Expression.make(type, "", type, ".slice(", INTS, ", ", type, ", ", type.maskType, ")", WITH_OUT_OF_BOUNDS_EXCEPTION)); + + ops.add(Expression.make(type, "", type, ".sub(", type.elementType, ")")); + ops.add(Expression.make(type, "", type, ".sub(", type.elementType, ", ", type.maskType, ")")); + ops.add(Expression.make(type, "", type, ".sub(", type, ")")); + ops.add(Expression.make(type, "", type, ".sub(", type, ", ", type.maskType, ")")); + + + for (VOP test : VECTOR_TEST) { + if (test.elementTypes().contains(type.elementType)) { + ops.add(Expression.make(type.maskType, "", type, ".test(VectorOperators." + test.name() + ")")); + ops.add(Expression.make(type.maskType, "", type, ".test(VectorOperators." + test.name() + ", ", type.maskType, ")")); + } + } + + // skip toArray and friends + + ops.add(Expression.make(type, "", type, ".unslice(", INTS, " & " + (type.length-1) + ")")); + ops.add(Expression.make(type, "", type, ".unslice(", INTS, ")", WITH_OUT_OF_BOUNDS_EXCEPTION)); + ops.add(Expression.make(type, "", type, ".unslice(", INTS, " & " + (type.length-1) + ", ", type, ", ", INTS, " & 2)")); + ops.add(Expression.make(type, "", type, ".unslice(", INTS, ", ", type, ", 0)", WITH_OUT_OF_BOUNDS_EXCEPTION)); + ops.add(Expression.make(type, "", type, ".unslice(", INTS, ", ", type, ", ", INTS, ")", WITH_OUT_OF_BOUNDS_EXCEPTION)); + ops.add(Expression.make(type, "", type, ".unslice(", INTS, ", ", type, ", 0, ", type.maskType, ")", WITH_OUT_OF_BOUNDS_EXCEPTION)); + ops.add(Expression.make(type, "", type, ".unslice(", INTS, ", ", type, ", ", INTS, ", ", type.maskType, ")", WITH_OUT_OF_BOUNDS_EXCEPTION)); + + ops.add(Expression.make(type, "", type, ".withLane(", INTS, ", ", type.elementType, ")", WITH_ILLEGAL_ARGUMENT_EXCEPTION)); + + if (type.elementType.isFloating()) { + ops.add(Expression.make(type, "", type, ".fma(", type.elementType, ", ", type.elementType, ")")); + ops.add(Expression.make(type, "", type, ".fma(", type, ", ", type, ")")); + + // TODO: enforce precision instead of just making it non-deterministic? + // See similar comment at VOP definition. + ops.add(Expression.make(type, "", type, ".pow(", type.elementType, ")", WITH_NONDETERMINISTIC_RESULT)); + ops.add(Expression.make(type, "", type, ".pow(", type, ")", WITH_NONDETERMINISTIC_RESULT)); + ops.add(Expression.make(type, "", type, ".sqrt()")); + } + + ops.add(Expression.make(type.shuffleType, "", type, ".toShuffle()")); + // skip zero - can get it from type.con() anyway. + + // ----------------- MaskVector -------------------- + // skip fromValues, too many inputs + // skip fromArray + ops.add(Expression.make(type.maskType, "VectorMask.fromLong(" + type.speciesName + ", ", LONGS, ")")); + for (var type2 : CodeGenerationDataNameType.VECTOR_VECTOR_TYPES) { + var mask = type.maskType; + var mask2 = type2.maskType; + if (type.length == type2.length) { + ops.add(Expression.make(mask, "((" + mask.name() + ")", mask2 , ".cast(" + type.speciesName + "))")); + } + } + ops.add(Expression.make(LONGS, "", type.maskType , ".toLong()")); + // skip toArray + // skip intoArray + ops.add(Expression.make(BOOLEANS, "", type.maskType , ".anyTrue()")); + ops.add(Expression.make(BOOLEANS, "", type.maskType , ".allTrue()")); + ops.add(Expression.make(INTS, "", type.maskType , ".trueCount()")); + ops.add(Expression.make(INTS, "", type.maskType , ".firstTrue()")); + ops.add(Expression.make(INTS, "", type.maskType , ".lastTrue()")); + ops.add(Expression.make(type.maskType, "", type.maskType , ".and(", type.maskType, ")")); + ops.add(Expression.make(type.maskType, "", type.maskType , ".or(", type.maskType, ")")); + ops.add(Expression.make(type.maskType, "", type.maskType , ".xor(", type.maskType, ")")); + ops.add(Expression.make(type.maskType, "", type.maskType , ".andNot(", type.maskType, ")")); + ops.add(Expression.make(type.maskType, "", type.maskType , ".eq(", type.maskType, ")")); + ops.add(Expression.make(type.maskType, "", type.maskType , ".not()")); + ops.add(Expression.make(type.maskType, "", type.maskType , ".indexInRange(", INTS, ", ", INTS,")")); + ops.add(Expression.make(type.maskType, "", type.maskType , ".indexInRange(", LONGS, ", ", LONGS,")")); + ops.add(Expression.make(type, "((" + type.name() + ")", type.maskType , ".toVector())")); + ops.add(Expression.make(BOOLEANS, "", type.maskType , ".laneIsSet(", INTS, ")", WITH_OUT_OF_BOUNDS_EXCEPTION)); + ops.add(Expression.make(BOOLEANS, "", type.maskType , ".laneIsSet(", INTS, " & " + (type.length-1) + ")")); + // skip check + // skip toString + // skip equals + // skip hashCode + ops.add(Expression.make(type.maskType, "", type.maskType , ".compress()")); + + // ----------------- ShuffleVector -------------------- + for (var type2 : CodeGenerationDataNameType.VECTOR_VECTOR_TYPES) { + var shuffle = type.shuffleType; + var shuffle2 = type2.shuffleType; + if (type.length == type2.length) { + ops.add(Expression.make(shuffle, "((" + shuffle.name() + ")", shuffle2 , ".cast(" + type.speciesName + "))")); + } + } + ops.add(Expression.make(INTS, "", type.shuffleType , ".checkIndex(", INTS, ")", WITH_OUT_OF_BOUNDS_EXCEPTION)); + ops.add(Expression.make(INTS, "", type.shuffleType , ".wrapIndex(", INTS, ")")); + ops.add(Expression.make(type.shuffleType, "", type.shuffleType , ".checkIndexes()", WITH_OUT_OF_BOUNDS_EXCEPTION)); + ops.add(Expression.make(type.shuffleType, "", type.shuffleType , ".wrapIndexes()")); + ops.add(Expression.make(type.maskType, "", type.shuffleType , ".laneIsValid()")); + // skip fromValues, too many inputs + // skip fromArray + // skip fromMemorySegment + // skip fromOp + // skip iota + // skip makeZip + // skip makeUnzip + // skip toArray + // skip intoArray + // skip intoMemorySegment + ops.add(Expression.make(type, "((" + type.name() + ")", type.shuffleType , ".toVector())")); + ops.add(Expression.make(INTS, "", type.shuffleType , ".laneSource(", INTS,")", WITH_ILLEGAL_ARGUMENT_EXCEPTION)); + ops.add(Expression.make(INTS, "", type.shuffleType , ".laneSource(", INTS," & " + (type.length-1) + ")")); + ops.add(Expression.make(type.shuffleType, "", type.shuffleType, ".rearrange(", type.shuffleType, ")")); + // skip toString + // skip equals + // skip hashCode + } + + // TODO: VectorSpecies API methods + + // Make sure the list is not modifiable. + return List.copyOf(ops); + } + + /** + * Provides a lits of operations on {@link PrimitiveType}s, such as arithmetic, logical, + * and cast operations. + */ + public static final List PRIMITIVE_OPERATIONS = generatePrimitiveOperations(); + + public static final List FLOAT16_OPERATIONS = generateFloat16Operations(); + + public static final List SCALAR_NUMERIC_OPERATIONS = Utils.concat( + PRIMITIVE_OPERATIONS, + FLOAT16_OPERATIONS + ); + + public static final List VECTOR_OPERATIONS = generateVectorOperations(); + + public static final List ALL_OPERATIONS = Utils.concat( + SCALAR_NUMERIC_OPERATIONS, + VECTOR_OPERATIONS + ); } diff --git a/test/hotspot/jtreg/compiler/lib/template_framework/library/PrimitiveType.java b/test/hotspot/jtreg/compiler/lib/template_framework/library/PrimitiveType.java index b20dbb28d22..cd796fd0d31 100644 --- a/test/hotspot/jtreg/compiler/lib/template_framework/library/PrimitiveType.java +++ b/test/hotspot/jtreg/compiler/lib/template_framework/library/PrimitiveType.java @@ -34,6 +34,7 @@ import compiler.lib.template_framework.DataName; import compiler.lib.template_framework.Template; import compiler.lib.template_framework.TemplateToken; import static compiler.lib.template_framework.Template.scope; +import static compiler.lib.template_framework.Template.let; /** * The {@link PrimitiveType} models Java's primitive types, and provides a set @@ -281,6 +282,22 @@ public final class PrimitiveType implements CodeGenerationDataNameType { public static boolean nextBoolean() { return RANDOM.nextBoolean(); } + + """, + CodeGenerationDataNameType.PRIMITIVE_TYPES.stream().map(type -> scope( + let("type", type), + """ + public static void fill(#type[] a) { + for (int i = 0; i < a.length; i++) { + """, + " a[i] = ", type.callLibraryRNG(), ";\n", + """ + } + } + """ + )).toList(), + """ + } """ )); diff --git a/test/hotspot/jtreg/compiler/lib/template_framework/library/Utils.java b/test/hotspot/jtreg/compiler/lib/template_framework/library/Utils.java new file mode 100644 index 00000000000..b96ad830a4b --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/template_framework/library/Utils.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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.lib.template_framework.library; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +/** + * Package private class with some helpful utility methods, used in multiple + * places of the template library. + */ +final class Utils { + @SafeVarargs + public static List concat(List... lists) { + return Arrays.stream(lists) + .flatMap(List::stream) + .collect(Collectors.toList()); + } +} diff --git a/test/hotspot/jtreg/compiler/lib/template_framework/library/VectorType.java b/test/hotspot/jtreg/compiler/lib/template_framework/library/VectorType.java new file mode 100644 index 00000000000..7eabd42a723 --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/template_framework/library/VectorType.java @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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.lib.template_framework.library; + +import java.util.List; +import java.util.stream.Stream; +import java.util.Random; +import jdk.test.lib.Utils; + +import compiler.lib.template_framework.DataName; +import static compiler.lib.template_framework.library.PrimitiveType.BYTES; +import static compiler.lib.template_framework.library.PrimitiveType.SHORTS; +import static compiler.lib.template_framework.library.PrimitiveType.INTS; +import static compiler.lib.template_framework.library.PrimitiveType.LONGS; +import static compiler.lib.template_framework.library.PrimitiveType.FLOATS; +import static compiler.lib.template_framework.library.PrimitiveType.DOUBLES; +import static compiler.lib.template_framework.library.PrimitiveType.BOOLEANS; + +/** + * The {@link VectorType} models the Vector API types. + */ +public abstract class VectorType implements CodeGenerationDataNameType { + private static final Random RANDOM = Utils.getRandomInstance(); + + public static final VectorType.Vector BYTE_64 = new VectorType.Vector(BYTES, 8); + public static final VectorType.Vector BYTE_128 = new VectorType.Vector(BYTES, 16); + public static final VectorType.Vector BYTE_256 = new VectorType.Vector(BYTES, 32); + public static final VectorType.Vector BYTE_512 = new VectorType.Vector(BYTES, 64); + + public static final VectorType.Vector SHORT_64 = new VectorType.Vector(SHORTS, 4); + public static final VectorType.Vector SHORT_128 = new VectorType.Vector(SHORTS, 8); + public static final VectorType.Vector SHORT_256 = new VectorType.Vector(SHORTS, 16); + public static final VectorType.Vector SHORT_512 = new VectorType.Vector(SHORTS, 32); + + public static final VectorType.Vector INT_64 = new VectorType.Vector(INTS, 2); + public static final VectorType.Vector INT_128 = new VectorType.Vector(INTS, 4); + public static final VectorType.Vector INT_256 = new VectorType.Vector(INTS, 8); + public static final VectorType.Vector INT_512 = new VectorType.Vector(INTS, 16); + + public static final VectorType.Vector LONG_64 = new VectorType.Vector(LONGS, 1); + public static final VectorType.Vector LONG_128 = new VectorType.Vector(LONGS, 2); + public static final VectorType.Vector LONG_256 = new VectorType.Vector(LONGS, 4); + public static final VectorType.Vector LONG_512 = new VectorType.Vector(LONGS, 8); + + public static final VectorType.Vector FLOAT_64 = new VectorType.Vector(FLOATS, 2); + public static final VectorType.Vector FLOAT_128 = new VectorType.Vector(FLOATS, 4); + public static final VectorType.Vector FLOAT_256 = new VectorType.Vector(FLOATS, 8); + public static final VectorType.Vector FLOAT_512 = new VectorType.Vector(FLOATS, 16); + + public static final VectorType.Vector DOUBLE_64 = new VectorType.Vector(DOUBLES, 1); + public static final VectorType.Vector DOUBLE_128 = new VectorType.Vector(DOUBLES, 2); + public static final VectorType.Vector DOUBLE_256 = new VectorType.Vector(DOUBLES, 4); + public static final VectorType.Vector DOUBLE_512 = new VectorType.Vector(DOUBLES, 8); + + private final String vectorTypeName; + + private VectorType(String vectorTypeName) { + this.vectorTypeName = vectorTypeName; + } + + @Override + public final String name() { + return vectorTypeName; + } + + @Override + public String toString() { + return name(); + } + + @Override + public boolean isSubtypeOf(DataName.Type other) { + // Each type has a unique instance. + return this == other; + } + + private static final String vectorTypeName(PrimitiveType elementType) { + return switch(elementType.name()) { + case "byte" -> "ByteVector"; + case "short" -> "ShortVector"; + case "char" -> throw new UnsupportedOperationException("VectorAPI has no char vector type"); + case "int" -> "IntVector"; + case "long" -> "LongVector"; + case "float" -> "FloatVector"; + case "double" -> "DoubleVector"; + default -> throw new UnsupportedOperationException("Not supported: " + elementType.name()); + }; + } + + public static final class Vector extends VectorType { + public final PrimitiveType elementType; + public final int length; // lane count + public final String speciesName; + + public final Mask maskType; + public final Shuffle shuffleType; + + private Vector(PrimitiveType elementType, int length) { + super(vectorTypeName(elementType)); + this.elementType = elementType; + this.length = length; + this.speciesName = name() + ".SPECIES_" + (byteSize() * 8); + this.maskType = new Mask(this); + this.shuffleType = new Shuffle(this); + } + + @Override + public final Object con() { + int r = RANDOM.nextInt(64); + if (r == 0) { + return List.of(name(), ".zero(", speciesName, ")"); + } else if (r <= 8) { + return List.of( + name(), ".fromArray(", speciesName, ", new ", elementType.name(), "[] {", + elementType.con(), + Stream.generate(() -> + List.of(", ", elementType.con()) + ).limit(length - 1).toList(), + "}, 0)" + ); + } else { + return List.of(name(), ".broadcast(", speciesName, ", ", elementType.con(), ")"); + } + } + + public int byteSize() { + return elementType.byteSize() * length; + } + } + + public static final class Mask extends VectorType { + public final Vector vectorType; + + private Mask(Vector vectorType) { + super("VectorMask<" + vectorType.elementType.boxedTypeName() + ">"); + this.vectorType = vectorType; + } + + @Override + public final Object con() { + int r = RANDOM.nextInt(64); + if (r <= 8) { + return List.of( + "VectorMask.fromArray(", vectorType.speciesName, ", new boolean[] {", + BOOLEANS.con(), + Stream.generate(() -> + List.of(", ", BOOLEANS.con()) + ).limit(vectorType.length - 1).toList(), + "}, 0)" + ); + } else if (r <= 16) { + return List.of( + "VectorMask.fromValues(", vectorType.speciesName, + Stream.generate(() -> + List.of(", ", BOOLEANS.con()) + ).limit(vectorType.length).toList(), + ")" + ); + } else if (r <= 24) { + // All true or all false + var tf = BOOLEANS.con(); + return List.of( + "VectorMask.fromValues(", vectorType.speciesName, + Stream.generate(() -> + List.of(", ", tf) + ).limit(vectorType.length).toList(), + ")" + ); + } else { + return List.of("VectorMask.fromLong(", vectorType.speciesName, ", ", LONGS.con(), ")"); + } + } + } + + public static final class Shuffle extends VectorType { + public final Vector vectorType; + + private Shuffle(Vector vectorType) { + super("VectorShuffle<" + vectorType.elementType.boxedTypeName() + ">"); + this.vectorType = vectorType; + } + + @Override + public final Object con() { + int r = RANDOM.nextInt(64); + if (r <= 8) { + return List.of( + "VectorShuffle.fromArray(", vectorType.speciesName, ", new int[] {", + INTS.con(), + Stream.generate(() -> + List.of(", ", INTS.con()) + ).limit(vectorType.length - 1).toList(), + "}, 0)" + ); + } else if (r <= 16) { + return List.of( + "VectorShuffle.fromValues(", vectorType.speciesName, + Stream.generate(() -> + List.of(", ", INTS.con()) + ).limit(vectorType.length).toList(), + ")" + ); + } else if (r <= 24) { + return List.of("VectorShuffle.makeZip(", vectorType.speciesName, ", ", RANDOM.nextInt(2), ")"); + } else if (r <= 32) { + return List.of("VectorShuffle.makeUnzip(", vectorType.speciesName, ", ", RANDOM.nextInt(2), ")"); + } else if (r <= 40) { + return List.of("VectorShuffle.fromOp(", vectorType.speciesName, ", i -> ", + INTS.con(), " + i * ", INTS.con(), " + i * i * ", INTS.con(), ")"); + } else { + return List.of("VectorShuffle.iota(", vectorType.speciesName, ", ", + INTS.con(), ", ", INTS.con(), ", true)"); + } + } + } +} diff --git a/test/hotspot/jtreg/compiler/vectorapi/VectorExpressionFuzzer.java b/test/hotspot/jtreg/compiler/vectorapi/VectorExpressionFuzzer.java new file mode 100644 index 00000000000..ea36cca4b92 --- /dev/null +++ b/test/hotspot/jtreg/compiler/vectorapi/VectorExpressionFuzzer.java @@ -0,0 +1,345 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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=AVX2 + * @bug 8369699 + * @key randomness + * @summary Test the Template Library's expression generation for the Vector API. + * @requires os.family == "linux" & os.simpleArch == "x64" + * @modules jdk.incubator.vector + * @modules java.base/jdk.internal.misc + * @library /test/lib / + * @compile ../../compiler/lib/verify/Verify.java + * @run driver ${test.main.class} -XX:UseAVX=2 + */ + +// TODO: remove the x64 and linux restriction above. I added that for now so we are not flooded +// with failures in the CI. We should remove these restriction once more bugs are fixed. +// x64 linux is the easiest to debug on for me, that's why I picked it. +// In addition, I put a UseAVX=2 restriction below, to avoid AVX512 bugs for now. +// +// A trick to extend this to other platforms: create a new run block, so you have full +// freedom to restrict it as necessary for platform and vector features. + +package compiler.vectorapi; + +import java.util.List; +import java.util.Arrays; +import java.util.ArrayList; +import java.util.Set; +import java.util.Random; +import jdk.test.lib.Utils; +import java.util.stream.IntStream; + +import compiler.lib.compile_framework.CompileFramework; + +import compiler.lib.template_framework.Template; +import compiler.lib.template_framework.TemplateToken; +import static compiler.lib.template_framework.Template.scope; +import static compiler.lib.template_framework.Template.let; +import static compiler.lib.template_framework.Template.$; +import compiler.lib.template_framework.library.CodeGenerationDataNameType; +import compiler.lib.template_framework.library.Expression; +import compiler.lib.template_framework.library.Expression.Nesting; +import compiler.lib.template_framework.library.Operations; +import compiler.lib.template_framework.library.TestFrameworkClass; +import compiler.lib.template_framework.library.PrimitiveType; +import compiler.lib.template_framework.library.VectorType; + +/** + * Basic Expression Fuzzer for Vector API. + */ +public class VectorExpressionFuzzer { + private static final Random RANDOM = Utils.getRandomInstance(); + + public static void main(String[] args) { + // Create a new CompileFramework instance. + CompileFramework comp = new CompileFramework(); + + // Add a java source file. + comp.addJavaSourceCode("compiler.vectorapi.templated.Templated", generate(comp)); + + // Compile the source file. + comp.compile("--add-modules=jdk.incubator.vector"); + + List vmArgs = new ArrayList<>(List.of( + "--add-modules=jdk.incubator.vector", + "--add-opens", "jdk.incubator.vector/jdk.incubator.vector=ALL-UNNAMED", + "--add-opens", "java.base/java.lang=ALL-UNNAMED" + )); + vmArgs.addAll(Arrays.asList(args)); // Forward args + String[] vmArgsArray = vmArgs.toArray(new String[0]); + + // compiler.vectorapi.templated.InnterTest.main(new String[] {}); + comp.invoke("compiler.vectorapi.templated.Templated", "main", new Object[] { vmArgsArray } ); + } + + // For Example 2 below. + record TestArgument( + Object defineAndFill, // used once: to define and fill the input value + Object passMethodArgument, // used twice: to pass argument to test and reference + Object receiveMethodArgument, // used twice: to receive argument in test and reference + Object use) {} // used twice: to use the value as expression argument + + // Generate a source Java file as String + public static String generate(CompileFramework comp) { + // Generate a list of test methods. + List tests = new ArrayList<>(); + + // We are going to use some random numbers in our tests, so import some good methods for that. + tests.add(PrimitiveType.generateLibraryRNG()); + + // Example 1: + // To start simple, we just call the expression with the same constant arguments + // every time. We can still compare the "gold" value obtained via interpreter with + // later results obtained from the compiled method. + var template1 = Template.make("type", (VectorType.Vector type) -> { + // The depth determines roughly how many operations are going to be used in the expression. + int depth = RANDOM.nextInt(1, 10); + Expression expression = Expression.nestRandomly(type, Operations.ALL_OPERATIONS, depth, Nesting.EXACT); + List expressionArguments = expression.argumentTypes.stream().map(CodeGenerationDataNameType::con).toList(); + return scope( + """ + // --- $test start --- + // Using $GOLD + // type: #type + + static final Object $GOLD = $test(); + + @Test + public static Object $test() { + try { + """, + " return ", expression.asToken(expressionArguments), ";\n", + expression.info.exceptions.stream().map(exception -> + " } catch (" + exception + " e) { return e;\n" + ).toList(), + """ + } finally { + // Just so javac is happy if there are no exceptions to catch. + } + } + + @Check(test = "$test") + public static void $check(Object result) { + """, + expression.info.isResultDeterministic + ? " Verify.checkEQ(result, $GOLD);\n" + : " // result not deterministic - don't verify.\n", + """ + } + + // --- $test end --- + """ + ); + }); + + // Example 2: + // Now a more complicated case. We want: + // - For every invocation of the test method, we want to have different inputs for the arguments. + // - We check correctness with a reference method that does the same but runs in the interpreter. + // - Input values are delivered via fields or array loads. + // - The final vector is written into an array, and that array is returned. + var template2Body = Template.make("expression", "arguments", (Expression expression, List arguments) -> scope( + let("elementType", ((VectorType.Vector)expression.returnType).elementType), + """ + try { + #elementType[] out = new #elementType[1000]; + """, + expression.asToken(arguments), ".intoArray(out, 0);\n", + "return out;\n", + expression.info.exceptions.stream().map(exception -> + "} catch (" + exception + " e) { return e;\n" + ).toList(), + """ + } finally { + // Just javac is happy if there are no exceptions to catch. + } + """ + )); + + var template2 = Template.make("type", (VectorType.Vector type) -> { + // The depth determines roughly how many operations are going to be used in the expression. + int depth = RANDOM.nextInt(1, 10); + Expression expression = Expression.nestRandomly(type, Operations.ALL_OPERATIONS, depth, Nesting.EXACT); + + List arguments = new ArrayList<>(); + for (int i = 0; i < expression.argumentTypes.size(); i++) { + String name = "arg_" + i; + CodeGenerationDataNameType argumentType = expression.argumentTypes.get(i); + switch(RANDOM.nextInt(4)) { + case 0 -> { + // Use the constant directly, no argument passing needed. + // To make the logic of passing arguments easy, we just pass null and receive an unused argument anyway. + arguments.add(new TestArgument( + "", + "null", + "Object unused_" + i, + argumentType.con() + )); + } + case 1 -> { + // Create the constant outside, and pass it. + arguments.add(new TestArgument( + List.of(argumentType.name(), " ", name, " = ", argumentType.con(), ";\n"), + name, + List.of(argumentType.name(), " ", name), + name + )); + } + default -> { + if (argumentType instanceof PrimitiveType t) { + // We can use the LibraryRGN to create a new value for the primitive in each + // invocation. We have to make sure to call the LibraryRNG in the "defineAndFill", + // so we get the same value for both test and reference. If we called LibraryRNG + // for "use", we would get separate values, which is not helpful. + arguments.add(new TestArgument( + List.of(t.name(), " ", name, " = ", t.callLibraryRNG(), ";\n"), + name, + List.of(t.name(), " ", name), + name + )); + } else if (argumentType instanceof VectorType.Vector t) { + PrimitiveType et = t.elementType; + arguments.add(new TestArgument( + List.of(et.name(), "[] ", name, " = new ", et.name(), "[1000];\n", + "LibraryRNG.fill(", name,");\n"), + name, + List.of(et.name(), "[] ", name), + List.of(t.name(), ".fromArray(", t.speciesName, ", ", name, ", 0)") + )); + } else if (argumentType instanceof VectorType.Mask t) { + arguments.add(new TestArgument( + List.of("boolean[] ", name, " = new boolean[1000];\n", + "LibraryRNG.fill(", name,");\n"), + name, + List.of("boolean[] ", name), + List.of("VectorMask.fromArray(", t.vectorType.speciesName, ", ", name, ", 0)") + )); + } else if (argumentType instanceof VectorType.Shuffle t) { + arguments.add(new TestArgument( + List.of("int[] ", name, " = new int[1000];\n", + "LibraryRNG.fill(", name,");\n"), + name, + List.of("int[] ", name), + List.of("VectorShuffle.fromArray(", t.vectorType.speciesName, ", ", name, ", 0)") + )); + } else { + // We don't know anything special how to create different values + // each time, so let's just crate the same constant each time. + arguments.add(new TestArgument( + List.of(argumentType.name(), " ", name, " = ", argumentType.con(), ";\n"), + name, + List.of(argumentType.name(), " ", name), + name + )); + } + } + } + } + + // "join" together the arguments to make a comma separated list. + List passArguments = IntStream.range(0, arguments.size() * 2 - 1).mapToObj(i -> + (i % 2 == 0) ? arguments.get(i / 2).passMethodArgument() : ", " + ).toList(); + List receiveArguments = IntStream.range(0, arguments.size() * 2 - 1).mapToObj(i -> + (i % 2 == 0) ? arguments.get(i / 2).receiveMethodArgument() : ", " + ).toList(); + + List useArguments = arguments.stream().map(TestArgument::use).toList(); + + return scope( + """ + // --- $test start --- + // type: #type + + @Run(test = "$test") + public void $run() { + """, + arguments.stream().map(TestArgument::defineAndFill).toList(), + """ + Object v0 = $test( + """, + passArguments, + """ + ); + Object v1 = $reference( + """, + passArguments, + """ + ); + """, + expression.info.isResultDeterministic + ? "Verify.checkEQ(v0, v1);\n" + : "// result not deterministic - don't verify.\n", + """ + } + + @Test + public static Object $test( + """, + receiveArguments, + """ + ) { + """, + template2Body.asToken(expression, useArguments), + """ + } + + @DontCompile + public static Object $reference( + """, + receiveArguments, + """ + ) { + """, + template2Body.asToken(expression, useArguments), + """ + } + // --- $test end --- + """ + ); + }); + + for (VectorType.Vector type : CodeGenerationDataNameType.VECTOR_VECTOR_TYPES) { + tests.add(template1.asToken(type)); + tests.add(template2.asToken(type)); + } + + // Create the test class, which runs all tests. + return TestFrameworkClass.render( + // package and class name. + "compiler.vectorapi.templated", "Templated", + // Set of imports. + Set.of("compiler.lib.verify.*", + "java.util.Random", + "jdk.test.lib.Utils", + "compiler.lib.generators.*", + "jdk.incubator.vector.*"), + // classpath, so the Test VM has access to the compiled class files. + comp.getEscapedClassPathOfCompiledClasses(), + // The list of tests. + tests); + } +} diff --git a/test/hotspot/jtreg/testlibrary_tests/template_framework/examples/TestExpressions.java b/test/hotspot/jtreg/testlibrary_tests/template_framework/examples/TestExpressions.java index 4bec633553b..8e87985e3d3 100644 --- a/test/hotspot/jtreg/testlibrary_tests/template_framework/examples/TestExpressions.java +++ b/test/hotspot/jtreg/testlibrary_tests/template_framework/examples/TestExpressions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * 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,8 @@ /* * @test - * @bug 8359412 8370922 + * @bug 8359412 8370922 8369699 + * @key randomness * @summary Demonstrate the use of Expressions from the Template Library. * @modules java.base/jdk.internal.misc * @modules jdk.incubator.vector @@ -37,6 +38,8 @@ package template_framework.examples; import java.util.List; import java.util.ArrayList; import java.util.Set; +import java.util.Random; +import jdk.test.lib.Utils; import compiler.lib.compile_framework.*; import compiler.lib.template_framework.Template; @@ -48,6 +51,8 @@ import compiler.lib.template_framework.library.Operations; import compiler.lib.template_framework.library.TestFrameworkClass; public class TestExpressions { + private static final Random RANDOM = Utils.getRandomInstance(); + public static void main(String[] args) { // Create a new CompileFramework instance. CompileFramework comp = new CompileFramework(); @@ -126,16 +131,26 @@ public class TestExpressions { ); }); + // The scalar operations are very important and we would like to always test them all. for (Expression operation : Operations.SCALAR_NUMERIC_OPERATIONS) { tests.add(withConstantsTemplate.asToken(operation)); } + // There are a LOT of instructions, especially a lot of vector instructions. + // A bit too many to run them all in an individual test. + // So let's just sample some at random. + for (int i = 0; i < 100; i++) { + int r = RANDOM.nextInt(Operations.ALL_OPERATIONS.size()); + Expression operation = Operations.ALL_OPERATIONS.get(r); + tests.add(withConstantsTemplate.asToken(operation)); + } + // Create the test class, which runs all tests. return TestFrameworkClass.render( // package and class name. "p.xyz", "InnerTest", // Set of imports. - Set.of("compiler.lib.verify.*", "jdk.incubator.vector.Float16"), + Set.of("compiler.lib.verify.*", "jdk.incubator.vector.*"), // classpath, so the Test VM has access to the compiled class files. comp.getEscapedClassPathOfCompiledClasses(), // The list of tests. diff --git a/test/hotspot/jtreg/testlibrary_tests/template_framework/examples/TestPrimitiveTypes.java b/test/hotspot/jtreg/testlibrary_tests/template_framework/examples/TestPrimitiveTypes.java index facaefaa8f3..861298c7da7 100644 --- a/test/hotspot/jtreg/testlibrary_tests/template_framework/examples/TestPrimitiveTypes.java +++ b/test/hotspot/jtreg/testlibrary_tests/template_framework/examples/TestPrimitiveTypes.java @@ -254,6 +254,18 @@ public class TestPrimitiveTypes { } if (allSame) { throw new RuntimeException("all values were the same for #type"); } } + { + #type[] a = new #type[1_000]; + LibraryRNG.fill(a); + boolean allSame = true; + for (int i = 0; i < a.length; i++) { + if (a[i] != a[0]) { + allSame = false; + break; + } + } + if (allSame) { throw new RuntimeException("all values were the same for #type"); } + } """ )); diff --git a/test/hotspot/jtreg/testlibrary_tests/template_framework/examples/TestVectorTypes.java b/test/hotspot/jtreg/testlibrary_tests/template_framework/examples/TestVectorTypes.java new file mode 100644 index 00000000000..554cdc1094c --- /dev/null +++ b/test/hotspot/jtreg/testlibrary_tests/template_framework/examples/TestVectorTypes.java @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8358772 + * @summary Demonstrate the use of VectorTypes (Vector API) form the Template Library. + * @modules java.base/jdk.internal.misc + * @modules jdk.incubator.vector + * @library /test/lib / + * @compile ../../../compiler/lib/verify/Verify.java + * @run main ${test.main.class} + */ + +package template_framework.examples; + +import java.util.List; +import java.util.ArrayList; +import java.util.Set; + +import compiler.lib.compile_framework.*; +import compiler.lib.template_framework.Template; +import compiler.lib.template_framework.TemplateToken; +import static compiler.lib.template_framework.Template.scope; +import static compiler.lib.template_framework.Template.let; +import static compiler.lib.template_framework.Template.$; + +import compiler.lib.template_framework.library.CodeGenerationDataNameType; +import compiler.lib.template_framework.library.VectorType; +import compiler.lib.template_framework.library.TestFrameworkClass; + +/** + * This test shows the use of {@link VectorType}. + */ +public class TestVectorTypes { + + public static void main(String[] args) { + // Create a new CompileFramework instance. + CompileFramework comp = new CompileFramework(); + + // Add a java source file. + comp.addJavaSourceCode("p.xyz.InnerTest", generate(comp)); + + // Compile the source file. + comp.compile("--add-modules=jdk.incubator.vector"); + + // p.xyz.InnerTest.main(); + comp.invoke("p.xyz.InnerTest", "main", new Object[] {new String[] { + "--add-modules=jdk.incubator.vector", + "--add-opens", "jdk.incubator.vector/jdk.incubator.vector=ALL-UNNAMED", + "--add-opens", "java.base/java.lang=ALL-UNNAMED" + }}); + } + + // Generate a Java source file as String + public static String generate(CompileFramework comp) { + // Generate a list of test methods. + List tests = new ArrayList<>(); + + var vectorTemplate = Template.make("type", (VectorType.Vector type) -> { + return scope( + let("elementType", type.elementType), + let("length", type.length), + let("SPECIES", type.speciesName), + let("maskType", type.maskType), + let("shuffleType", type.shuffleType), + """ + // #type #elementType #length #SPECIES + @Test + public static void $test() { + """, + " #elementType scalar = ", type.elementType.con(), ";\n", + " #maskType mask = ", type.maskType.con(), ";\n", + " #shuffleType shuffle = ", type.shuffleType.con(), ";\n", + """ + #type zeros = #{type}.zero(#SPECIES); + #type zeros2 = #{type}.broadcast(#SPECIES, 0); + #type vector = #{type}.broadcast(#SPECIES, scalar); + Verify.checkEQ(zeros, zeros2); + Verify.checkEQ(zeros.add(vector), vector.add(zeros)); + Verify.checkEQ(vector.length(), #length); + Verify.checkEQ(vector.lane(#length-1), scalar); + + #type v1 = zeros.blend(vector, mask); + #type v2 = vector.blend(zeros, mask.not()); + Verify.checkEQ(v1, v2); + + #type iota = zeros.addIndex(1); + #type v3 = iota.rearrange(iota.toShuffle()); + Verify.checkEQ(iota, v3); + #type v4 = iota.rearrange(shuffle); + Verify.checkEQ(shuffle.wrapIndexes(), v4.toShuffle()); + Verify.checkEQ(shuffle.wrapIndexes().toVector(), v4); + } + """ + ); + }); + + for (var type : CodeGenerationDataNameType.VECTOR_VECTOR_TYPES) { + tests.add(vectorTemplate.asToken(type)); + } + + // Create the test class, which runs all tests. + return TestFrameworkClass.render( + // package and class name. + "p.xyz", "InnerTest", + // Set of imports. + Set.of("compiler.lib.verify.*", "jdk.incubator.vector.*"), + // classpath, so the Test VM has access to the compiled class files. + comp.getEscapedClassPathOfCompiledClasses(), + // The list of tests. + tests); + } +} From ba0aefba9cd558cf41c26f68e9d9668d9198d3c6 Mon Sep 17 00:00:00 2001 From: Vladimir Kozlov Date: Fri, 3 Apr 2026 15:58:48 +0000 Subject: [PATCH 171/359] 8381596: Adjust checks which use supports_ht() on x86 for hybrid CPUs Reviewed-by: iklam, iveresov --- src/hotspot/cpu/x86/vm_version_x86.cpp | 6 +++--- src/hotspot/cpu/x86/vm_version_x86.hpp | 6 ++++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/hotspot/cpu/x86/vm_version_x86.cpp b/src/hotspot/cpu/x86/vm_version_x86.cpp index a77105efbbf..fc4cfbc5a8b 100644 --- a/src/hotspot/cpu/x86/vm_version_x86.cpp +++ b/src/hotspot/cpu/x86/vm_version_x86.cpp @@ -1647,7 +1647,7 @@ void VM_Version::get_processor_features() { } #endif // COMPILER2 - if ((supports_sse4_2() && supports_ht()) || supports_avx()) { // Newest Intel cpus + if (is_intel_modern_cpu()) { // Newest Intel cpus if (FLAG_IS_DEFAULT(UseUnalignedLoadStores)) { UseUnalignedLoadStores = true; // use movdqu on newest Intel cpus } @@ -1883,7 +1883,7 @@ void VM_Version::get_processor_features() { if (is_intel() && is_intel_server_family() && supports_sse3()) { if (FLAG_IS_DEFAULT(AllocatePrefetchLines) && - supports_sse4_2() && supports_ht()) { // Nehalem based cpus + is_intel_modern_cpu()) { // Nehalem based cpus FLAG_SET_DEFAULT(AllocatePrefetchLines, 4); } #ifdef COMPILER2 @@ -3316,7 +3316,7 @@ int VM_Version::allocate_prefetch_distance(bool use_watermark_prefetch) { } } else { // Intel if (supports_sse3() && is_intel_server_family()) { - if (supports_sse4_2() && supports_ht()) { // Nehalem based cpus + if (is_intel_modern_cpu()) { // Nehalem based cpus return 192; } else if (use_watermark_prefetch) { // watermark prefetching on Core return 384; diff --git a/src/hotspot/cpu/x86/vm_version_x86.hpp b/src/hotspot/cpu/x86/vm_version_x86.hpp index a42558a8023..4f3580d216c 100644 --- a/src/hotspot/cpu/x86/vm_version_x86.hpp +++ b/src/hotspot/cpu/x86/vm_version_x86.hpp @@ -958,6 +958,12 @@ public: static bool is_intel_darkmont(); + static bool is_intel_modern_cpu() { + precond(is_intel()); // should be called only for intel CPU + // Efficient cores in hybrid CPU may not support hyper-threads. + return (supports_avx() || (supports_sse4_2() && (supports_ht() || supports_hybrid()))); + } + static bool is_intel_tsc_synched_at_init(); static void insert_features_names(VM_Version::VM_Features features, stringStream& ss); From 0c98ab8dc9736f73a5fde2247ca335c1b12075c7 Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Fri, 3 Apr 2026 16:24:59 +0000 Subject: [PATCH 172/359] 8380936: Cleanup temp dir usage in ZipFSTester Reviewed-by: jpai --- test/jdk/jdk/nio/zipfs/ZipFSTester.java | 591 +++++++++++++----------- 1 file changed, 326 insertions(+), 265 deletions(-) diff --git a/test/jdk/jdk/nio/zipfs/ZipFSTester.java b/test/jdk/jdk/nio/zipfs/ZipFSTester.java index 9d70350272f..2ca4686ff14 100644 --- a/test/jdk/jdk/nio/zipfs/ZipFSTester.java +++ b/test/jdk/jdk/nio/zipfs/ZipFSTester.java @@ -30,11 +30,13 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.URI; +import java.net.URISyntaxException; import java.net.URLDecoder; import java.nio.ByteBuffer; import java.nio.channels.Channels; import java.nio.channels.FileChannel; import java.nio.channels.SeekableByteChannel; +import java.nio.charset.StandardCharsets; import java.nio.file.DirectoryStream; import java.nio.file.FileAlreadyExistsException; import java.nio.file.FileStore; @@ -56,8 +58,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Enumeration; -import java.util.HashMap; -import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; @@ -73,6 +73,7 @@ import java.util.zip.ZipOutputStream; import static java.nio.file.StandardOpenOption.*; import static java.nio.file.StandardCopyOption.*; import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotEquals; @@ -116,9 +117,9 @@ public class ZipFSTester { } @Test - void test0() throws Exception { + void entryParentTest() throws Exception { List list = new LinkedList<>(); - try (var fs = newZipFileSystem(jarFile, Map.of()); + try (var fs = FileSystems.newFileSystem(jarFile, Map.of()); ZipFile zf = new ZipFile(fs.toString())) { Enumeration zes = zf.entries(); while (zes.hasMoreElements()) { @@ -134,25 +135,177 @@ public class ZipFSTester { } } + // Validates ZipFS provider for expected UOE on directory and non-zip file input @Test - void test1() throws Exception { - // prepare a src for testing - Path src = getTempPath(); - String tmpName = src.toString(); - try (OutputStream os = Files.newOutputStream(src)) { - byte[] bits = new byte[12345]; - RDM.nextBytes(bits); - os.write(bits); + void providerValidationUOETest() throws Exception { + var nonZipFile = getNonZipFile(); + var tmpfsPath = getTempZipPath(); + createClonedZip(tmpfsPath); + try (FileSystem fs = FileSystems.newFileSystem(pathToJarURI(tmpfsPath), Map.of())) { + FileSystemProvider provider = fs.provider(); + assertThrows(UnsupportedOperationException.class, + () -> provider.newFileSystem(new File(System.getProperty("test.src", ".")).toPath(), + Map.of()), "newFileSystem() opens a directory as zipfs"); + assertThrows(UnsupportedOperationException.class, + () -> provider.newFileSystem(nonZipFile, Map.of()), + "newFileSystem() opens a non-zip file as zipfs"); + } finally { + Files.deleteIfExists(tmpfsPath); + Files.deleteIfExists(nonZipFile); } + } - // clone a fs from fs0 and test on it - Path tmpfsPath = getTempPath(); - Map env = new HashMap(); - env.put("create", "true"); - try (var fs = newZipFileSystem(jarFile, Map.of()); - FileSystem copy = newZipFileSystem(tmpfsPath, env)) { + // Validates ZipFS provider for expected FSAE on duplicate input + @Test + void providerValidationFSAETest() throws Exception { + var tmpfsPath = getTempZipPath(); + createClonedZip(tmpfsPath); + try (FileSystem fs = FileSystems.newFileSystem(pathToJarURI(tmpfsPath), Map.of())) { + FileSystemProvider provider = fs.provider(); + assertThrows(FileSystemAlreadyExistsException.class, + () -> provider.newFileSystem(pathToJarURI(tmpfsPath), + Map.of()), "newFileSystem(URI...) does not throw exception"); + } finally { + Files.deleteIfExists(tmpfsPath); + } + } + + // Validates ZipFS provider for newFileSystem(Path, ...) + @Test + void providerValidationTest() throws Exception { + var tmpfsPath = getTempZipPath(); + createClonedZip(tmpfsPath); + try (FileSystem fs = FileSystems.newFileSystem(pathToJarURI(tmpfsPath), Map.of())) { + FileSystemProvider provider = fs.provider(); + try (FileSystem _ = provider.newFileSystem(tmpfsPath, Map.of())) {} + } finally { + Files.deleteIfExists(tmpfsPath); + } + } + + // Performs a sequence of operations where subsequent ops depend on previous state. + // Covers ops such as `copy`, `delete`, `move` + @Test + void entryCopyMoveDeleteFlowTest() throws Exception { + var src = getFile(); + Path tmpfsPath = getTempZipPath(); + createClonedZip(tmpfsPath); + try (FileSystem fs = FileSystems.newFileSystem(pathToJarURI(tmpfsPath), Map.of())) { + // walk + walk(fs.getPath("/")); + // copyin + Path dst = getPathWithParents(fs, src.toString()); + Files.copy(src, dst); + checkEqual(src, dst); + // copy + Path dst2 = getPathWithParents(fs, "/xyz" + RDM.nextInt(100) + + "/efg" + RDM.nextInt(100) + "/foo.class"); + Files.copy(dst, dst2); + // dst.moveTo(dst2); + checkEqual(src, dst2); + // delete + Files.delete(dst); + assertFalse(Files.exists(dst)); + // moveout + Path dst3 = Paths.get(src + "_Tmp"); + Files.move(dst2, dst3); + checkEqual(src, dst3); + assertFalse(Files.exists(dst2)); + // copyback + move + Files.copy(dst3, dst); + Path dst4 = getPathWithParents(fs, src + "_Tmp0"); + Files.move(dst, dst4); + checkEqual(src, dst4); + // delete + Files.delete(dst4); + assertFalse(Files.exists(dst4)); + Files.delete(dst3); + assertFalse(Files.exists(dst3)); + } finally { + Files.deleteIfExists(tmpfsPath); + Files.deleteIfExists(src); + } + } + + // Verify existing entry can be renamed within zfs + @Test + void existingEntryMoveTest() throws Exception { + Path tmpfsPath = getTempZipPath(); + createClonedZip(tmpfsPath); + try (FileSystem fs = FileSystems.newFileSystem(pathToJarURI(tmpfsPath), Map.of())) { + // move (existing entry) + Path manifest = fs.getPath("META-INF/MANIFEST.MF"); + if (Files.exists(manifest)) { + Path movedManifest = fs.getPath("META-INF/MANIFEST.MF_TMP"); + Files.move(manifest, movedManifest); + // Ensure the move operation was successful + assertFalse(Files.exists(manifest)); + assertTrue(Files.exists(movedManifest)); + walk(fs.getPath("/")); + } else { + fail("Unexpected failure, manifest does not exist"); + } + } finally { + Files.deleteIfExists(tmpfsPath); + } + } + + // Verify some directory behavior: open dir as stream fails, correct cleanup of empty parent dir + @Test + void directoryOpsTest() throws Exception { + var src = getFile(); + Path tmpfsPath = getTempZipPath(); + createClonedZip(tmpfsPath); + try (FileSystem fs = FileSystems.newFileSystem(pathToJarURI(tmpfsPath), Map.of())) { + Path pathWithParents = getPathWithParents(fs, "/xyz" + RDM.nextInt(100) + + "/efg" + RDM.nextInt(100) + "/foo.class"); + Files.copy(src, pathWithParents); + // Invoking `newInputStream` on directory should fail + Path parent = pathWithParents.getParent(); + assertThrows(FileSystemException.class, () -> Files.newInputStream(parent)); + Files.delete(pathWithParents); + // Clean up directory (when nested child is removed) + assertDoesNotThrow(() -> rmdirs(parent)); + assertFalse(Files.exists(parent)); + } finally { + Files.deleteIfExists(tmpfsPath); + Files.deleteIfExists(src); + } + } + + // Verify some channel ops + @Test + void channelTest() throws Exception { + var src = getFile(); + Path tmpfsPath = getTempZipPath(); + createClonedZip(tmpfsPath); + try (FileSystem fs = FileSystems.newFileSystem(pathToJarURI(tmpfsPath), Map.of())) { + Path dst = getPathWithParents(fs, src.toString()); + // newFileChannel() copy in, out and verify via fch + fchCopy(src, dst); // in + checkEqual(src, dst); + Path tmp = Paths.get(src + "_Tmp"); + fchCopy(dst, tmp); // out + checkEqual(src, tmp); + Files.delete(tmp); + // test channels + channel(fs, dst); + Files.delete(dst); + } finally { + Files.deleteIfExists(tmpfsPath); + Files.deleteIfExists(src); + } + } + + // Verify ZipFS can operate on nested zip file entry in another zip + @Test + void nestedZipContentsTest() throws Exception { + // Set up the nested behavior + var src = getFile(); + Path tmpfsPath = getTempZipPath(); + try (var fs = FileSystems.newFileSystem(jarFile, Map.of()); + FileSystem copy = FileSystems.newFileSystem(tmpfsPath, Map.of("create", "true"))) { z2zcopy(fs, copy, "/", 0); - // copy the test jar itself in Files.copy(Paths.get(fs.toString()), copy.getPath("/foo.jar")); Path zpath = copy.getPath("/foo.jar"); @@ -160,106 +313,21 @@ public class ZipFSTester { Files.copy(src, zzfs.getPath("/srcInjarjar")); } } - - try (FileSystem fs = newZipFileSystem(tmpfsPath, new HashMap())) { - - FileSystemProvider provider = fs.provider(); - // newFileSystem(path...) should not throw exception - try (FileSystem fsPath = provider.newFileSystem(tmpfsPath, new HashMap())){} - assertThrows(FileSystemAlreadyExistsException.class, - () -> provider.newFileSystem(new URI("jar", tmpfsPath.toUri().toString(), null), - new HashMap<>()), "newFileSystem(URI...) does not throw exception"); - assertThrows(UnsupportedOperationException.class, - () -> provider.newFileSystem(new File(System.getProperty("test.src", ".")).toPath(), - new HashMap<>()), "newFileSystem() opens a directory as zipfs"); - assertThrows(UnsupportedOperationException.class, - () -> provider.newFileSystem(src, new HashMap()), - "newFileSystem() opens a non-zip file as zipfs"); - - // walk - walk(fs.getPath("/")); - - // copyin - Path dst = getPathWithParents(fs, tmpName); - Files.copy(src, dst); - checkEqual(src, dst); - - // copy - Path dst2 = getPathWithParents(fs, "/xyz" + RDM.nextInt(100) + - "/efg" + RDM.nextInt(100) + "/foo.class"); - Files.copy(dst, dst2); - //dst.moveTo(dst2); - checkEqual(src, dst2); - - // delete - Files.delete(dst); - assertFalse(Files.exists(dst)); - - // moveout - Path dst3 = Paths.get(tmpName + "_Tmp"); - Files.move(dst2, dst3); - checkEqual(src, dst3); - assertFalse(Files.exists(dst2)); - - // copyback + move - Files.copy(dst3, dst); - Path dst4 = getPathWithParents(fs, tmpName + "_Tmp0"); - Files.move(dst, dst4); - checkEqual(src, dst4); - - // delete - Files.delete(dst4); - assertFalse(Files.exists(dst4)); - Files.delete(dst3); - assertFalse(Files.exists(dst3)); - - // move (existing entry) - Path dst5 = fs.getPath("META-INF/MANIFEST.MF"); - if (Files.exists(dst5)) { - Path dst6 = fs.getPath("META-INF/MANIFEST.MF_TMP"); - Files.move(dst5, dst6); - walk(fs.getPath("/")); - } - - // newInputStream on dir - Path parent = dst2.getParent(); - assertThrows(FileSystemException.class, () -> Files.newInputStream(parent)); - - // rmdirs - try { - rmdirs(parent); - } catch (IOException x) { - x.printStackTrace(); - } - - // newFileChannel() copy in, out and verify via fch - fchCopy(src, dst); // in - checkEqual(src, dst); - Path tmp = Paths.get(tmpName + "_Tmp"); - fchCopy(dst, tmp); // out - checkEqual(src, tmp); - Files.delete(tmp); - - // test channels - channel(fs, dst); - Files.delete(dst); - + // Assertions + try (FileSystem fs = FileSystems.newFileSystem(pathToJarURI(tmpfsPath), Map.of())) { // test foo.jar in jar/zipfs #8034802 Path jpath = fs.getPath("/foo.jar"); - System.out.println("walking: " + jpath); try (FileSystem zzfs = FileSystems.newFileSystem(jpath)) { walk(zzfs.getPath("/")); // foojar:/srcInjarjar checkEqual(src, zzfs.getPath("/srcInjarjar")); - - dst = getPathWithParents(zzfs, tmpName); + var dst = getPathWithParents(zzfs, src.toString()); fchCopy(src, dst); checkEqual(src, dst); - tmp = Paths.get(tmpName + "_Tmp"); + Path tmp = Paths.get(src + "_Tmp"); fchCopy(dst, tmp); // out checkEqual(src, tmp); Files.delete(tmp); - channel(zzfs, dst); Files.delete(dst); } @@ -270,100 +338,86 @@ public class ZipFSTester { } @Test - void test2() throws Exception { - Path fs1Path = getTempPath(); - Path fs2Path = getTempPath(); - Path fs3Path = getTempPath(); + void concurrentCopyTest() throws Exception { + Path fs1Path = getTempZipPath(); + Path fs2Path = getTempZipPath(); + Path fs3Path = getTempZipPath(); // create a new filesystem, copy everything from fs - Map env = new HashMap(); - env.put("create", "true"); - FileSystem fs0 = newZipFileSystem(fs1Path, env); + var env = Map.of("create", "true"); + FileSystem fs0 = FileSystems.newFileSystem(fs1Path, env); - final FileSystem fs2 = newZipFileSystem(fs2Path, env); - final FileSystem fs3 = newZipFileSystem(fs3Path, env); + final FileSystem fs2 = FileSystems.newFileSystem(fs2Path, env); + final FileSystem fs3 = FileSystems.newFileSystem(fs3Path, env); System.out.println("copy src: fs -> fs0..."); - try (var fs = newZipFileSystem(jarFile, Map.of())) { + try (var fs = FileSystems.newFileSystem(jarFile, Map.of())) { z2zcopy(fs, fs0, "/", 0); // copy fs -> fs1 fs0.close(); // dump to file System.out.println("open fs0 as fs1"); - env = new HashMap(); - final FileSystem fs1 = newZipFileSystem(fs1Path, env); + final FileSystem fs1 = FileSystems.newFileSystem(fs1Path, Map.of()); System.out.println("listing..."); final ArrayList files = new ArrayList<>(); final ArrayList dirs = new ArrayList<>(); list(fs1.getPath("/"), files, dirs); - Thread t0 = new Thread(new Runnable() { - public void run() { - List list = new ArrayList<>(dirs); - Collections.shuffle(list); - for (String path : list) { - try { - z2zcopy(fs1, fs2, path, 0); - } catch (Exception x) { - x.printStackTrace(); - } + Thread t0 = new Thread(() -> { + List list = new ArrayList<>(dirs); + Collections.shuffle(list); + for (String path : list) { + try { + z2zcopy(fs1, fs2, path, 0); + } catch (Exception x) { + x.printStackTrace(); } } - }); - Thread t1 = new Thread(new Runnable() { - public void run() { - List list = new ArrayList<>(dirs); - Collections.shuffle(list); - for (String path : list) { - try { - z2zcopy(fs1, fs2, path, 1); - } catch (Exception x) { - x.printStackTrace(); - } + Thread t1 = new Thread(() -> { + List list = new ArrayList<>(dirs); + Collections.shuffle(list); + for (String path : list) { + try { + z2zcopy(fs1, fs2, path, 1); + } catch (Exception x) { + x.printStackTrace(); } } - }); - Thread t2 = new Thread(new Runnable() { - public void run() { - List list = new ArrayList<>(dirs); - Collections.shuffle(list); - for (String path : list) { - try { - z2zcopy(fs1, fs2, path, 2); - } catch (Exception x) { - x.printStackTrace(); - } + Thread t2 = new Thread(() -> { + List list = new ArrayList<>(dirs); + Collections.shuffle(list); + for (String path : list) { + try { + z2zcopy(fs1, fs2, path, 2); + } catch (Exception x) { + x.printStackTrace(); } } - }); - Thread t3 = new Thread(new Runnable() { - public void run() { - List list = new ArrayList<>(files); - Collections.shuffle(list); - while (!list.isEmpty()) { - Iterator itr = list.iterator(); - while (itr.hasNext()) { - String path = itr.next(); - try { - if (Files.exists(fs2.getPath(path))) { - z2zmove(fs2, fs3, path); - itr.remove(); - } - } catch (FileAlreadyExistsException x) { + Thread t3 = new Thread(() -> { + List list = new ArrayList<>(files); + Collections.shuffle(list); + while (!list.isEmpty()) { + Iterator itr = list.iterator(); + while (itr.hasNext()) { + String path = itr.next(); + try { + if (Files.exists(fs2.getPath(path))) { + z2zmove(fs2, fs3, path); itr.remove(); - } catch (Exception x) { - x.printStackTrace(); } + } catch (FileAlreadyExistsException x) { + itr.remove(); + } catch (Exception x) { + x.printStackTrace(); } } } - }); System.out.println("copying/removing..."); @@ -394,7 +448,7 @@ public class ZipFSTester { fs3.close(); System.out.println("opening: fs3 as fs4"); - FileSystem fs4 = newZipFileSystem(fs3Path, env); + FileSystem fs4 = FileSystems.newFileSystem(fs3Path, Map.of()); ArrayList files2 = new ArrayList<>(); @@ -503,7 +557,7 @@ public class ZipFSTester { // test entry stream/channel reading @Test void testStreamChannel() throws Exception { - Path zpath = getTempPath(); + Path zpath = getTempZipPath(); try { var crc = new CRC32(); Object[][] entries = getEntries(); @@ -527,7 +581,7 @@ public class ZipFSTester { zos.closeEntry(); } } - try (var zfs = newZipFileSystem(zpath, Map.of())) { + try (var zfs = FileSystems.newFileSystem(zpath, Map.of())) { for (Object[] e : entries) { Path path = zfs.getPath((String)e[0]); byte[] bytes = (byte[])e[2]; @@ -537,7 +591,7 @@ public class ZipFSTester { Files.deleteIfExists(zpath); // [2] create zip via zfs.newByteChannel - try (var zfs = newZipFileSystem(zpath, Map.of("create", "true"))) { + try (var zfs = FileSystems.newFileSystem(zpath, Map.of("create", "true"))) { for (Object[] e : entries) { // tbd: method is not used try (var sbc = Files.newByteChannel(zfs.getPath((String)e[0]), @@ -546,7 +600,7 @@ public class ZipFSTester { } } } - try (var zfs = newZipFileSystem(zpath, Map.of())) { + try (var zfs = FileSystems.newFileSystem(zpath, Map.of())) { for (Object[] e : entries) { checkRead(zfs.getPath((String)e[0]), (byte[])e[2]); } @@ -554,12 +608,12 @@ public class ZipFSTester { Files.deleteIfExists(zpath); // [3] create zip via Files.write()/newoutputStream/ - try (var zfs = newZipFileSystem(zpath, Map.of("create", "true"))) { + try (var zfs = FileSystems.newFileSystem(zpath, Map.of("create", "true"))) { for (Object[] e : entries) { Files.write(zfs.getPath((String)e[0]), (byte[])e[2]); } } - try (var zfs = newZipFileSystem(zpath, Map.of())) { + try (var zfs = FileSystems.newFileSystem(zpath, Map.of())) { for (Object[] e : entries) { checkRead(zfs.getPath((String)e[0]), (byte[])e[2]); } @@ -567,7 +621,7 @@ public class ZipFSTester { Files.deleteIfExists(zpath); // [4] create zip via zfs.newByteChannel, with "method_stored" - try (var zfs = newZipFileSystem(zpath, + try (var zfs = FileSystems.newFileSystem(zpath, Map.of("create", true, "noCompression", true))) { for (Object[] e : entries) { try (var sbc = Files.newByteChannel(zfs.getPath((String)e[0]), @@ -576,7 +630,7 @@ public class ZipFSTester { } } } - try (var zfs = newZipFileSystem(zpath, Map.of())) { + try (var zfs = FileSystems.newFileSystem(zpath, Map.of())) { for (Object[] e : entries) { checkRead(zfs.getPath((String)e[0]), (byte[])e[2]); } @@ -596,7 +650,7 @@ public class ZipFSTester { .getFileAttributeView(jar, BasicFileAttributeView.class) .readAttributes(); // create a new filesystem, copy this file into it - Path fsPath = getTempPath(); + Path fsPath = getTempZipPath(); try (FileSystem fs = FileSystems.newFileSystem(fsPath, Map.of("create", "true"))) { System.out.println("test copy with timestamps..."); // copyin @@ -630,20 +684,18 @@ public class ZipFSTester { @Test void test8069211() throws Exception { // create a new filesystem, copy this file into it - Map env = new HashMap(); - env.put("create", "true"); - Path fsPath = getTempPath(); - try (FileSystem fs = newZipFileSystem(fsPath, env);) { + Path fsPath = getTempZipPath(); + try (FileSystem fs = FileSystems.newFileSystem(fsPath, Map.of("create", "true"))) { OutputStream out = Files.newOutputStream(fs.getPath("/foo")); out.write("hello".getBytes()); out.close(); - out.close(); + out.close(); // Intentional second `close` invocation } - try (FileSystem fs = newZipFileSystem(fsPath, new HashMap())) { + try (FileSystem fs = FileSystems.newFileSystem(fsPath, Map.of())) { assertArrayEquals("hello".getBytes(), Files.readAllBytes(fs.getPath("/foo")), - "entry close() failed"); + "Second `close` on entry output stream corrupted /foo"); } catch (Exception x) { - fail("entry close() failed", x); + fail("Second `close` on entry output stream causes unexpected error", x); } finally { Files.delete(fsPath); } @@ -651,26 +703,9 @@ public class ZipFSTester { @Test void test8131067() throws Exception { - Map env = new HashMap(); - env.put("create", "true"); - // file name with space character for URI to quote it - File tmp = File.createTempFile("test zipfs", "zip"); - tmp.delete(); // we need a clean path, no file - Path fsPath = tmp.toPath(); - try (FileSystem fs = newZipFileSystem(fsPath, env);) { - Files.write(fs.getPath("/foo"), "hello".getBytes()); - URI fooUri = fs.getPath("/foo").toUri(); - assertArrayEquals("hello".getBytes(), Files.readAllBytes(Paths.get(fooUri)), - "entry close() failed"); - } finally { - Files.delete(fsPath); - } - } - - private static FileSystem newZipFileSystem(Path path, Map env) - throws Exception - { + Path fsPath = Files.createTempFile(Path.of("."), "test zipfs", ".zip"); + Files.delete(fsPath); // we need a clean path, no file // Use URLDecoder (for test only) to remove the double escaped space // character. For the path which is not encoded by UTF-8, we need to // replace "+" by "%2b" manually before feeding into the decoder. @@ -682,16 +717,83 @@ public class ZipFSTester { // // Also, we should not use URLEncoder in case of the path has been // encoded. - return FileSystems.newFileSystem( - new URI("jar", URLDecoder.decode(path.toUri().toString() - .replace("+", "%2b"), "utf8"), null), env, null); + try (FileSystem fs = FileSystems.newFileSystem(new URI("jar", + URLDecoder.decode(fsPath.toUri().toString().replace("+", "%2b"), StandardCharsets.UTF_8), + null), Map.of("create", "true"))) { + Files.write(fs.getPath("/foo"), "hello".getBytes()); + URI fooUri = fs.getPath("/foo").toUri(); + assertArrayEquals("hello".getBytes(), Files.readAllBytes(Paths.get(fooUri)), + "entry close() failed"); + } finally { + Files.deleteIfExists(fsPath); + } } - private static Path getTempPath() throws IOException - { - File tmp = File.createTempFile("testzipfs_", "zip"); - tmp.delete(); // we need a clean path, no file - return tmp.toPath(); + /** + * Tests if certain methods throw a NullPointerException if invoked with null + * as specified in java.nio.file.package-info.java + * + * @see 8299864 + */ + @Test + void testFileStoreNullArgs() throws Exception { + try (var fs = FileSystems.newFileSystem(jarFile, Map.of())) { + // file system containing at least one ZipFileStore + FileStore store = fs.getFileStores().iterator().next(); + + // Make sure we are testing the right thing + assertEquals("jdk.nio.zipfs.ZipFileStore", store.getClass().getName()); + + assertThrows(NullPointerException.class, () -> store.supportsFileAttributeView((String) null)); + assertThrows(NullPointerException.class, () -> store.supportsFileAttributeView((Class) null)); + assertThrows(NullPointerException.class, () -> store.getAttribute(null)); + assertThrows(NullPointerException.class, () -> store.getFileStoreAttributeView(null)); + } + } + + private static Path getTempNonZipPath() throws IOException { + var path = Files.createTempFile( + Path.of("."), "testzipfs_", ".foo"); + Files.delete(path); + return path; + } + + private static Path getTempZipPath() throws IOException { + var path = Files.createTempFile( + Path.of("."), "testzipfs_", ".zip"); + Files.delete(path); + return path; + } + + private static Path getNonZipFile() throws IOException { + var src = getTempNonZipPath(); + writeRandomBytes(src); + return src; + } + + static Path getFile() throws IOException { + Path src = getTempZipPath(); + writeRandomBytes(src); + return src; + } + + private static void writeRandomBytes(Path src) throws IOException { + try (OutputStream os = Files.newOutputStream(src)) { + byte[] bits = new byte[12345]; + RDM.nextBytes(bits); + os.write(bits); + } + } + + private static void createClonedZip(Path tmpfsPath) throws Exception { + try (var fs = FileSystems.newFileSystem(jarFile, Map.of()); + FileSystem copy = FileSystems.newFileSystem(tmpfsPath, Map.of("create", "true"))) { + z2zcopy(fs, copy, "/", 0); + } + } + + private static URI pathToJarURI(Path path) throws URISyntaxException { + return new URI("jar", path.toUri().toString(), null); } private static void list(Path path, List files, List dirs ) @@ -718,7 +820,7 @@ public class ZipFSTester { if (Files.isDirectory(srcPath)) { if (!Files.exists(dstPath)) { try { - mkdirs(dstPath); + Files.createDirectories(dstPath); } catch (FileAlreadyExistsException x) {} } try (DirectoryStream ds = Files.newDirectoryStream(srcPath)) { @@ -756,7 +858,7 @@ public class ZipFSTester { if (Files.isDirectory(srcPath)) { if (!Files.exists(dstPath)) - mkdirs(dstPath); + Files.createDirectories(dstPath); try (DirectoryStream ds = Files.newDirectoryStream(srcPath)) { for (Path child : ds) { z2zmove(src, dst, @@ -767,7 +869,7 @@ public class ZipFSTester { //System.out.println("moving..." + path); Path parent = dstPath.getParent(); if (parent != null && Files.notExists(parent)) - mkdirs(parent); + Files.createDirectories(parent); Files.move(srcPath, dstPath); } } @@ -814,18 +916,6 @@ public class ZipFSTester { }); } - private static void mkdirs(Path path) throws IOException { - if (Files.exists(path)) - return; - path = path.toAbsolutePath(); - Path parent = path.getParent(); - if (parent != null) { - if (Files.notExists(parent)) - mkdirs(parent); - } - Files.createDirectory(path); - } - private static void rmdirs(Path path) throws IOException { while (path != null && path.getNameCount() != 0) { Files.delete(path); @@ -915,11 +1005,8 @@ public class ZipFSTester { private static void fchCopy(Path src, Path dst) throws IOException { - Set read = new HashSet<>(); - read.add(READ); - Set openwrite = new HashSet<>(); - openwrite.add(CREATE_NEW); - openwrite.add(WRITE); + Set read = Set.of(READ); + Set openwrite = Set.of(CREATE_NEW, WRITE); try (FileChannel srcFc = src.getFileSystem() .provider() @@ -939,11 +1026,8 @@ public class ZipFSTester { private static void chCopy(Path src, Path dst) throws IOException { - Set read = new HashSet<>(); - read.add(READ); - Set openwrite = new HashSet<>(); - openwrite.add(CREATE_NEW); - openwrite.add(WRITE); + Set read = Set.of(READ); + Set openwrite = Set.of(CREATE_NEW, WRITE); try (SeekableByteChannel srcCh = Files.newByteChannel(src, read); SeekableByteChannel dstCh = Files.newByteChannel(dst, openwrite)) @@ -983,8 +1067,7 @@ public class ZipFSTester { throws Exception { System.out.println("test ByteChannel..."); - Set read = new HashSet<>(); - read.add(READ); + Set read = Set.of(READ); int n = 0; ByteBuffer bb = null; ByteBuffer bb2 = null; @@ -1027,29 +1110,7 @@ public class ZipFSTester { Path path = fs.getPath(name); Path parent = path.getParent(); if (parent != null && Files.notExists(parent)) - mkdirs(parent); + Files.createDirectories(parent); return path; } - - /** - * Tests if certain methods throw a NullPointerException if invoked with null - * as specified in java.nio.file.package-info.java - * - * @see 8299864 - */ - @Test - void testFileStoreNullArgs() throws Exception { - try (var fs = newZipFileSystem(jarFile, Map.of())) { - // file system containing at least one ZipFileStore - FileStore store = fs.getFileStores().iterator().next(); - - // Make sure we are testing the right thing - assertEquals("jdk.nio.zipfs.ZipFileStore", store.getClass().getName()); - - assertThrows(NullPointerException.class, () -> store.supportsFileAttributeView((String) null)); - assertThrows(NullPointerException.class, () -> store.supportsFileAttributeView((Class) null)); - assertThrows(NullPointerException.class, () -> store.getAttribute(null)); - assertThrows(NullPointerException.class, () -> store.getFileStoreAttributeView(null)); - } - } } From 410b3e816a73f00ffbb93e01707e33ea9cd2ecd5 Mon Sep 17 00:00:00 2001 From: Naoto Sato Date: Fri, 3 Apr 2026 19:37:33 +0000 Subject: [PATCH 173/359] 8381606: Javadoc typo in ResourceBundle example Reviewed-by: iris, jlu --- src/java.base/share/classes/java/util/ResourceBundle.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/java.base/share/classes/java/util/ResourceBundle.java b/src/java.base/share/classes/java/util/ResourceBundle.java index db19eda6399..f91db79891b 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, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1119,15 +1119,15 @@ public abstract class ResourceBundle { * sequence of bundle names generated by truncating the last underscore and * the part following it is inserted after a candidate bundle name with the * original variant. For example, for a locale with language "en", script - * "Latn, country "US" and variant "WINDOWS_VISTA", and bundle base name + * "Latn", country "US" and variant "WINDOWS_WIN11", and bundle base name * "MyResource", the list of candidate bundle names below is generated: * *
-     * MyResource_en_Latn_US_WINDOWS_VISTA
+     * MyResource_en_Latn_US_WINDOWS_WIN11
      * MyResource_en_Latn_US_WINDOWS
      * MyResource_en_Latn_US
      * MyResource_en_Latn
-     * MyResource_en_US_WINDOWS_VISTA
+     * MyResource_en_US_WINDOWS_WIN11
      * MyResource_en_US_WINDOWS
      * MyResource_en_US
      * MyResource_en

From e254526f4a2647996c808e66b294f33fe38d57af Mon Sep 17 00:00:00 2001
From: William Kemper 
Date: Fri, 3 Apr 2026 20:10:26 +0000
Subject: [PATCH 174/359] 8380958: GenShen: Regulator thread may observe
 inconsistent old generation state

Reviewed-by: kdnilsen, xpeng
---
 .../heuristics/shenandoahOldHeuristics.cpp    |  2 +-
 .../gc/shenandoah/shenandoahDegeneratedGC.cpp |  2 +-
 .../shenandoahGenerationalControlThread.cpp   | 17 ++----
 .../gc/shenandoah/shenandoahOldGeneration.cpp | 60 +++++++------------
 .../gc/shenandoah/shenandoahOldGeneration.hpp | 12 ++--
 5 files changed, 33 insertions(+), 60 deletions(-)

diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahOldHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahOldHeuristics.cpp
index 33c91e27be5..0789fd5cb1c 100644
--- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahOldHeuristics.cpp
+++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahOldHeuristics.cpp
@@ -576,7 +576,7 @@ void ShenandoahOldHeuristics::prepare_for_old_collections() {
   } else if (has_coalesce_and_fill_candidates()) {
     _old_generation->transition_to(ShenandoahOldGeneration::FILLING);
   } else {
-    _old_generation->transition_to(ShenandoahOldGeneration::WAITING_FOR_BOOTSTRAP);
+    _old_generation->transition_to(ShenandoahOldGeneration::IDLE);
   }
 }
 
diff --git a/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp
index 8cd8a390c4a..1873d818093 100644
--- a/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp
+++ b/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp
@@ -55,7 +55,7 @@ bool ShenandoahDegenGC::collect(GCCause::Cause cause) {
   vmop_degenerated();
   ShenandoahHeap* heap = ShenandoahHeap::heap();
   if (heap->mode()->is_generational()) {
-    bool is_bootstrap_gc = heap->old_generation()->is_bootstrapping();
+    bool is_bootstrap_gc = heap->young_generation()->is_bootstrap_cycle();
     heap->mmu_tracker()->record_degenerated(GCId::current(), is_bootstrap_gc);
     const char* msg = is_bootstrap_gc? "At end of Degenerated Bootstrap Old GC": "At end of Degenerated Young GC";
     heap->log_heap_status(msg);
diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp
index 064f43ffd6b..aa6a4a9bab2 100644
--- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp
+++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp
@@ -422,12 +422,11 @@ void ShenandoahGenerationalControlThread::service_concurrent_old_cycle(const She
       }
 
       // Coalescing threads completed and nothing was cancelled. it is safe to transition from this state.
-      old_generation->transition_to(ShenandoahOldGeneration::WAITING_FOR_BOOTSTRAP);
+      old_generation->transition_to(ShenandoahOldGeneration::IDLE);
       return;
     }
-    case ShenandoahOldGeneration::WAITING_FOR_BOOTSTRAP:
-      old_generation->transition_to(ShenandoahOldGeneration::BOOTSTRAPPING);
-    case ShenandoahOldGeneration::BOOTSTRAPPING: {
+    case ShenandoahOldGeneration::IDLE:
+      old_generation->transition_to(ShenandoahOldGeneration::MARKING);
       // Configure the young generation's concurrent mark to put objects in
       // old regions into the concurrent mark queues associated with the old
       // generation. The young cycle will run as normal except that rather than
@@ -450,8 +449,6 @@ void ShenandoahGenerationalControlThread::service_concurrent_old_cycle(const She
       // and init mark for the concurrent mark. All of that work will have been
       // done by the bootstrapping young cycle.
       set_gc_mode(servicing_old);
-      old_generation->transition_to(ShenandoahOldGeneration::MARKING);
-    }
     case ShenandoahOldGeneration::MARKING: {
       ShenandoahGCSession session(request.cause, old_generation);
       bool marking_complete = resume_concurrent_old_cycle(old_generation, request.cause);
@@ -644,12 +641,6 @@ void ShenandoahGenerationalControlThread::service_stw_degenerated_cycle(const Sh
   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(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);
-    }
   }
 }
 
@@ -681,7 +672,7 @@ bool ShenandoahGenerationalControlThread::request_concurrent_gc(ShenandoahGenera
     // 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);
+      _heap->cancel_gc(GCCause::_shenandoah_concurrent_gc);
       notify_control_thread(ml, GCCause::_shenandoah_concurrent_gc, generation);
       ml.wait();
     }
diff --git a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp
index 16a24da8b1c..bbfa0961e86 100644
--- a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp
+++ b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp
@@ -114,7 +114,7 @@ ShenandoahOldGeneration::ShenandoahOldGeneration(uint max_queues)
     _promotable_regular_regions(0),
     _is_parsable(true),
     _card_scan(nullptr),
-    _state(WAITING_FOR_BOOTSTRAP),
+    _state(IDLE),
     _growth_percent_before_collection(INITIAL_GROWTH_PERCENT_BEFORE_COLLECTION)
 {
   assert(type() == ShenandoahGenerationType::OLD, "OO sanity");
@@ -339,7 +339,7 @@ void ShenandoahOldGeneration::cancel_gc() {
   shenandoah_assert_safepoint();
   if (is_idle()) {
 #ifdef ASSERT
-    validate_waiting_for_bootstrap();
+    validate_idle();
 #endif
   } else {
     log_info(gc)("Terminating old gc cycle.");
@@ -350,7 +350,7 @@ void ShenandoahOldGeneration::cancel_gc() {
     // Remove old generation access to young generation mark queues
     ShenandoahHeap::heap()->young_generation()->set_old_gen_task_queues(nullptr);
     // Transition to IDLE now.
-    transition_to(ShenandoahOldGeneration::WAITING_FOR_BOOTSTRAP);
+    transition_to(ShenandoahOldGeneration::IDLE);
   }
 }
 
@@ -477,9 +477,8 @@ void ShenandoahOldGeneration::prepare_regions_and_collection_set(bool concurrent
 
 const char* ShenandoahOldGeneration::state_name(State state) {
   switch (state) {
-    case WAITING_FOR_BOOTSTRAP:   return "Waiting for Bootstrap";
+    case IDLE:                    return "Idle";
     case FILLING:                 return "Coalescing";
-    case BOOTSTRAPPING:           return "Bootstrapping";
     case MARKING:                 return "Marking";
     case EVACUATING:              return "Evacuating";
     case EVACUATING_AFTER_GLOBAL: return "Evacuating (G)";
@@ -517,7 +516,7 @@ void ShenandoahOldGeneration::transition_to(State new_state) {
 // the old generation in the respective states (EVACUATING or FILLING). After a Full GC,
 // the mark bitmaps are all reset, all regions are parsable and the mark context will
 // not be "complete". After a Full GC, remembered set scans will _not_ use the mark bitmap
-// and we expect the old generation to be waiting for bootstrap.
+// and we expect the old generation to be idle.
 //
 //                              +-----------------+
 //               +------------> |     FILLING     | <---+
@@ -526,19 +525,12 @@ void ShenandoahOldGeneration::transition_to(State new_state) {
 //               |   |            |                     |
 //               |   |            | Filling Complete    | <-> A global collection may
 //               |   |            v                     |     move the old generation
-//               |   |          +-----------------+     |     directly from waiting for
-//           +-- |-- |--------> |     WAITING     |     |     bootstrap to filling or
-//           |   |   |    +---- |  FOR BOOTSTRAP  | ----+     evacuating. It may also
-//           |   |   |    |     +-----------------+           move from filling to waiting
-//           |   |   |    |       |                           for bootstrap.
-//           |   |   |    |       | Reset Bitmap
-//           |   |   |    |       v
-//           |   |   |    |     +-----------------+     +----------------------+
-//           |   |   |    |     |    BOOTSTRAP    | <-> |       YOUNG GC       |
-//           |   |   |    |     |                 |     | (RSet Parses Region) |
-//           |   |   |    |     +-----------------+     +----------------------+
+//               |   |          +-----------------+     |     directly from idle to
+//           +-- |-- |--------> |      IDLE       |     |     filling or evacuating.
+//           |   |   |    +---- |                 | ----+     It may also move from
+//           |   |   |    |     +-----------------+           filling to idle.
 //           |   |   |    |       |
-//           |   |   |    |       | Old Marking
+//           |   |   |    |       | Reset Bitmap + Start Marking
 //           |   |   |    |       v
 //           |   |   |    |     +-----------------+     +----------------------+
 //           |   |   |    |     |     MARKING     | <-> |       YOUNG GC       |
@@ -564,29 +556,23 @@ void ShenandoahOldGeneration::validate_transition(State new_state) {
   ShenandoahGenerationalHeap* heap = ShenandoahGenerationalHeap::heap();
   switch (new_state) {
     case FILLING:
-      assert(_state != BOOTSTRAPPING, "Cannot begin making old regions parsable after bootstrapping");
       assert(is_mark_complete(), "Cannot begin filling without first completing marking, state is '%s'", state_name(_state));
       assert(_old_heuristics->has_coalesce_and_fill_candidates(), "Cannot begin filling without something to fill.");
       break;
-    case WAITING_FOR_BOOTSTRAP:
+    case IDLE:
       // GC cancellation can send us back here from any state.
-      validate_waiting_for_bootstrap();
-      break;
-    case BOOTSTRAPPING:
-      assert(_state == WAITING_FOR_BOOTSTRAP, "Cannot reset bitmap without making old regions parsable, state is '%s'", state_name(_state));
-      assert(_old_heuristics->unprocessed_old_collection_candidates() == 0, "Cannot bootstrap with mixed collection candidates");
-      assert(!heap->is_prepare_for_old_mark_in_progress(), "Cannot still be making old regions parsable.");
+      validate_idle();
       break;
     case MARKING:
-      assert(_state == BOOTSTRAPPING, "Must have finished bootstrapping before marking, state is '%s'", state_name(_state));
-      assert(heap->young_generation()->old_gen_task_queues() != nullptr, "Young generation needs old mark queues.");
-      assert(heap->is_concurrent_old_mark_in_progress(), "Should be marking old now.");
+      assert(_state == IDLE, "Must be idle before marking, state is '%s'", state_name(_state));
+      assert(_old_heuristics->unprocessed_old_collection_candidates() == 0, "Cannot start marking with mixed collection candidates");
+      assert(!heap->is_prepare_for_old_mark_in_progress(), "Cannot still be making old regions parsable.");
       break;
     case EVACUATING_AFTER_GLOBAL:
       assert(_state == EVACUATING, "Must have been evacuating, state is '%s'", state_name(_state));
       break;
     case EVACUATING:
-      assert(_state == WAITING_FOR_BOOTSTRAP || _state == MARKING, "Cannot have old collection candidates without first marking, state is '%s'", state_name(_state));
+      assert(_state == IDLE || _state == MARKING, "Cannot have old collection candidates without first marking, state is '%s'", state_name(_state));
       assert(_old_heuristics->unprocessed_old_collection_candidates() > 0, "Must have collection candidates here.");
       break;
     default:
@@ -594,10 +580,10 @@ void ShenandoahOldGeneration::validate_transition(State new_state) {
   }
 }
 
-bool ShenandoahOldGeneration::validate_waiting_for_bootstrap() {
+bool ShenandoahOldGeneration::validate_idle() {
   ShenandoahHeap* heap = ShenandoahHeap::heap();
-  assert(!heap->is_concurrent_old_mark_in_progress(), "Cannot become ready for bootstrap during old mark.");
-  assert(heap->young_generation()->old_gen_task_queues() == nullptr, "Cannot become ready for bootstrap when still setup for bootstrapping.");
+  assert(!heap->is_concurrent_old_mark_in_progress(), "Cannot be idle during old mark.");
+  assert(heap->young_generation()->old_gen_task_queues() == nullptr, "Cannot be idle when still setup for bootstrapping.");
   assert(!is_concurrent_mark_in_progress(), "Cannot be marking in IDLE");
   assert(!heap->young_generation()->is_bootstrap_cycle(), "Cannot have old mark queues if IDLE");
   assert(!_old_heuristics->has_coalesce_and_fill_candidates(), "Cannot have coalesce and fill candidates in IDLE");
@@ -733,7 +719,7 @@ void ShenandoahOldGeneration::set_parsable(bool parsable) {
         // that we would unload classes and make everything parsable. But, we know
         // that now so we can override this state.
         abandon_collection_candidates();
-        transition_to(ShenandoahOldGeneration::WAITING_FOR_BOOTSTRAP);
+        transition_to(ShenandoahOldGeneration::IDLE);
         break;
       default:
         // We can get here during a full GC. The full GC will cancel anything
@@ -750,7 +736,7 @@ void ShenandoahOldGeneration::complete_mixed_evacuations() {
   assert(is_doing_mixed_evacuations(), "Mixed evacuations should be in progress");
   if (!_old_heuristics->has_coalesce_and_fill_candidates()) {
     // No candidate regions to coalesce and fill
-    transition_to(ShenandoahOldGeneration::WAITING_FOR_BOOTSTRAP);
+    transition_to(ShenandoahOldGeneration::IDLE);
     return;
   }
 
@@ -764,7 +750,7 @@ void ShenandoahOldGeneration::complete_mixed_evacuations() {
   // more to do.
   assert(state() == ShenandoahOldGeneration::EVACUATING_AFTER_GLOBAL, "Should be evacuating after a global cycle");
   abandon_collection_candidates();
-  transition_to(ShenandoahOldGeneration::WAITING_FOR_BOOTSTRAP);
+  transition_to(ShenandoahOldGeneration::IDLE);
 }
 
 void ShenandoahOldGeneration::abandon_mixed_evacuations() {
@@ -774,7 +760,7 @@ void ShenandoahOldGeneration::abandon_mixed_evacuations() {
       break;
     case ShenandoahOldGeneration::EVACUATING_AFTER_GLOBAL:
       abandon_collection_candidates();
-      transition_to(ShenandoahOldGeneration::WAITING_FOR_BOOTSTRAP);
+      transition_to(ShenandoahOldGeneration::IDLE);
       break;
     default:
       log_warning(gc)("Abandon mixed evacuations in unexpected state: %s", state_name(state()));
diff --git a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.hpp b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.hpp
index 12e046a1afc..8a356fc9b92 100644
--- a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.hpp
+++ b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.hpp
@@ -256,11 +256,7 @@ public:
   }
 
   bool is_idle() const {
-    return state() == WAITING_FOR_BOOTSTRAP;
-  }
-
-  bool is_bootstrapping() const {
-    return state() == BOOTSTRAPPING;
+    return state() == IDLE;
   }
 
   // Amount of live memory (bytes) in regions waiting for mixed collections
@@ -271,11 +267,11 @@ public:
 
 public:
   enum State {
-    FILLING, WAITING_FOR_BOOTSTRAP, BOOTSTRAPPING, MARKING, EVACUATING, EVACUATING_AFTER_GLOBAL
+    FILLING, IDLE, MARKING, EVACUATING, EVACUATING_AFTER_GLOBAL
   };
 
 #ifdef ASSERT
-  bool validate_waiting_for_bootstrap();
+  bool validate_idle();
 #endif
 
 private:
@@ -318,7 +314,7 @@ public:
   size_t usage_trigger_threshold() const;
 
   bool can_start_gc() {
-    return _state == WAITING_FOR_BOOTSTRAP;
+    return _state == IDLE;
   }
 
   static const char* state_name(State state);

From a333111bd866b2da356b13ea9b8d362ae1c94107 Mon Sep 17 00:00:00 2001
From: Ioi Lam 
Date: Fri, 3 Apr 2026 20:28:45 +0000
Subject: [PATCH 175/359] 8380291: AOT cache should store only unregistered
 classes with file: code source

Reviewed-by: kvn, iveresov
---
 .../share/classfile/classFileParser.cpp       |  7 +--
 .../classfile/systemDictionaryShared.cpp      | 14 ++++++
 .../classfile/systemDictionaryShared.hpp      |  1 +
 .../AOTCacheSupportForCustomLoaders.java      | 48 ++++++++++++++++++-
 4 files changed, 65 insertions(+), 5 deletions(-)

diff --git a/src/hotspot/share/classfile/classFileParser.cpp b/src/hotspot/share/classfile/classFileParser.cpp
index 404693f5cee..a9ea6fbea11 100644
--- a/src/hotspot/share/classfile/classFileParser.cpp
+++ b/src/hotspot/share/classfile/classFileParser.cpp
@@ -34,6 +34,7 @@
 #include "classfile/packageEntry.hpp"
 #include "classfile/symbolTable.hpp"
 #include "classfile/systemDictionary.hpp"
+#include "classfile/systemDictionaryShared.hpp"
 #include "classfile/verificationType.hpp"
 #include "classfile/verifier.hpp"
 #include "classfile/vmClasses.hpp"
@@ -86,9 +87,6 @@
 #include "utilities/macros.hpp"
 #include "utilities/ostream.hpp"
 #include "utilities/utf8.hpp"
-#if INCLUDE_CDS
-#include "classfile/systemDictionaryShared.hpp"
-#endif
 
 // We generally try to create the oops directly when parsing, rather than
 // allocating temporary data structures and copying the bytes twice. A
@@ -5256,6 +5254,9 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik,
 
   if (!is_internal()) {
     ik->print_class_load_logging(_loader_data, module_entry, _stream);
+    if (CDSConfig::is_dumping_archive()) {
+      SystemDictionaryShared::check_code_source(ik, _stream);
+    }
 
     if (ik->minor_version() == JAVA_PREVIEW_MINOR_VERSION &&
         ik->major_version() == JVM_CLASSFILE_MAJOR_VERSION &&
diff --git a/src/hotspot/share/classfile/systemDictionaryShared.cpp b/src/hotspot/share/classfile/systemDictionaryShared.cpp
index 58d432a628c..fd30fc6766f 100644
--- a/src/hotspot/share/classfile/systemDictionaryShared.cpp
+++ b/src/hotspot/share/classfile/systemDictionaryShared.cpp
@@ -202,6 +202,20 @@ DumpTimeClassInfo* SystemDictionaryShared::get_info_locked(InstanceKlass* k) {
   return info;
 }
 
+void SystemDictionaryShared::check_code_source(InstanceKlass* ik, const ClassFileStream* cfs) {
+  if (CDSConfig::is_dumping_preimage_static_archive() && !is_builtin_loader(ik->class_loader_data())) {
+    if (cfs == nullptr || cfs->source() == nullptr || strncmp(cfs->source(), "file:", 5) != 0) {
+      // AOT cache filtering:
+      // For non-built-in loaders, cache only the classes that have a file: code source, so
+      // we can avoid caching dynamically generated classes that are likely to change from
+      // run to run. This is similar to the filtering in ClassListWriter::write_to_stream()
+      // for the classic CDS static archive.
+      SystemDictionaryShared::log_exclusion(ik, "Not loaded from \"file:\" code source");
+      SystemDictionaryShared::set_excluded(ik);
+    }
+  }
+}
+
 bool SystemDictionaryShared::should_be_excluded_impl(InstanceKlass* k, DumpTimeClassInfo* info) {
   assert_lock_strong(DumpTimeTable_lock);
 
diff --git a/src/hotspot/share/classfile/systemDictionaryShared.hpp b/src/hotspot/share/classfile/systemDictionaryShared.hpp
index 33b245e26fc..c837a386344 100644
--- a/src/hotspot/share/classfile/systemDictionaryShared.hpp
+++ b/src/hotspot/share/classfile/systemDictionaryShared.hpp
@@ -235,6 +235,7 @@ public:
   static void update_shared_entry(InstanceKlass* klass, int id);
   static void set_shared_class_misc_info(InstanceKlass* k, ClassFileStream* cfs);
 
+  static void check_code_source(InstanceKlass* ik, const ClassFileStream* cfs) NOT_CDS_RETURN;
   static InstanceKlass* lookup_from_stream(Symbol* class_name,
                                            Handle class_loader,
                                            Handle protection_domain,
diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/AOTCacheSupportForCustomLoaders.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/AOTCacheSupportForCustomLoaders.java
index 1a8313a3058..9fef0845d1d 100644
--- a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/AOTCacheSupportForCustomLoaders.java
+++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/AOTCacheSupportForCustomLoaders.java
@@ -31,7 +31,10 @@
  * @build ReturnIntegerAsString
  * @build AOTCacheSupportForCustomLoaders
  * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app.jar AppWithCustomLoaders AppWithCustomLoaders$MyLoader
- * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar cust.jar AppWithCustomLoaders$MyLoadeeA AppWithCustomLoaders$MyLoadeeB ReturnIntegerAsString
+ * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar cust.jar
+ *                 AppWithCustomLoaders$MyLoadeeA AppWithCustomLoaders$MyLoadeeB
+ *                 AppWithCustomLoaders$MyLoadeeC AppWithCustomLoaders$MyLoadeeD
+ *                 ReturnIntegerAsString
  * @run driver AOTCacheSupportForCustomLoaders AOT
  */
 
@@ -40,6 +43,7 @@ import java.lang.module.ModuleFinder;
 import java.net.URL;
 import java.net.URLClassLoader;
 import java.io.File;
+import java.io.InputStream;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.Set;
@@ -62,10 +66,17 @@ public class AOTCacheSupportForCustomLoaders {
                        "--module-path=" + modulePath,
                        "--add-modules=com.test")
             .appCommandLine("AppWithCustomLoaders", modulePath)
+            .setTrainingChecker((OutputAnalyzer out) -> {
+                    out.shouldContain("Skipping AppWithCustomLoaders$MyLoadeeC: Not loaded from \"file:\" code source")
+                       .shouldContain("Skipping AppWithCustomLoaders$MyLoadeeD: super AppWithCustomLoaders$MyLoadeeC is excluded")
+                       .shouldContain("Skipping ReturnIntegerAsString: Failed verification");
+                })
             .setAssemblyChecker((OutputAnalyzer out) -> {
                     out.shouldMatch(",class.*unreg AppWithCustomLoaders[$]MyLoadeeA")
                        .shouldMatch(",class.*unreg com.test.Foo")
                        .shouldMatch(",class.*array \\[LAppWithCustomLoaders[$]MyLoadeeA;")
+                       .shouldNotMatch("class.*unreg.*MyLoadeeC") // not from "file:" code source
+                       .shouldNotMatch("class.*unreg.*MyLoadeeD") // parent is not from "file:" code source
                        .shouldNotMatch(",class.* ReturnIntegerAsString");
                 })
             .setProductionChecker((OutputAnalyzer out) -> {
@@ -76,7 +87,7 @@ public class AOTCacheSupportForCustomLoaders {
 }
 
 class AppWithCustomLoaders {
-    static MyLoader loader; // keep alive so its classes can be cached.
+    static MyLoader loader; // keep alive
 
     public static void main(String args[]) throws Exception {
         File custJar = new File("cust.jar");
@@ -86,6 +97,7 @@ class AppWithCustomLoaders {
         test1(loader);
         test2(loader);
         test3(args[0]);
+        test4(loader);
 
         // TODO: more test cases JDK-8354557
     }
@@ -147,10 +159,37 @@ class AppWithCustomLoaders {
         }
     }
 
+    // Test 4: classes that don't use file: code source should be excluded
+    static void test4(MyLoader loader) throws Exception {
+        Class c = loader.loadLoadeeC();
+        Class d = loader.loadClass("AppWithCustomLoaders$MyLoadeeD");
+
+        URL ccs = c.getProtectionDomain().getCodeSource().getLocation();
+
+        if (ccs != null) {
+            throw new RuntimeException("MyLoadeeC should have null CodeSource but got: " + ccs);
+        }
+
+        if (d.getSuperclass() != c) {
+            throw new RuntimeException("MyLoadeeC should be super class of MyLoadeeD");
+        }
+    }
+
     public static class MyLoader extends URLClassLoader {
         public MyLoader(URL[] urls, ClassLoader parent) {
             super(urls, parent);
         }
+
+        public Class loadLoadeeC() throws Exception {
+            try (InputStream in = getResourceAsStream("AppWithCustomLoaders$MyLoadeeC.class")) {
+                byte[] b = in.readAllBytes();
+                // Define MyLoadeeC without specifying a ProtectionDomain. As a result, this
+                // class will get an empty ProtectionDomain whose CodeSource location will be null.
+                //
+                // This class should be excluded from the AOT cache. See JDK-8380291
+                return defineClass(b, 0, b.length);
+            }
+        }
     }
 
     public static class MyLoadeeA {
@@ -180,4 +219,9 @@ class AppWithCustomLoaders {
     }
 
     public static class MyLoadeeB extends MyLoadeeA {}
+
+
+    public static class MyLoadeeC {}
+
+    public static class MyLoadeeD extends MyLoadeeC {}
 }

From f21e47db805b56d5bf183d7a2cfba076f380612a Mon Sep 17 00:00:00 2001
From: William Kemper 
Date: Fri, 3 Apr 2026 21:04:52 +0000
Subject: [PATCH 176/359] 8381549: GenShen: Global collections skip coalesce
 and fill when the collection set is empty

Reviewed-by: kdnilsen, xpeng, ysr
---
 .../heuristics/shenandoahGenerationalHeuristics.cpp           | 4 ++--
 src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp   | 2 +-
 src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.hpp   | 2 +-
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp
index d5622ed5d79..45ba2740ea5 100644
--- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp
+++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp
@@ -84,7 +84,7 @@ void ShenandoahGenerationalHeuristics::choose_collection_set(ShenandoahCollectio
   // Choose the collection set
   filter_regions(collection_set);
 
-  if (!collection_set->is_empty() && _generation->is_global()) {
+  if (_generation->is_global()) {
     // We have just chosen a collection set for a global cycle. The mark bitmap covering old regions is complete, so
     // the remembered set scan can use that to avoid walking into garbage. When the next old mark begins, we will
     // use the mark bitmap to make the old regions parsable by coalescing and filling any unmarked objects. Thus,
@@ -94,7 +94,7 @@ void ShenandoahGenerationalHeuristics::choose_collection_set(ShenandoahCollectio
     // coalesce those regions. Only the old regions which are not part of the collection set at this point are
     // eligible for coalescing. As implemented now, this has the side effect of possibly initiating mixed-evacuations
     // after a global cycle for old regions that were not included in this collection set.
-    heap->old_generation()->prepare_for_mixed_collections_after_global_gc();
+    heap->old_generation()->transition_old_generation_after_global_gc();
   }
 }
 
diff --git a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp
index bbfa0961e86..4ad7d2a1ae5 100644
--- a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp
+++ b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp
@@ -685,7 +685,7 @@ void ShenandoahOldGeneration::abandon_collection_candidates() {
   _old_heuristics->abandon_collection_candidates();
 }
 
-void ShenandoahOldGeneration::prepare_for_mixed_collections_after_global_gc() {
+void ShenandoahOldGeneration::transition_old_generation_after_global_gc() {
   assert(is_mark_complete(), "Expected old generation mark to be complete after global cycle.");
   _old_heuristics->prepare_for_old_collections();
   log_info(gc, ergo)("After choosing global collection set, mixed candidates: " UINT32_FORMAT ", coalescing candidates: %zu",
diff --git a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.hpp b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.hpp
index 8a356fc9b92..630736190f0 100644
--- a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.hpp
+++ b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.hpp
@@ -213,7 +213,7 @@ public:
   bool is_concurrent_mark_in_progress() override;
 
   bool entry_coalesce_and_fill();
-  void prepare_for_mixed_collections_after_global_gc();
+  void transition_old_generation_after_global_gc();
   void prepare_gc() override;
   void prepare_regions_and_collection_set(bool concurrent) override;
   void record_success_concurrent(bool abbreviated) override;

From 1d290109d33a1b4bac671bb8d530a2d15424a683 Mon Sep 17 00:00:00 2001
From: Daisuke Yamazaki 
Date: Mon, 6 Apr 2026 03:08:19 +0000
Subject: [PATCH 177/359] 8379675:
 test/jdk/sun/security/pkcs11/rsa/GenKeyStore.java uses removed methods

Reviewed-by: weijun
---
 test/jdk/sun/security/rsa/GenKeyStore.java | 29 +++++++++++-----------
 1 file changed, 14 insertions(+), 15 deletions(-)

diff --git a/test/jdk/sun/security/rsa/GenKeyStore.java b/test/jdk/sun/security/rsa/GenKeyStore.java
index 26178e9a576..8b0016e77af 100644
--- a/test/jdk/sun/security/rsa/GenKeyStore.java
+++ b/test/jdk/sun/security/rsa/GenKeyStore.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2026, Oracle and/or its affiliates. All rights reserved.
  * 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 @@
 // program to generate rsakeys.ks. does not need to run during testing
 // checked into the workspace so that the keystore file can be recreated
 // in the future if needed.
+//
+// To run:
+//   java --add-exports java.base/sun.security.x509=ALL-UNNAMED GenKeyStore.java
 
 // @author Andreas Sterbenz
 
@@ -43,26 +46,22 @@ public class GenKeyStore {
 
     static final char[] password = "test12".toCharArray();
 
-    private static X509Certificate getCertificate(String suffix, PublicKey publicKey, PrivateKey privateKey) throws Exception {
+    private static X509Certificate getCertificate(String suffix,
+                                                    PublicKey publicKey,
+                                                    PrivateKey privateKey) throws Exception {
         X500Name name = new X500Name("CN=Dummy Certificate " + suffix);
         String algorithm = "SHA1with" + publicKey.getAlgorithm();
         Date date = new Date();
-        AlgorithmId algID = AlgorithmId.getAlgorithmId(algorithm);
 
         X509CertInfo certInfo = new X509CertInfo();
+        certInfo.setVersion(new CertificateVersion(CertificateVersion.V1));
+        certInfo.setSerialNumber(new CertificateSerialNumber(1));
+        certInfo.setSubject(name);
+        certInfo.setIssuer(name);
+        certInfo.setKey(new CertificateX509Key(publicKey));
+        certInfo.setValidity(new CertificateValidity(date, date));
 
-        certInfo.set(X509CertInfo.VERSION, new CertificateVersion(CertificateVersion.V1));
-        certInfo.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber(1));
-        certInfo.set(X509CertInfo.ALGORITHM_ID, new CertificateAlgorithmId(algID));
-        certInfo.set(X509CertInfo.SUBJECT, name);
-        certInfo.set(X509CertInfo.ISSUER, name);
-        certInfo.set(X509CertInfo.KEY, new CertificateX509Key(publicKey));
-        certInfo.set(X509CertInfo.VALIDITY, new CertificateValidity(date, date));
-
-        X509CertImpl cert = new X509CertImpl(certInfo);
-        cert.sign(privateKey, algorithm);
-
-        return cert;
+        return X509CertImpl.newSigned(certInfo, privateKey, algorithm);
     }
 
     private static void addToKeyStore(KeyStore ks, KeyPair kp, String name) throws Exception {

From f40a359df36edef8df5a72e3c072967924636264 Mon Sep 17 00:00:00 2001
From: Jaikiran Pai 
Date: Mon, 6 Apr 2026 13:21:44 +0000
Subject: [PATCH 178/359] 8373778: java.util.NoSuchElementException in
 HttpURLConnection.doTunneling0 when connecting via HTTPS

Reviewed-by: michaelm, vyazici
---
 .../www/protocol/http/HttpURLConnection.java  |  43 ++-
 .../HttpURLConnection/ProxyBadStatusLine.java | 266 ++++++++++++++++++
 2 files changed, 306 insertions(+), 3 deletions(-)
 create mode 100644 test/jdk/java/net/HttpURLConnection/ProxyBadStatusLine.java

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 3a915cf96df..480553e9a62 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
@@ -1924,9 +1924,15 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
                 }
 
                 statusLine = responses.getValue(0);
-                StringTokenizer st = new StringTokenizer(statusLine);
-                st.nextToken();
-                respCode = Integer.parseInt(st.nextToken().trim());
+                respCode = parseConnectResponseCode(statusLine);
+                if (respCode == -1) {
+                    // a respCode of -1, due to a invalid status line,
+                    // will (rightly) result in an IOException being thrown
+                    // later in this code. here we merely log the invalid status line.
+                    if (logger.isLoggable(PlatformLogger.Level.FINE)) {
+                        logger.fine("invalid status line: \"" + statusLine + "\"");
+                    }
+                }
                 if (respCode == HTTP_PROXY_AUTH) {
                     // Read comments labeled "Failed Negotiate" for details.
                     boolean dontUseNegotiate = false;
@@ -2027,6 +2033,37 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
         responses.reset();
     }
 
+    // parses the status line, that was returned for a CONNECT request, and returns
+    // the response code from that line. returns -1 if the response code could not be
+    // parsed.
+    private static int parseConnectResponseCode(final String statusLine) {
+        final int invalidStatusLine = -1;
+        if (statusLine == null || statusLine.isBlank()) {
+            return invalidStatusLine;
+        }
+        //
+        // status-line = HTTP-version SP status-code SP [ reason-phrase ]
+        // SP = space character
+        //
+        final StringTokenizer st = new StringTokenizer(statusLine, " ");
+        if (!st.hasMoreTokens()) {
+            return invalidStatusLine;
+        }
+        st.nextToken(); // the HTTP version part (ex: HTTP/1.1)
+        if (!st.hasMoreTokens()) {
+            return invalidStatusLine;
+        }
+        final String v = st.nextToken().trim(); // status code
+        try {
+            return Integer.parseInt(v);
+        } catch (NumberFormatException nfe) {
+            if (logger.isLoggable(PlatformLogger.Level.FINE)) {
+                logger.fine("invalid response code: " + v);
+            }
+        }
+        return invalidStatusLine;
+    }
+
     /**
      * Overridden in https to also include the server certificate
      */
diff --git a/test/jdk/java/net/HttpURLConnection/ProxyBadStatusLine.java b/test/jdk/java/net/HttpURLConnection/ProxyBadStatusLine.java
new file mode 100644
index 00000000000..be881030715
--- /dev/null
+++ b/test/jdk/java/net/HttpURLConnection/ProxyBadStatusLine.java
@@ -0,0 +1,266 @@
+/*
+ * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please 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.io.InputStream;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Proxy;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.URL;
+import java.util.List;
+
+import jdk.test.lib.net.URIBuilder;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+import static java.net.Proxy.Type.HTTP;
+import static java.nio.charset.StandardCharsets.ISO_8859_1;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+/* @test
+ * @bug 8373778
+ * @summary Verify that a IOException gets thrown from HttpURLConnection, if the proxy returns
+ *          an invalid status line in response to a CONNECT request
+ * @library /test/lib
+ * @build jdk.test.lib.net.URIBuilder
+ * @run junit ${test.main.class}
+ */
+class ProxyBadStatusLine {
+
+    static List badStatusLines() {
+        return List.of(
+                Arguments.of("", "Unexpected end of file from server"),
+                Arguments.of(" ", "Unexpected end of file from server"),
+                Arguments.of("\t", "Unexpected end of file from server"),
+                Arguments.of("\r\n", "Unexpected end of file from server"),
+
+                Arguments.of("HTTP/1.", "Unable to tunnel through proxy"),
+                Arguments.of("HTTP/1.1", "Unable to tunnel through proxy"),
+                Arguments.of("HTTP/1.0", "Unable to tunnel through proxy"),
+                Arguments.of("HTTP/1.1     ", "Unable to tunnel through proxy"),
+                Arguments.of("HTTP/1.1\r\n", "Unable to tunnel through proxy"),
+                Arguments.of("HTTP/1.1\n", "Unable to tunnel through proxy"),
+                Arguments.of("HTTP/1.1 301 ", "Unable to tunnel through proxy"),
+                Arguments.of("HTTP/1.1 404 ", "Unable to tunnel through proxy"),
+                Arguments.of("HTTP/1.1 503 ", "Unable to tunnel through proxy"),
+                Arguments.of("HTTP/1.1\n200 ", "Unable to tunnel through proxy"),
+                Arguments.of("HTTP/1.1\r200 ", "Unable to tunnel through proxy"),
+                Arguments.of("HTTP/1.1\f200 ", "Unable to tunnel through proxy")
+        );
+    }
+
+    /*
+     * Uses HttpURLConnection to initiate a HTTP request that results in a CONNECT
+     * request to a proxy server. The proxy server then responds with a bad status line.
+     * The test expects that an IOException gets thrown back to the application (instead
+     * of some unspecified exception).
+     */
+    @ParameterizedTest
+    @MethodSource(value = "badStatusLines")
+    void testProxyConnectResponse(final String badStatusLine, final String expectedExceptionMsg)
+            throws Exception {
+        final InetSocketAddress irrelevantTargetServerAddr =
+                new InetSocketAddress(InetAddress.getLoopbackAddress(), 12345);
+        final URL url = URIBuilder.newBuilder()
+                .scheme("https")
+                .host(irrelevantTargetServerAddr.getAddress())
+                .port(irrelevantTargetServerAddr.getPort())
+                .path("/doesnotmatter")
+                .build().toURL();
+
+        Thread proxyServerThread = null;
+        try (final BadProxyServer proxy = new BadProxyServer(badStatusLine)) {
+
+            proxyServerThread = Thread.ofPlatform().name("proxy-server").start(proxy);
+            final HttpURLConnection urlc = (HttpURLConnection)
+                    url.openConnection(new Proxy(HTTP, proxy.getAddress()));
+
+            final IOException ioe = assertThrows(IOException.class, () -> urlc.getInputStream());
+            final String exMsg = ioe.getMessage();
+            if (exMsg == null || !exMsg.contains(expectedExceptionMsg)) {
+                // unexpected message in the exception, propagate the exception
+                throw ioe;
+            }
+            System.err.println("got excepted exception: " + ioe);
+        } finally {
+            if (proxyServerThread != null) {
+                System.err.println("waiting for proxy server thread to complete");
+                proxyServerThread.join();
+            }
+        }
+    }
+
+    private static final class BadProxyServer implements Runnable, AutoCloseable {
+        private static final int CR = '\r';
+        private static final int LF = '\n';
+
+        private final ServerSocket serverSocket;
+        private final String connectRespStatusLine;
+        private volatile boolean closed;
+
+        /**
+         *
+         * @param connectRespStatusLine the status line that this server writes
+         *                              out in response to a CONNECT request
+         * @throws IOException
+         */
+        BadProxyServer(final String connectRespStatusLine) throws IOException {
+            this.connectRespStatusLine = connectRespStatusLine;
+            final int port = 0;
+            final int backlog = 0;
+            this.serverSocket = new ServerSocket(port, backlog, InetAddress.getLoopbackAddress());
+        }
+
+        InetSocketAddress getAddress() {
+            return (InetSocketAddress) this.serverSocket.getLocalSocketAddress();
+        }
+
+        @Override
+        public void close() {
+            if (this.closed) {
+                return;
+            }
+            synchronized (this) {
+                if (this.closed) {
+                    return;
+                }
+                this.closed = true;
+            }
+            try {
+                this.serverSocket.close();
+            } catch (IOException e) {
+                System.err.println("failed to close proxy server: " + e);
+                e.printStackTrace();
+            }
+        }
+
+        @Override
+        public void run() {
+            try {
+                doRun();
+            } catch (Throwable t) {
+                if (!closed) {
+                    System.err.println("Proxy server ran into exception: " + t);
+                    t.printStackTrace();
+                }
+            }
+            System.err.println("Proxy server " + this.serverSocket + " exiting");
+        }
+
+        private void doRun() throws IOException {
+            while (!closed) {
+                System.err.println("waiting for incoming connection at " + this.serverSocket);
+                try (final Socket accepted = this.serverSocket.accept()) {
+                    System.err.println("accepted incoming connection from " + accepted);
+                    handleIncomingConnection(accepted);
+                }
+            }
+        }
+
+        private static int findCRLF(final byte[] b) {
+            for (int i = 0; i < b.length - 1; i++) {
+                if (b[i] == CR && b[i + 1] == LF) {
+                    return i;
+                }
+            }
+            return -1;
+        }
+
+        // writes out a status line in response to a CONNECT request
+        private void handleIncomingConnection(final Socket acceptedSocket) throws IOException {
+            final byte[] req = readRequest(acceptedSocket.getInputStream());
+            final int crlfIndex = findCRLF(req);
+            if (crlfIndex < 0) {
+                System.err.println("unexpected request content from " + acceptedSocket);
+                // nothing to process, ignore this connection
+                return;
+            }
+            final String requestLine = new String(req, 0, crlfIndex, ISO_8859_1);
+            System.err.println("received request line: \"" + requestLine + "\"");
+            final String[] parts = requestLine.split(" ");
+            if (parts[0].equals("CONNECT")) {
+                // reply back with the status line
+                try (final OutputStream os = acceptedSocket.getOutputStream()) {
+                    System.err.println("responding to CONNECT request from " + acceptedSocket
+                            + ", response status line: \"" + connectRespStatusLine + "\"");
+                    final byte[] statusLine = connectRespStatusLine.getBytes(ISO_8859_1);
+                    os.write(statusLine);
+                }
+            } else {
+                System.err.println("unexpected request from " + acceptedSocket + ": \"" + requestLine + "\"");
+                return;
+            }
+        }
+
+        private static byte[] readRequest(InputStream is) throws IOException {
+            // we don't expect the HTTP request body in this test to be larger than this size
+            final byte[] buff = new byte[4096];
+            int crlfcount = 0;
+            int numRead = 0;
+            int c;
+            while ((c = is.read()) != -1 && numRead < buff.length) {
+                buff[numRead++] = (byte) c;
+                //
+                // HTTP-message = start-line CRLF
+                //               *( field-line CRLF )
+                //               CRLF
+                //               [ message-body ]
+                //
+                // start-line = request-line / status-line
+                //
+                // we are not interested in the message body, so this loop is
+                // looking for the CRLFCRLF sequence to stop parsing the request
+                // content
+                if (c == CR || c == LF) {
+                    switch (crlfcount) {
+                        case 0, 2 -> {
+                            if (c == CR) {
+                                crlfcount++;
+                            }
+                        }
+                        case 1, 3 -> {
+                            if (c == LF) {
+                                crlfcount++;
+                            }
+                        }
+                    }
+                } else {
+                    crlfcount = 0;
+                }
+                if (crlfcount == 4) {
+                    break;
+                }
+            }
+            if (crlfcount != 4) {
+                throw new IOException("Could not locate a CRLFCRLF sequence in the request");
+            }
+            final byte[] request = new byte[numRead];
+            System.arraycopy(buff, 0, request, 0, numRead);
+            return request;
+        }
+    }
+}

From 4fcf913b93bb58d49be20fb99ee4431200ce0dd5 Mon Sep 17 00:00:00 2001
From: Vicente Romero 
Date: Mon, 6 Apr 2026 13:48:34 +0000
Subject: [PATCH 179/359] 8381639: Remove bug id 8381475 from
 test/jdk/tools/sincechecker/modules/jdk.compiler/JdkCompilerCheckSince.java

Reviewed-by: liach
---
 .../modules/jdk.compiler/JdkCompilerCheckSince.java             | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/test/jdk/tools/sincechecker/modules/jdk.compiler/JdkCompilerCheckSince.java b/test/jdk/tools/sincechecker/modules/jdk.compiler/JdkCompilerCheckSince.java
index bf4b906b623..5eb819786e9 100644
--- a/test/jdk/tools/sincechecker/modules/jdk.compiler/JdkCompilerCheckSince.java
+++ b/test/jdk/tools/sincechecker/modules/jdk.compiler/JdkCompilerCheckSince.java
@@ -23,7 +23,7 @@
 
 /*
  * @test
- * @bug 8341399 8381475
+ * @bug 8341399
  * @summary Test for `@since` in jdk.compiler module
  * @library /test/lib /test/jdk/tools/sincechecker
  * @run main SinceChecker jdk.compiler

From 133c0424b9df25ec8fb95404ee64e611ebad31e2 Mon Sep 17 00:00:00 2001
From: Ashutosh Mehra 
Date: Mon, 6 Apr 2026 15:30:55 +0000
Subject: [PATCH 180/359] 8364584: Inconsistency in setting up cpu feature bits

Reviewed-by: kvn, iklam
---
 .../cpu/aarch64/vm_version_aarch64.cpp        | 113 ++++++-------
 .../cpu/aarch64/vm_version_aarch64.hpp        |   2 +
 .../cpu/x86/stubGenerator_x86_64_aes.cpp      |   2 +-
 .../cpu/x86/stubGenerator_x86_64_fmod.cpp     |   2 +-
 src/hotspot/cpu/x86/vm_version_x86.cpp        | 153 ++++++++----------
 src/hotspot/cpu/x86/vm_version_x86.hpp        |   5 +
 .../share/runtime/abstract_vm_version.hpp     |  15 ++
 .../cpuflags/CPUFeaturesClearTest.java        | 143 ++++++++++++++++
 8 files changed, 286 insertions(+), 149 deletions(-)
 create mode 100644 test/hotspot/jtreg/compiler/cpuflags/CPUFeaturesClearTest.java

diff --git a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp
index 8ccffac25a8..b39d1618b3d 100644
--- a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp
@@ -97,8 +97,9 @@ void VM_Version::initialize() {
   _supports_atomic_getadd8 = true;
 
   get_os_cpu_info();
+  _cpu_features = _features;
 
-  int dcache_line = VM_Version::dcache_line_size();
+  int dcache_line = dcache_line_size();
 
   // Limit AllocatePrefetchDistance so that it does not exceed the
   // static constraint of 512 defined in runtime/globals.hpp.
@@ -146,7 +147,7 @@ void VM_Version::initialize() {
     // if dcpop is available publish data cache line flush size via
     // generic field, otherwise let if default to zero thereby
     // disabling writeback
-    if (VM_Version::supports_dcpop()) {
+    if (supports_dcpop()) {
       _data_cache_line_flush_size = dcache_line;
     }
   }
@@ -267,14 +268,24 @@ void VM_Version::initialize() {
     }
   }
 
-  if (FLAG_IS_DEFAULT(UseCRC32)) {
-    UseCRC32 = VM_Version::supports_crc32();
+  if (supports_sha1() || supports_sha256() ||
+      supports_sha3() || supports_sha512()) {
+    if (FLAG_IS_DEFAULT(UseSHA)) {
+      FLAG_SET_DEFAULT(UseSHA, true);
+    } else if (!UseSHA) {
+      clear_feature(CPU_SHA1);
+      clear_feature(CPU_SHA2);
+      clear_feature(CPU_SHA3);
+      clear_feature(CPU_SHA512);
+    }
+  } else if (UseSHA) {
+    warning("SHA instructions are not available on this CPU");
+    FLAG_SET_DEFAULT(UseSHA, false);
   }
 
-  if (UseCRC32 && !VM_Version::supports_crc32()) {
-    warning("UseCRC32 specified, but not supported on this CPU");
-    FLAG_SET_DEFAULT(UseCRC32, false);
-  }
+  CHECK_CPU_FEATURE(supports_crc32, CRC32);
+  CHECK_CPU_FEATURE(supports_lse, LSE);
+  CHECK_CPU_FEATURE(supports_aes, AES);
 
   if (_cpu == CPU_ARM &&
       model_is_in({ CPU_MODEL_ARM_NEOVERSE_V1, CPU_MODEL_ARM_NEOVERSE_V2,
@@ -287,7 +298,7 @@ void VM_Version::initialize() {
     }
   }
 
-  if (UseCryptoPmullForCRC32 && (!VM_Version::supports_pmull() || !VM_Version::supports_sha3() || !VM_Version::supports_crc32())) {
+  if (UseCryptoPmullForCRC32 && (!supports_pmull() || !supports_sha3() || !supports_crc32())) {
     warning("UseCryptoPmullForCRC32 specified, but not supported on this CPU");
     FLAG_SET_DEFAULT(UseCryptoPmullForCRC32, false);
   }
@@ -301,48 +312,40 @@ void VM_Version::initialize() {
     FLAG_SET_DEFAULT(UseVectorizedMismatchIntrinsic, false);
   }
 
-  if (VM_Version::supports_lse()) {
-    if (FLAG_IS_DEFAULT(UseLSE))
-      FLAG_SET_DEFAULT(UseLSE, true);
-  } else {
-    if (UseLSE) {
-      warning("UseLSE specified, but not supported on this CPU");
-      FLAG_SET_DEFAULT(UseLSE, false);
-    }
-  }
-
-  if (VM_Version::supports_aes()) {
-    UseAES = UseAES || FLAG_IS_DEFAULT(UseAES);
-    UseAESIntrinsics =
-        UseAESIntrinsics || (UseAES && FLAG_IS_DEFAULT(UseAESIntrinsics));
-    if (UseAESIntrinsics && !UseAES) {
-      warning("UseAESIntrinsics enabled, but UseAES not, enabling");
-      UseAES = true;
+  if (supports_aes()) {
+    if (FLAG_IS_DEFAULT(UseAESIntrinsics)) {
+      FLAG_SET_DEFAULT(UseAESIntrinsics, true);
     }
     if (FLAG_IS_DEFAULT(UseAESCTRIntrinsics)) {
       FLAG_SET_DEFAULT(UseAESCTRIntrinsics, true);
     }
   } else {
-    if (UseAES) {
-      warning("AES instructions are not available on this CPU");
-      FLAG_SET_DEFAULT(UseAES, false);
-    }
-    if (UseAESIntrinsics) {
-      warning("AES intrinsics are not available on this CPU");
-      FLAG_SET_DEFAULT(UseAESIntrinsics, false);
-    }
-    if (UseAESCTRIntrinsics) {
-      warning("AES/CTR intrinsics are not available on this CPU");
-      FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false);
+    if (!UseAES) {
+      if (UseAESIntrinsics) {
+        warning("AES intrinsics require UseAES flag to be enabled. Intrinsics will be disabled.");
+        FLAG_SET_DEFAULT(UseAESIntrinsics, false);
+      }
+      if (UseAESCTRIntrinsics) {
+        warning("AES/CTR intrinsics require UseAES flag to be enabled. Intrinsics will be disabled.");
+        FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false);
+      }
+    } else if (!cpu_supports_aes()) {
+      if (UseAESIntrinsics) {
+        warning("AES intrinsics are not available on this CPU");
+        FLAG_SET_DEFAULT(UseAESIntrinsics, false);
+      }
+      if (UseAESCTRIntrinsics) {
+        warning("AES/CTR intrinsics are not available on this CPU");
+        FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false);
+      }
     }
   }
 
-
   if (FLAG_IS_DEFAULT(UseCRC32Intrinsics)) {
     UseCRC32Intrinsics = true;
   }
 
-  if (VM_Version::supports_crc32()) {
+  if (supports_crc32()) {
     if (FLAG_IS_DEFAULT(UseCRC32CIntrinsics)) {
       FLAG_SET_DEFAULT(UseCRC32CIntrinsics, true);
     }
@@ -359,17 +362,7 @@ void VM_Version::initialize() {
     UseMD5Intrinsics = true;
   }
 
-  if (VM_Version::supports_sha1() || VM_Version::supports_sha256() ||
-      VM_Version::supports_sha3() || VM_Version::supports_sha512()) {
-    if (FLAG_IS_DEFAULT(UseSHA)) {
-      FLAG_SET_DEFAULT(UseSHA, true);
-    }
-  } else if (UseSHA) {
-    warning("SHA instructions are not available on this CPU");
-    FLAG_SET_DEFAULT(UseSHA, false);
-  }
-
-  if (UseSHA && VM_Version::supports_sha1()) {
+  if (UseSHA && supports_sha1()) {
     if (FLAG_IS_DEFAULT(UseSHA1Intrinsics)) {
       FLAG_SET_DEFAULT(UseSHA1Intrinsics, true);
     }
@@ -378,7 +371,7 @@ void VM_Version::initialize() {
     FLAG_SET_DEFAULT(UseSHA1Intrinsics, false);
   }
 
-  if (UseSHA && VM_Version::supports_sha256()) {
+  if (UseSHA && supports_sha256()) {
     if (FLAG_IS_DEFAULT(UseSHA256Intrinsics)) {
       FLAG_SET_DEFAULT(UseSHA256Intrinsics, true);
     }
@@ -388,7 +381,7 @@ void VM_Version::initialize() {
   }
 
   if (UseSHA) {
-    // No need to check VM_Version::supports_sha3(), since a fallback GPR intrinsic implementation is provided.
+    // No need to check supports_sha3(), since a fallback GPR intrinsic implementation is provided.
     if (FLAG_IS_DEFAULT(UseSHA3Intrinsics)) {
       FLAG_SET_DEFAULT(UseSHA3Intrinsics, true);
     }
@@ -398,7 +391,7 @@ void VM_Version::initialize() {
     FLAG_SET_DEFAULT(UseSHA3Intrinsics, false);
   }
 
-  if (UseSHA3Intrinsics && VM_Version::supports_sha3()) {
+  if (UseSHA3Intrinsics && supports_sha3()) {
     // Auto-enable UseSIMDForSHA3Intrinsic on hardware with performance benefit.
     // Note that the evaluation of SHA3 extension Intrinsics shows better performance
     // on Apple and Qualcomm silicon but worse performance on Neoverse V1 and N2.
@@ -408,12 +401,12 @@ void VM_Version::initialize() {
       }
     }
   }
-  if (UseSHA3Intrinsics && UseSIMDForSHA3Intrinsic && !VM_Version::supports_sha3()) {
+  if (UseSHA3Intrinsics && UseSIMDForSHA3Intrinsic && !supports_sha3()) {
     warning("Intrinsics for SHA3-224, SHA3-256, SHA3-384 and SHA3-512 crypto hash functions not available on this CPU.");
     FLAG_SET_DEFAULT(UseSHA3Intrinsics, false);
   }
 
-  if (UseSHA && VM_Version::supports_sha512()) {
+  if (UseSHA && supports_sha512()) {
     if (FLAG_IS_DEFAULT(UseSHA512Intrinsics)) {
       FLAG_SET_DEFAULT(UseSHA512Intrinsics, true);
     }
@@ -426,7 +419,7 @@ void VM_Version::initialize() {
     FLAG_SET_DEFAULT(UseSHA, false);
   }
 
-  if (VM_Version::supports_pmull()) {
+  if (supports_pmull()) {
     if (FLAG_IS_DEFAULT(UseGHASHIntrinsics)) {
       FLAG_SET_DEFAULT(UseGHASHIntrinsics, true);
     }
@@ -477,7 +470,7 @@ void VM_Version::initialize() {
       FLAG_SET_DEFAULT(UseBlockZeroing, true);
     }
     if (FLAG_IS_DEFAULT(BlockZeroingLowLimit)) {
-      FLAG_SET_DEFAULT(BlockZeroingLowLimit, 4 * VM_Version::zva_length());
+      FLAG_SET_DEFAULT(BlockZeroingLowLimit, 4 * zva_length());
     }
   } else if (UseBlockZeroing) {
     if (!FLAG_IS_DEFAULT(UseBlockZeroing)) {
@@ -486,11 +479,11 @@ void VM_Version::initialize() {
     FLAG_SET_DEFAULT(UseBlockZeroing, false);
   }
 
-  if (VM_Version::supports_sve2()) {
+  if (supports_sve2()) {
     if (FLAG_IS_DEFAULT(UseSVE)) {
       FLAG_SET_DEFAULT(UseSVE, 2);
     }
-  } else if (VM_Version::supports_sve()) {
+  } else if (supports_sve()) {
     if (FLAG_IS_DEFAULT(UseSVE)) {
       FLAG_SET_DEFAULT(UseSVE, 1);
     } else if (UseSVE > 1) {
@@ -541,7 +534,7 @@ void VM_Version::initialize() {
     // 1) this code has been built with branch-protection and
     // 2) the CPU/OS supports it
 #ifdef __ARM_FEATURE_PAC_DEFAULT
-    if (!VM_Version::supports_paca()) {
+    if (!supports_paca()) {
       // Disable PAC to prevent illegal instruction crashes.
       warning("ROP-protection specified, but not supported on this CPU. Disabling ROP-protection.");
     } else {
diff --git a/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp b/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp
index 378524fe168..f8274554f1c 100644
--- a/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp
+++ b/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp
@@ -193,6 +193,8 @@ public:
     return (features & BIT_MASK(flag)) != 0;
   }
 
+  static bool cpu_supports_aes()      { return supports_feature(_cpu_features, CPU_AES); }
+
   static int cpu_family()                     { return _cpu; }
   static int cpu_model()                      { return _model; }
   static int cpu_model2()                     { return _model2; }
diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp
index 1fa80c9d967..162c92d5190 100644
--- a/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp
+++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp
@@ -220,7 +220,7 @@ void StubGenerator::generate_aes_stubs() {
       StubRoutines::_cipherBlockChaining_decryptAESCrypt = generate_cipherBlockChaining_decryptAESCrypt_Parallel();
       StubRoutines::_electronicCodeBook_encryptAESCrypt = generate_electronicCodeBook_encryptAESCrypt_Parallel();
       StubRoutines::_electronicCodeBook_decryptAESCrypt = generate_electronicCodeBook_decryptAESCrypt_Parallel();
-      if (VM_Version::supports_avx2()) {
+      if (VM_Version::supports_avx2() && VM_Version::supports_clmul()) {
           StubRoutines::_galoisCounterMode_AESCrypt = generate_avx2_galoisCounterMode_AESCrypt();
       }
     }
diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_fmod.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_fmod.cpp
index b1eaa4b8031..a0962943556 100644
--- a/src/hotspot/cpu/x86/stubGenerator_x86_64_fmod.cpp
+++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_fmod.cpp
@@ -78,7 +78,7 @@ address StubGenerator::generate_libmFmod() {
   address start = __ pc();
   __ enter(); // required for proper stackwalking of RuntimeStub frame
 
-  if (VM_Version::supports_avx512vlbwdq()) {     // AVX512 version
+  if (VM_Version::supports_avx512vlbwdq() && VM_Version::supports_fma()) {     // AVX512 version
 
     // Source used to generate the AVX512 fmod assembly below:
     //
diff --git a/src/hotspot/cpu/x86/vm_version_x86.cpp b/src/hotspot/cpu/x86/vm_version_x86.cpp
index fc4cfbc5a8b..7899a2f7e51 100644
--- a/src/hotspot/cpu/x86/vm_version_x86.cpp
+++ b/src/hotspot/cpu/x86/vm_version_x86.cpp
@@ -1094,15 +1094,35 @@ void VM_Version::get_processor_features() {
     }
   }
 
-    // Currently APX support is only enabled for targets supporting AVX512VL feature.
-  bool apx_supported = os_supports_apx_egprs() && supports_apx_f() && supports_avx512vl();
-  if (UseAPX && !apx_supported) {
-    warning("UseAPX is not supported on this CPU, setting it to false");
+  // Currently APX support is only enabled for targets supporting AVX512VL feature.
+  if (supports_apx_f() && os_supports_apx_egprs() && supports_avx512vl()) {
+    if (FLAG_IS_DEFAULT(UseAPX)) {
+      UseAPX = false; // by default UseAPX is false
+    } else if (!UseAPX) {
+      _features.clear_feature(CPU_APX_F);
+    }
+  } else if (UseAPX) {
+    if (!FLAG_IS_DEFAULT(UseAPX)) {
+      warning("APX is not supported on this CPU, setting it to false)");
+    }
     FLAG_SET_DEFAULT(UseAPX, false);
   }
 
-  if (!UseAPX) {
-    _features.clear_feature(CPU_APX_F);
+  CHECK_CPU_FEATURE(supports_clmul, CLMUL);
+  CHECK_CPU_FEATURE(supports_aes, AES);
+  CHECK_CPU_FEATURE(supports_fma, FMA);
+
+  if (supports_sha() || (supports_avx2() && supports_bmi2())) {
+    if (FLAG_IS_DEFAULT(UseSHA)) {
+      UseSHA = true;
+    } else if (!UseSHA) {
+      _features.clear_feature(CPU_SHA);
+    }
+  } else if (UseSHA) {
+    if (!FLAG_IS_DEFAULT(UseSHA)) {
+      warning("SHA instructions are not available on this CPU");
+    }
+    FLAG_SET_DEFAULT(UseSHA, false);
   }
 
   if (FLAG_IS_DEFAULT(IntelJccErratumMitigation)) {
@@ -1152,9 +1172,40 @@ void VM_Version::get_processor_features() {
 
   // Use AES instructions if available.
   if (supports_aes()) {
-    if (FLAG_IS_DEFAULT(UseAES)) {
-      FLAG_SET_DEFAULT(UseAES, true);
+    if (supports_sse3()) {
+      if (FLAG_IS_DEFAULT(UseAESIntrinsics)) {
+        FLAG_SET_DEFAULT(UseAESIntrinsics, true);
+      }
+    } else if (UseAESIntrinsics) {
+      // The AES intrinsic stubs require AES instruction support (of course)
+      // but also require sse3 mode or higher for instructions it use.
+      if (!FLAG_IS_DEFAULT(UseAESIntrinsics)) {
+        warning("X86 AES intrinsics require SSE3 instructions or higher. Intrinsics will be disabled.");
+      }
+      FLAG_SET_DEFAULT(UseAESIntrinsics, false);
     }
+    if (!UseAESIntrinsics) {
+      if (UseAESCTRIntrinsics) {
+        if (FLAG_IS_DEFAULT(UseAESCTRIntrinsics)) {
+          warning("AES-CTR intrinsics require UseAESIntrinsics flag to be enabled. Intrinsics will be disabled.");
+        }
+        FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false);
+      }
+    } else {
+      if (supports_sse4_1()) {
+        if (FLAG_IS_DEFAULT(UseAESCTRIntrinsics)) {
+          FLAG_SET_DEFAULT(UseAESCTRIntrinsics, true);
+        }
+      } else if (UseAESCTRIntrinsics) {
+        // The AES-CTR intrinsic stubs require AES instruction support (of course)
+        // but also require sse4.1 mode or higher for instructions it use.
+        if (!FLAG_IS_DEFAULT(UseAESCTRIntrinsics)) {
+          warning("X86 AES-CTR intrinsics require SSE4.1 instructions or higher. Intrinsics will be disabled.");
+        }
+        FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false);
+      }
+    }
+  } else {
     if (!UseAES) {
       if (UseAESIntrinsics && !FLAG_IS_DEFAULT(UseAESIntrinsics)) {
         warning("AES intrinsics require UseAES flag to be enabled. Intrinsics will be disabled.");
@@ -1164,66 +1215,16 @@ void VM_Version::get_processor_features() {
         warning("AES_CTR intrinsics require UseAES flag to be enabled. AES_CTR intrinsics will be disabled.");
       }
       FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false);
-    } else {
-      if (UseSSE > 2) {
-        if (FLAG_IS_DEFAULT(UseAESIntrinsics)) {
-          FLAG_SET_DEFAULT(UseAESIntrinsics, true);
-        }
-      } else {
-        // The AES intrinsic stubs require AES instruction support (of course)
-        // but also require sse3 mode or higher for instructions it use.
-        if (UseAESIntrinsics && !FLAG_IS_DEFAULT(UseAESIntrinsics)) {
-          warning("X86 AES intrinsics require SSE3 instructions or higher. Intrinsics will be disabled.");
-        }
-        FLAG_SET_DEFAULT(UseAESIntrinsics, false);
+    } else if (!cpu_supports_aes()) {
+      if (UseAESIntrinsics && !FLAG_IS_DEFAULT(UseAESIntrinsics)) {
+        warning("AES intrinsics are not available on this CPU");
       }
-
-      // --AES-CTR begins--
-      if (!UseAESIntrinsics) {
-        if (UseAESCTRIntrinsics && !FLAG_IS_DEFAULT(UseAESCTRIntrinsics)) {
-          warning("AES-CTR intrinsics require UseAESIntrinsics flag to be enabled. Intrinsics will be disabled.");
-        }
-        FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false);
-      } else {
-        if (supports_sse4_1()) {
-          if (FLAG_IS_DEFAULT(UseAESCTRIntrinsics)) {
-            FLAG_SET_DEFAULT(UseAESCTRIntrinsics, true);
-          }
-        } else {
-           // The AES-CTR intrinsic stubs require AES instruction support (of course)
-           // but also require sse4.1 mode or higher for instructions it use.
-          if (UseAESCTRIntrinsics && !FLAG_IS_DEFAULT(UseAESCTRIntrinsics)) {
-             warning("X86 AES-CTR intrinsics require SSE4.1 instructions or higher. Intrinsics will be disabled.");
-           }
-           FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false);
-        }
+      FLAG_SET_DEFAULT(UseAESIntrinsics, false);
+      if (UseAESCTRIntrinsics && !FLAG_IS_DEFAULT(UseAESCTRIntrinsics)) {
+        warning("AES-CTR intrinsics are not available on this CPU");
       }
-      // --AES-CTR ends--
+      FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false);
     }
-  } else if (UseAES || UseAESIntrinsics || UseAESCTRIntrinsics) {
-    if (UseAES && !FLAG_IS_DEFAULT(UseAES)) {
-      warning("AES instructions are not available on this CPU");
-    }
-    FLAG_SET_DEFAULT(UseAES, false);
-    if (UseAESIntrinsics && !FLAG_IS_DEFAULT(UseAESIntrinsics)) {
-      warning("AES intrinsics are not available on this CPU");
-    }
-    FLAG_SET_DEFAULT(UseAESIntrinsics, false);
-    if (UseAESCTRIntrinsics && !FLAG_IS_DEFAULT(UseAESCTRIntrinsics)) {
-      warning("AES-CTR intrinsics are not available on this CPU");
-    }
-    FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false);
-  }
-
-  // Use CLMUL instructions if available.
-  if (supports_clmul()) {
-    if (FLAG_IS_DEFAULT(UseCLMUL)) {
-      UseCLMUL = true;
-    }
-  } else if (UseCLMUL) {
-    if (!FLAG_IS_DEFAULT(UseCLMUL))
-      warning("CLMUL instructions not available on this CPU (AVX may also be required)");
-    FLAG_SET_DEFAULT(UseCLMUL, false);
   }
 
   if (UseCLMUL && (UseSSE > 2)) {
@@ -1323,32 +1324,10 @@ void VM_Version::get_processor_features() {
     FLAG_SET_DEFAULT(UseBASE64Intrinsics, false);
   }
 
-  if (supports_fma()) {
-    if (FLAG_IS_DEFAULT(UseFMA)) {
-      UseFMA = true;
-    }
-  } else if (UseFMA) {
-    if (!FLAG_IS_DEFAULT(UseFMA)) {
-      warning("FMA instructions are not available on this CPU");
-    }
-    FLAG_SET_DEFAULT(UseFMA, false);
-  }
-
   if (FLAG_IS_DEFAULT(UseMD5Intrinsics)) {
     UseMD5Intrinsics = true;
   }
 
-  if (supports_sha() || (supports_avx2() && supports_bmi2())) {
-    if (FLAG_IS_DEFAULT(UseSHA)) {
-      UseSHA = true;
-    }
-  } else if (UseSHA) {
-    if (!FLAG_IS_DEFAULT(UseSHA)) {
-      warning("SHA instructions are not available on this CPU");
-    }
-    FLAG_SET_DEFAULT(UseSHA, false);
-  }
-
   if (supports_sha() && supports_sse4_1() && UseSHA) {
     if (FLAG_IS_DEFAULT(UseSHA1Intrinsics)) {
       FLAG_SET_DEFAULT(UseSHA1Intrinsics, true);
diff --git a/src/hotspot/cpu/x86/vm_version_x86.hpp b/src/hotspot/cpu/x86/vm_version_x86.hpp
index 4f3580d216c..f721635a02e 100644
--- a/src/hotspot/cpu/x86/vm_version_x86.hpp
+++ b/src/hotspot/cpu/x86/vm_version_x86.hpp
@@ -535,6 +535,10 @@ protected:
 
   static const char* _features_names[];
 
+  static void clear_feature(Feature_Flag feature) {
+    _features.clear_feature(feature);
+  }
+
   static void clear_cpu_features() {
     _features = VM_Features();
     _cpu_features = VM_Features();
@@ -930,6 +934,7 @@ public:
   // Feature identification not affected by VM flags
   //
   static bool cpu_supports_evex()     { return _cpu_features.supports_feature(CPU_AVX512F); }
+  static bool cpu_supports_aes()      { return _cpu_features.supports_feature(CPU_AES); }
 
   static bool supports_avx512_simd_sort() {
     if (supports_avx512dq()) {
diff --git a/src/hotspot/share/runtime/abstract_vm_version.hpp b/src/hotspot/share/runtime/abstract_vm_version.hpp
index 17ade2c068d..61a8aa84080 100644
--- a/src/hotspot/share/runtime/abstract_vm_version.hpp
+++ b/src/hotspot/share/runtime/abstract_vm_version.hpp
@@ -45,6 +45,21 @@ class outputStream;
 class stringStream;
 enum class vmIntrinsicID;
 
+// Helper macro to test and set VM flag and corresponding cpu feature
+#define CHECK_CPU_FEATURE(feature_test_fn, feature) \
+  if (feature_test_fn()) { \
+    if (FLAG_IS_DEFAULT(Use##feature)) { \
+      FLAG_SET_DEFAULT(Use##feature, true); \
+    } else if (!Use##feature) { \
+      clear_feature(CPU_##feature); \
+    } \
+  } else if (Use##feature) { \
+    if (!FLAG_IS_DEFAULT(Use##feature)) { \
+      warning(#feature " instructions not available on this CPU"); \
+    } \
+    FLAG_SET_DEFAULT(Use##feature, false); \
+  }
+
 // Abstract_VM_Version provides information about the VM.
 
 class Abstract_VM_Version: AllStatic {
diff --git a/test/hotspot/jtreg/compiler/cpuflags/CPUFeaturesClearTest.java b/test/hotspot/jtreg/compiler/cpuflags/CPUFeaturesClearTest.java
new file mode 100644
index 00000000000..a0fb3525381
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/cpuflags/CPUFeaturesClearTest.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please 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
+ * @library /test/lib /
+ * @modules java.base/jdk.internal.misc
+ *          java.management
+ * @requires os.simpleArch == "x64" | os.simpleArch == "aarch64"
+ * @build jdk.test.whitebox.WhiteBox
+ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
+ * @run main/othervm/timeout=600 -Xbootclasspath/a:.
+ *                   -XX:+UnlockDiagnosticVMOptions
+ *                   -XX:+WhiteBoxAPI -Xbatch
+ *                   compiler.cpuflags.CPUFeaturesClearTest
+ */
+
+package compiler.cpuflags;
+
+import java.util.List;
+
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.Platform;
+import jdk.test.lib.process.ProcessTools;
+import jdk.test.whitebox.WhiteBox;
+import jdk.test.whitebox.cpuinfo.CPUInfo;
+import static jdk.test.lib.cli.CommandLineOptionTest.*;
+
+public class CPUFeaturesClearTest {
+    private static List cpuFeaturesList;
+    public void runTestCases() throws Throwable {
+        if (Platform.isX64()) {
+            testX86Flags();
+        } else if (Platform.isAArch64()) {
+            testAArch64Flags();
+        }
+    }
+
+    String[] generateArgs(String vmFlag) {
+        String[] args = {"-Xlog:os+cpu", "-XX:+UnlockDiagnosticVMOptions", vmFlag, "-version"};
+        return args;
+    }
+
+    public void testX86Flags() throws Throwable {
+        OutputAnalyzer outputAnalyzer;
+        String vmFlagsToTest[] = {"UseCLMUL", "UseAES", "UseFMA", "UseSHA"};
+        String cpuFeatures[] =   {"clmul",    "aes",    "fma",    "sha"};
+        for (int i = 0; i < vmFlagsToTest.length; i++) {
+            String vmFlag = vmFlagsToTest[i];
+            String cpuFeature = cpuFeatures[i];
+            outputAnalyzer = ProcessTools.executeTestJava(generateArgs(prepareBooleanFlag(vmFlag, false)));
+            outputAnalyzer.shouldNotMatch("[os,cpu] CPU: .* " + cpuFeatures[i] + ".*");
+        }
+        if (isCpuFeatureSupported("sse4")) {
+            outputAnalyzer = ProcessTools.executeTestJava(generateArgs(prepareNumericFlag("UseSSE", 3)));
+            outputAnalyzer.shouldNotMatch("[os,cpu] CPU: .* sse4.*");
+        }
+        if (isCpuFeatureSupported("sse3")) {
+            outputAnalyzer = ProcessTools.executeTestJava(generateArgs(prepareNumericFlag("UseSSE", 2)));
+            outputAnalyzer.shouldNotMatch("[os,cpu] CPU: .* sse3.*");
+            outputAnalyzer.shouldNotMatch("[os,cpu] CPU: .* ssse3.*");
+        }
+        if (isCpuFeatureSupported("sse2")) {
+            outputAnalyzer = ProcessTools.executeTestJava(generateArgs(prepareNumericFlag("UseSSE", 1)));
+            outputAnalyzer.shouldNotMatch("[os,cpu] CPU: .* sse2.*");
+        }
+        if (isCpuFeatureSupported("sse")) {
+            outputAnalyzer = ProcessTools.executeTestJava(generateArgs(prepareNumericFlag("UseSSE", 0)));
+            outputAnalyzer.shouldNotMatch("[os,cpu] CPU: .* sse.*");
+        }
+        if (isCpuFeatureSupported("avx512f")) {
+            outputAnalyzer = ProcessTools.executeTestJava(generateArgs(prepareNumericFlag("UseAVX", 2)));
+            outputAnalyzer.shouldNotMatch("[os,cpu] CPU: .* avx512.*");
+        }
+        if (isCpuFeatureSupported("avx2")) {
+            outputAnalyzer = ProcessTools.executeTestJava(generateArgs(prepareNumericFlag("UseAVX", 1)));
+            outputAnalyzer.shouldNotMatch("[os,cpu] CPU: .* avx2.*");
+        }
+        if (isCpuFeatureSupported("avx")) {
+            outputAnalyzer = ProcessTools.executeTestJava(generateArgs(prepareNumericFlag("UseAVX", 0)));
+            outputAnalyzer.shouldNotMatch("[os,cpu] CPU: .* avx.*");
+        }
+    }
+
+    public void testAArch64Flags() throws Throwable {
+        OutputAnalyzer outputAnalyzer;
+        String vmFlagsToTest[] = {"UseCRC32", "UseLSE", "UseAES"};
+        String cpuFeatures[] =   {"crc32",    "lse",    "aes"};
+        for (int i = 0; i < vmFlagsToTest.length; i++) {
+            String vmFlag = vmFlagsToTest[i];
+            String cpuFeature = cpuFeatures[i];
+            outputAnalyzer = ProcessTools.executeTestJava(generateArgs(prepareBooleanFlag(vmFlag, false)));
+            outputAnalyzer.shouldNotMatch("[os,cpu] CPU: .* " + cpuFeatures[i] + ".*");
+        }
+
+        // Disabling UseSHA should clear all shaXXX cpu features
+        outputAnalyzer = ProcessTools.executeTestJava(generateArgs(prepareBooleanFlag("UseSHA", false)));
+        outputAnalyzer.shouldNotMatch("[os,cpu] CPU: .* sha1.*");
+        outputAnalyzer.shouldNotMatch("[os,cpu] CPU: .* sha256.*");
+        outputAnalyzer.shouldNotMatch("[os,cpu] CPU: .* sha3.*");
+        outputAnalyzer.shouldNotMatch("[os,cpu] CPU: .* sha512.*");
+
+        if (isCpuFeatureSupported("sve2")) {
+            outputAnalyzer = ProcessTools.executeTestJava(generateArgs(prepareNumericFlag("UseSVE", 1)));
+            outputAnalyzer.shouldNotMatch("[os,cpu] CPU: .* sve2.*");
+            verifyOutput(null, new String[]{"sve2"}, null, outputAnalyzer);
+        }
+        if (isCpuFeatureSupported("sve")) {
+            outputAnalyzer = ProcessTools.executeTestJava(generateArgs(prepareNumericFlag("UseSVE", 0)));
+            outputAnalyzer.shouldNotMatch("[os,cpu] CPU: .* sve.*");
+            verifyOutput(null, new String[]{"sve"}, null, outputAnalyzer);
+        }
+    }
+
+    static boolean isCpuFeatureSupported(String feature) {
+        return cpuFeaturesList.contains(feature);
+    }
+
+    public static void main(String args[]) throws Throwable {
+        cpuFeaturesList = CPUInfo.getFeatures();
+        new CPUFeaturesClearTest().runTestCases();
+    }
+}

From e79692881fab1d4c986b72a08f73bfc1b19f39b7 Mon Sep 17 00:00:00 2001
From: Ashay Rane <253344819+raneashay@users.noreply.github.com>
Date: Mon, 6 Apr 2026 15:44:19 +0000
Subject: [PATCH 181/359] 8381449: Build fails when Windows is not installed on
 C:

Reviewed-by: ysuenaga, erikj, lmesnik
---
 make/autoconf/toolchain_microsoft.m4     | 12 +++++++-----
 make/scripts/fixpath.sh                  |  5 ++++-
 test/jdk/com/sun/jdi/JdbReadTwiceTest.sh | 12 +++++++++---
 3 files changed, 20 insertions(+), 9 deletions(-)

diff --git a/make/autoconf/toolchain_microsoft.m4 b/make/autoconf/toolchain_microsoft.m4
index f577cf1a2a1..afe04acf029 100644
--- a/make/autoconf/toolchain_microsoft.m4
+++ b/make/autoconf/toolchain_microsoft.m4
@@ -217,10 +217,12 @@ AC_DEFUN([TOOLCHAIN_FIND_VISUAL_STUDIO_BAT_FILE],
     TOOLCHAIN_CHECK_POSSIBLE_VISUAL_STUDIO_ROOT([$TARGET_CPU], [$VS_VERSION],
         [$PROGRAMFILES_X86/$VS_INSTALL_DIR], [well-known name])
   fi
+  # Derive system drive root from CMD (which is at /windows/system32/cmd.exe)
+  WINSYSDRIVE_ROOT="$(dirname "$(dirname "$(dirname "$CMD")")")"
   TOOLCHAIN_CHECK_POSSIBLE_VISUAL_STUDIO_ROOT([$TARGET_CPU], [$VS_VERSION],
-      [c:/program files/$VS_INSTALL_DIR], [well-known name])
+      [$WINSYSDRIVE_ROOT/program files/$VS_INSTALL_DIR], [well-known name])
   TOOLCHAIN_CHECK_POSSIBLE_VISUAL_STUDIO_ROOT([$TARGET_CPU], [$VS_VERSION],
-      [c:/program files (x86)/$VS_INSTALL_DIR], [well-known name])
+      [$WINSYSDRIVE_ROOT/program files (x86)/$VS_INSTALL_DIR], [well-known name])
   if test "x$SDK_INSTALL_DIR" != x; then
     if test "x$ProgramW6432" != x; then
       TOOLCHAIN_CHECK_POSSIBLE_WIN_SDK_ROOT([$TARGET_CPU], [$VS_VERSION],
@@ -235,9 +237,9 @@ AC_DEFUN([TOOLCHAIN_FIND_VISUAL_STUDIO_BAT_FILE],
           [$PROGRAMFILES/$SDK_INSTALL_DIR], [well-known name])
     fi
     TOOLCHAIN_CHECK_POSSIBLE_WIN_SDK_ROOT([$TARGET_CPU], [$VS_VERSION],
-        [c:/program files/$SDK_INSTALL_DIR], [well-known name])
+        [$WINSYSDRIVE_ROOT/program files/$SDK_INSTALL_DIR], [well-known name])
     TOOLCHAIN_CHECK_POSSIBLE_WIN_SDK_ROOT([$TARGET_CPU], [$VS_VERSION],
-        [c:/program files (x86)/$SDK_INSTALL_DIR], [well-known name])
+        [$WINSYSDRIVE_ROOT/program files (x86)/$SDK_INSTALL_DIR], [well-known name])
   fi
 
   VCVARS_VER=auto
@@ -338,7 +340,7 @@ AC_DEFUN([TOOLCHAIN_EXTRACT_VISUAL_STUDIO_ENV],
   OLDPATH="$PATH"
   # Make sure we only capture additions to PATH needed by VS.
   # Clear out path, but need system dir present for vsvars cmd file to be able to run
-  export PATH=$WINENV_PREFIX/c/windows/system32
+  export PATH="$(dirname "$CMD")"
   # The "| cat" is to stop SetEnv.Cmd to mess with system colors on some systems
   # We can't pass -vcvars_ver=$VCVARS_VER here because cmd.exe eats all '='
   # in bat file arguments. :-(
diff --git a/make/scripts/fixpath.sh b/make/scripts/fixpath.sh
index 6a524df4c68..78690f1f2cc 100644
--- a/make/scripts/fixpath.sh
+++ b/make/scripts/fixpath.sh
@@ -88,7 +88,10 @@ function setup() {
   fi
 
   if [[ -z ${CMD+x} ]]; then
-    CMD="$DRIVEPREFIX/c/windows/system32/cmd.exe"
+    CMD="$(type -p cmd.exe 2>/dev/null)"
+    if [[ -z "$CMD" ]]; then
+      CMD="$DRIVEPREFIX/c/windows/system32/cmd.exe"
+    fi
   fi
 
   if [[ -z ${WINTEMP+x} ]]; then
diff --git a/test/jdk/com/sun/jdi/JdbReadTwiceTest.sh b/test/jdk/com/sun/jdi/JdbReadTwiceTest.sh
index 5902abe50ad..8103fb6f01d 100644
--- a/test/jdk/com/sun/jdi/JdbReadTwiceTest.sh
+++ b/test/jdk/com/sun/jdi/JdbReadTwiceTest.sh
@@ -68,6 +68,12 @@ jdbFiles="$HOME/jdb.ini $HOME/.jdbrc $here/jdb.ini $here/.jdbrc $tmpResult $fred
 cd $here
 failed=
 
+target_os=$($TESTJAVA/bin/java -XshowSettings:all 2>&1 | grep 'os.name' | grep -i 'windows')
+if [ -n "$target_os" ]; then
+    IS_WINDOWS=true
+else
+    IS_WINDOWS=false
+fi
 
 mkFiles()
 {
@@ -84,7 +90,7 @@ failIfNot()
     # $1 is the expected number of occurances of $2 in the jdb output.
     count=$1
     shift
-    if [ -r c:/ ] ; then
+    if [ "${IS_WINDOWS}" = "true" ] ; then
        sed -e 's@\\@/@g' $tmpResult > $tmpResult.1
        mv $tmpResult.1 $tmpResult
     fi
@@ -177,7 +183,7 @@ mkFiles $HOME/.jdbrc $here/jdb.ini
     clean
 
 
-if [ ! -r c:/ ] ; then
+if [ "${IS_WINDOWS}" != "true" ] ; then
     # No symlinks on windows.
     echo
     echo "+++++++++++++++++++++++++++++++++++"
@@ -191,7 +197,7 @@ if [ ! -r c:/ ] ; then
 fi
 
 
-if [ ! -r c:/ ] ; then
+if [ "${IS_WINDOWS}" != "true" ] ; then
     # No symlinks on windows.
     echo
     echo "+++++++++++++++++++++++++++++++++++"

From ef2e5379f5290fd1d8a57c9e11544b03c86d1b3b Mon Sep 17 00:00:00 2001
From: Robert Toyonaga 
Date: Mon, 6 Apr 2026 21:00:36 +0000
Subject: [PATCH 182/359] 8380467: JFR: RepositoryFiles.updatePaths() searches
 for chunkfiles incorrectly

Reviewed-by: egahlin
---
 .../internal/consumer/RepositoryFiles.java    |  8 +-
 .../streaming/TestRepositoryFilesRescan.java  | 97 +++++++++++++++++++
 2 files changed, 101 insertions(+), 4 deletions(-)
 create mode 100644 test/jdk/jdk/jfr/api/consumer/streaming/TestRepositoryFilesRescan.java

diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/RepositoryFiles.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/RepositoryFiles.java
index 09b64efbdd0..1e875691537 100644
--- a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/RepositoryFiles.java
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/RepositoryFiles.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -181,9 +181,9 @@ public final class RepositoryFiles {
             List added = new ArrayList<>();
             Set current = new HashSet<>();
             for (Path p : dirStream) {
-                if (!pathLookup.containsKey(p)) {
-                    String s = p.toString();
-                    if (s.endsWith(".jfr")) {
+                String s = p.toString();
+                if (s.endsWith(".jfr")) {
+                    if (!pathLookup.containsKey(p)) {
                         added.add(p);
                         Logger.log(LogTag.JFR_SYSTEM_STREAMING, LogLevel.DEBUG, "New file found: " + p.toAbsolutePath());
                     }
diff --git a/test/jdk/jdk/jfr/api/consumer/streaming/TestRepositoryFilesRescan.java b/test/jdk/jdk/jfr/api/consumer/streaming/TestRepositoryFilesRescan.java
new file mode 100644
index 00000000000..0cb80d18698
--- /dev/null
+++ b/test/jdk/jdk/jfr/api/consumer/streaming/TestRepositoryFilesRescan.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jfr.api.consumer.streaming;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import jdk.jfr.Recording;
+import jdk.jfr.internal.consumer.RepositoryFiles;
+import jdk.test.lib.Asserts;
+
+/**
+ * @test
+ * @summary Verifies that RepositoryFiles does not oscillate between
+ *          forgetting and rediscovering chunk files between scans
+ * @requires vm.hasJFR
+ * @library /test/lib
+ * @modules jdk.jfr/jdk.jfr.internal.consumer
+ * @run main/othervm jdk.jfr.api.consumer.streaming.TestRepositoryFilesRescan
+ */
+public class TestRepositoryFilesRescan {
+
+    public static void main(String... args) throws Exception {
+        Path dir = Files.createTempDirectory("jfr-rescan-test");
+        try {
+            createChunkFile(dir, "chunk1.jfr");
+            createChunkFile(dir, "chunk2.jfr");
+            testNoOscillation(dir);
+        } finally {
+            deleteDirectory(dir);
+        }
+    }
+
+    /**
+     * firstPath(0, false) will return non-null only when updatePaths discovers
+     * genuinely new chunk files; with no files added or removed between
+     * calls the result must be null after the first successful call.
+     */
+    private static void testNoOscillation(Path dir) {
+        RepositoryFiles rf = new RepositoryFiles(dir, false);
+        Asserts.assertNotNull(rf.firstPath(0, false), "Call 1: expected non-null (initial discovery of .jfr files)");
+
+        Path p2 = rf.firstPath(0, false);
+        Asserts.assertNull(p2, "Call 2: expected null (no new chunks), got " + p2);
+
+        // Call 3: still no new files.  This confirms call 2 did not wipe pathLookup, making all files look "new" again.
+        Path p3 = rf.firstPath(0, false);
+        Asserts.assertNull(p3, "Call 3: expected null (no new chunks), got " + p3
+            + " — pathLookup is oscillating between populated and empty");
+    }
+
+    private static void createChunkFile(Path dir, String name) throws Exception {
+        try (Recording r = new Recording()) {
+            r.start();
+            Thread.sleep(20);
+            r.stop();
+            r.dump(dir.resolve(name));
+        }
+    }
+
+    private static void deleteDirectory(Path dir) {
+        try {
+            try (var stream = Files.list(dir)) {
+                stream.forEach(p -> {
+                    try {
+                        Files.deleteIfExists(p);
+                    } catch (Exception e) {
+                        // Do nothing
+                    }
+                });
+            }
+            Files.deleteIfExists(dir);
+        } catch (Exception e) {
+            // best-effort cleanup
+        }
+    }
+}

From 273167f7236682401f1ea852b4b7c97445965952 Mon Sep 17 00:00:00 2001
From: Vladimir Kozlov 
Date: Mon, 6 Apr 2026 23:25:36 +0000
Subject: [PATCH 183/359] 8381683: Pass temp registers and use them in
 CardTableBarrierSetAssembler::store_check() on Aarch64

Reviewed-by: iveresov, vlivanov, aph
---
 .../cardTableBarrierSetAssembler_aarch64.cpp  | 20 ++++++++++---------
 .../cardTableBarrierSetAssembler_aarch64.hpp  |  2 +-
 .../cardTableBarrierSetAssembler_x86.cpp      |  4 +++-
 3 files changed, 15 insertions(+), 11 deletions(-)

diff --git a/src/hotspot/cpu/aarch64/gc/shared/cardTableBarrierSetAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/shared/cardTableBarrierSetAssembler_aarch64.cpp
index 0bfc320179d..a9c320912cb 100644
--- a/src/hotspot/cpu/aarch64/gc/shared/cardTableBarrierSetAssembler_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/gc/shared/cardTableBarrierSetAssembler_aarch64.cpp
@@ -56,8 +56,10 @@ void CardTableBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet d
   }
 }
 
-void CardTableBarrierSetAssembler::store_check(MacroAssembler* masm, Register obj, Address dst) {
-
+void CardTableBarrierSetAssembler::store_check(MacroAssembler* masm, Register obj, Address dst, Register tmp1, Register tmp2) {
+  precond(tmp1 != noreg);
+  precond(tmp2 != noreg);
+  assert_different_registers(obj, tmp1, tmp2);
   BarrierSet* bs = BarrierSet::barrier_set();
   assert(bs->kind() == BarrierSet::CardTableBarrierSet, "Wrong barrier set kind");
 
@@ -65,16 +67,16 @@ void CardTableBarrierSetAssembler::store_check(MacroAssembler* masm, Register ob
 
   assert(CardTable::dirty_card_val() == 0, "must be");
 
-  __ load_byte_map_base(rscratch1);
+  __ load_byte_map_base(tmp1);
 
   if (UseCondCardMark) {
     Label L_already_dirty;
-    __ ldrb(rscratch2,  Address(obj, rscratch1));
-    __ cbz(rscratch2, L_already_dirty);
-    __ strb(zr, Address(obj, rscratch1));
+    __ ldrb(tmp2,  Address(obj, tmp1));
+    __ cbz(tmp2, L_already_dirty);
+    __ strb(zr, Address(obj, tmp1));
     __ bind(L_already_dirty);
   } else {
-    __ strb(zr, Address(obj, rscratch1));
+    __ strb(zr, Address(obj, tmp1));
   }
 }
 
@@ -112,10 +114,10 @@ void CardTableBarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorS
   if (needs_post_barrier) {
     // flatten object address if needed
     if (!precise || (dst.index() == noreg && dst.offset() == 0)) {
-      store_check(masm, dst.base(), dst);
+      store_check(masm, dst.base(), dst, tmp1, tmp2);
     } else {
       __ lea(tmp3, dst);
-      store_check(masm, tmp3, dst);
+      store_check(masm, tmp3, dst, tmp1, tmp2);
     }
   }
 }
diff --git a/src/hotspot/cpu/aarch64/gc/shared/cardTableBarrierSetAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/gc/shared/cardTableBarrierSetAssembler_aarch64.hpp
index 07dd8eb5565..e05e9e90e5d 100644
--- a/src/hotspot/cpu/aarch64/gc/shared/cardTableBarrierSetAssembler_aarch64.hpp
+++ b/src/hotspot/cpu/aarch64/gc/shared/cardTableBarrierSetAssembler_aarch64.hpp
@@ -46,7 +46,7 @@ protected:
   virtual void store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
                         Address dst, Register val, Register tmp1, Register tmp2, Register tmp3);
 
-  void store_check(MacroAssembler* masm, Register obj, Address dst);
+  void store_check(MacroAssembler* masm, Register obj, Address dst, Register tmp1, Register tmp2);
 };
 
 #endif // CPU_AARCH64_GC_SHARED_CARDTABLEBARRIERSETASSEMBLER_AARCH64_HPP
diff --git a/src/hotspot/cpu/x86/gc/shared/cardTableBarrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/shared/cardTableBarrierSetAssembler_x86.cpp
index 0ea769dd488..1de147926bb 100644
--- a/src/hotspot/cpu/x86/gc/shared/cardTableBarrierSetAssembler_x86.cpp
+++ b/src/hotspot/cpu/x86/gc/shared/cardTableBarrierSetAssembler_x86.cpp
@@ -138,6 +138,8 @@ void CardTableBarrierSetAssembler::store_check(MacroAssembler* masm, Register ob
   __ shrptr(obj, CardTable::card_shift());
 
   Address card_addr;
+  precond(rscratch != noreg);
+  assert_different_registers(obj, rscratch);
 
   // The calculation for byte_map_base is as follows:
   // byte_map_base = _byte_map - (uintptr_t(low_bound) >> card_shift);
@@ -161,7 +163,7 @@ void CardTableBarrierSetAssembler::store_check(MacroAssembler* masm, Register ob
     // entry and that entry is not properly handled by the relocation code.
     AddressLiteral cardtable((address)byte_map_base, relocInfo::none);
     Address index(noreg, obj, Address::times_1);
-    card_addr = __ as_Address(ArrayAddress(cardtable, index), rscratch1);
+    card_addr = __ as_Address(ArrayAddress(cardtable, index), rscratch);
   }
 
   int dirty = CardTable::dirty_card_val();

From 1688d0f936be0ab15916f339997a8e35d611302b Mon Sep 17 00:00:00 2001
From: Vladimir Kozlov 
Date: Mon, 6 Apr 2026 23:32:33 +0000
Subject: [PATCH 184/359] 8381655: Port JDK-8363978 fix from leyden repo to
 mainline

Reviewed-by: iveresov, iklam
---
 src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp | 5 +++++
 src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp         | 5 +++++
 2 files changed, 10 insertions(+)

diff --git a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp
index e7d8c2d3648..4de6237304d 100644
--- a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp
@@ -42,6 +42,7 @@
 #include "runtime/frame.inline.hpp"
 #include "runtime/sharedRuntime.hpp"
 #include "runtime/stubRoutines.hpp"
+#include "runtime/threadIdentifier.hpp"
 #include "utilities/powerOfTwo.hpp"
 #include "vmreg_aarch64.inline.hpp"
 
@@ -520,6 +521,10 @@ void LIR_Assembler::const2reg(LIR_Opr src, LIR_Opr dest, LIR_PatchCode patch_cod
 #if INCLUDE_CDS
       if (AOTCodeCache::is_on_for_dump()) {
         address b = c->as_pointer();
+        if (b == (address)ThreadIdentifier::unsafe_offset()) {
+          __ lea(dest->as_register_lo(), ExternalAddress(b));
+          break;
+        }
         if (AOTRuntimeConstants::contains(b)) {
           __ load_aotrc_address(dest->as_register_lo(), b);
           break;
diff --git a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp
index 5397a230642..1242078e11d 100644
--- a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp
+++ b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp
@@ -42,6 +42,7 @@
 #include "runtime/safepointMechanism.hpp"
 #include "runtime/sharedRuntime.hpp"
 #include "runtime/stubRoutines.hpp"
+#include "runtime/threadIdentifier.hpp"
 #include "utilities/powerOfTwo.hpp"
 #include "vmreg_x86.inline.hpp"
 
@@ -522,6 +523,10 @@ void LIR_Assembler::const2reg(LIR_Opr src, LIR_Opr dest, LIR_PatchCode patch_cod
 #if INCLUDE_CDS
       if (AOTCodeCache::is_on_for_dump()) {
         address b = c->as_pointer();
+        if (b == (address)ThreadIdentifier::unsafe_offset()) {
+          __ lea(dest->as_register_lo(), ExternalAddress(b));
+          break;
+        }
         if (AOTRuntimeConstants::contains(b)) {
           __ load_aotrc_address(dest->as_register_lo(), b);
           break;

From a90f5a6300b80b5bb0db639337442c6663fae7fa Mon Sep 17 00:00:00 2001
From: Dingli Zhang 
Date: Tue, 7 Apr 2026 01:08:11 +0000
Subject: [PATCH 185/359] 8381611: RISC-V: Factor out function cmpptr from
 MacroAssembler

Reviewed-by: fyang, gcao
---
 src/hotspot/cpu/riscv/macroAssembler_riscv.cpp |  7 -------
 src/hotspot/cpu/riscv/macroAssembler_riscv.hpp |  3 +--
 src/hotspot/cpu/riscv/methodHandles_riscv.cpp  | 11 ++++++++---
 3 files changed, 9 insertions(+), 12 deletions(-)

diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp
index d031161db87..a2b7970f9f6 100644
--- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp
+++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp
@@ -5540,13 +5540,6 @@ void MacroAssembler::decrementw(const Address dst, int32_t value, Register tmp1,
   sw(tmp1, adr);
 }
 
-void MacroAssembler::cmpptr(Register src1, const Address &src2, Label& equal, Register tmp) {
-  assert_different_registers(src1, tmp);
-  assert(src2.getMode() == Address::literal, "must be applied to a literal address");
-  ld(tmp, src2);
-  beq(src1, tmp, equal);
-}
-
 void MacroAssembler::load_method_holder_cld(Register result, Register method) {
   load_method_holder(result, method);
   ld(result, Address(result, InstanceKlass::class_loader_data_offset()));
diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp
index 95821c29eec..a51a6aea468 100644
--- a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp
+++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp
@@ -1353,9 +1353,8 @@ public:
   void decrement(const Address dst, int64_t value = 1, Register tmp1 = t0, Register tmp2 = t1);
   void decrementw(const Address dst, int32_t value = 1, Register tmp1 = t0, Register tmp2 = t1);
 
-  void cmpptr(Register src1, const Address &src2, Label& equal, Register tmp = t0);
-
   void clinit_barrier(Register klass, Register tmp, Label* L_fast_path = nullptr, Label* L_slow_path = nullptr);
+
   void load_method_holder_cld(Register result, Register method);
   void load_method_holder(Register holder, Register method);
 
diff --git a/src/hotspot/cpu/riscv/methodHandles_riscv.cpp b/src/hotspot/cpu/riscv/methodHandles_riscv.cpp
index d770999df96..e80dedf58ed 100644
--- a/src/hotspot/cpu/riscv/methodHandles_riscv.cpp
+++ b/src/hotspot/cpu/riscv/methodHandles_riscv.cpp
@@ -72,17 +72,22 @@ void MethodHandles::verify_klass(MacroAssembler* _masm,
   InstanceKlass** klass_addr = vmClasses::klass_addr_at(klass_id);
   Klass* klass = vmClasses::klass_at(klass_id);
   Register temp1 = t1;
-  Register temp2 = t0; // used by MacroAssembler::cmpptr
+  Register temp2 = t0;
   Label L_ok, L_bad;
   BLOCK_COMMENT("verify_klass {");
   __ verify_oop(obj);
   __ beqz(obj, L_bad);
+
   __ push_reg(RegSet::of(temp1, temp2), sp);
   __ load_klass(temp1, obj, temp2);
-  __ cmpptr(temp1, ExternalAddress((address) klass_addr), L_ok);
+  __ ld(temp2, ExternalAddress((address)klass_addr));
+  __ beq(temp1, temp2, L_ok);
+
   intptr_t super_check_offset = klass->super_check_offset();
   __ ld(temp1, Address(temp1, super_check_offset));
-  __ cmpptr(temp1, ExternalAddress((address) klass_addr), L_ok);
+  __ ld(temp2, ExternalAddress((address)klass_addr));
+  __ beq(temp1, temp2, L_ok);
+
   __ pop_reg(RegSet::of(temp1, temp2), sp);
   __ bind(L_bad);
   __ stop(error_message);

From 132a8d118be66ad5f3d83d098f7df996c27da497 Mon Sep 17 00:00:00 2001
From: Ashay Rane <253344819+raneashay@users.noreply.github.com>
Date: Tue, 7 Apr 2026 05:38:50 +0000
Subject: [PATCH 186/359] 8381451: Prefetch support on Windows/x86 and
 Windows/AArch64

Reviewed-by: dholmes, jwaters
---
 .../prefetch_windows_aarch64.inline.hpp           | 14 ++++++++++++++
 .../windows_x86/prefetch_windows_x86.inline.hpp   | 15 +++++++++++++--
 2 files changed, 27 insertions(+), 2 deletions(-)

diff --git a/src/hotspot/os_cpu/windows_aarch64/prefetch_windows_aarch64.inline.hpp b/src/hotspot/os_cpu/windows_aarch64/prefetch_windows_aarch64.inline.hpp
index a360ee342be..a2c8f0c685c 100644
--- a/src/hotspot/os_cpu/windows_aarch64/prefetch_windows_aarch64.inline.hpp
+++ b/src/hotspot/os_cpu/windows_aarch64/prefetch_windows_aarch64.inline.hpp
@@ -27,10 +27,24 @@
 
 // Included in runtime/prefetch.inline.hpp
 
+#include 
+
+// __prefetch2(addr, prfop) emits a PRFM instruction.
+// The prfop encoding is: 
+//   type:   PLD = 00, PLI = 01, PST = 10
+//   target: L1  = 00, L2  = 01, L3  = 10
+//   policy: KEEP = 0, STRM = 1
+
 inline void Prefetch::read (const void *loc, intx interval) {
+  if (interval >= 0) {
+    __prefetch2((const char*) loc + interval, /* PLD + L1 + KEEP */ 0);
+  }
 }
 
 inline void Prefetch::write(void *loc, intx interval) {
+  if (interval >= 0) {
+    __prefetch2((char*) loc + interval, /* PST + L1 + KEEP */ 16);
+  }
 }
 
 #endif // OS_CPU_WINDOWS_AARCH64_PREFETCH_WINDOWS_AARCH64_INLINE_HPP
diff --git a/src/hotspot/os_cpu/windows_x86/prefetch_windows_x86.inline.hpp b/src/hotspot/os_cpu/windows_x86/prefetch_windows_x86.inline.hpp
index 645fbe99a22..575eabc97dd 100644
--- a/src/hotspot/os_cpu/windows_x86/prefetch_windows_x86.inline.hpp
+++ b/src/hotspot/os_cpu/windows_x86/prefetch_windows_x86.inline.hpp
@@ -27,7 +27,18 @@
 
 // Included in runtime/prefetch.inline.hpp
 
-inline void Prefetch::read (const void *loc, intx interval) {}
-inline void Prefetch::write(void *loc, intx interval) {}
+#include 
+
+inline void Prefetch::read (const void *loc, intx interval) {
+  if (interval >= 0) {
+    _mm_prefetch((const char*) loc + interval, _MM_HINT_T0);
+  }
+}
+
+inline void Prefetch::write(void *loc, intx interval) {
+  if (interval >= 0) {
+    _mm_prefetch((const char*) loc + interval, _MM_HINT_T0);
+  }
+}
 
 #endif // OS_CPU_WINDOWS_X86_PREFETCH_WINDOWS_X86_INLINE_HPP

From 06b797ec6b5e9a7aca3f196fb4b932d662e9a4a8 Mon Sep 17 00:00:00 2001
From: Anton Seoane Ampudia 
Date: Tue, 7 Apr 2026 07:22:22 +0000
Subject: [PATCH 187/359] 8350603: Several more compiler tests ignore vm flags
 and don't have vm.flagless

Reviewed-by: dfenacci, rcastanedalo, syan
---
 test/hotspot/jtreg/compiler/codecache/CheckLargePages.java    | 4 ++--
 test/hotspot/jtreg/compiler/debug/TestGenerateStressSeed.java | 3 ++-
 test/hotspot/jtreg/compiler/debug/TestStressCM.java           | 4 ++--
 test/hotspot/jtreg/compiler/debug/VerifyAdapterSharing.java   | 4 ++--
 .../compiler/jvmci/TestUncaughtErrorInCompileMethod.java      | 3 ++-
 .../loopopts/TestStressLongCountedLoopLimitChecks.java        | 1 +
 .../onSpinWait/TestOnSpinWaitAArch64DefaultFlags.java         | 1 +
 7 files changed, 12 insertions(+), 8 deletions(-)

diff --git a/test/hotspot/jtreg/compiler/codecache/CheckLargePages.java b/test/hotspot/jtreg/compiler/codecache/CheckLargePages.java
index a7935928cab..3b2451cb740 100644
--- a/test/hotspot/jtreg/compiler/codecache/CheckLargePages.java
+++ b/test/hotspot/jtreg/compiler/codecache/CheckLargePages.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved.
  * 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 8304954
  * @summary Code cache reservation should gracefully downgrade to using smaller pages if the code cache size is too small to host the requested page size.
  * @requires os.family == "linux"
- * @requires vm.gc != "Z"
+ * @requires vm.flagless
  * @library /test/lib
  * @build jdk.test.whitebox.WhiteBox
  * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
diff --git a/test/hotspot/jtreg/compiler/debug/TestGenerateStressSeed.java b/test/hotspot/jtreg/compiler/debug/TestGenerateStressSeed.java
index 9542e48e54e..60185fa91ad 100644
--- a/test/hotspot/jtreg/compiler/debug/TestGenerateStressSeed.java
+++ b/test/hotspot/jtreg/compiler/debug/TestGenerateStressSeed.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved.
  * 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.process.ProcessTools;
  * @key stress randomness
  * @bug 8252219 8256535 8325478
  * @requires vm.compiler2.enabled
+ * @requires vm.flagless
  * @summary Tests that using a stress option without -XX:StressSeed=N generates
  *          and logs a random seed.
  * @library /test/lib /
diff --git a/test/hotspot/jtreg/compiler/debug/TestStressCM.java b/test/hotspot/jtreg/compiler/debug/TestStressCM.java
index 0fb624bc16f..a6065fa4d09 100644
--- a/test/hotspot/jtreg/compiler/debug/TestStressCM.java
+++ b/test/hotspot/jtreg/compiler/debug/TestStressCM.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved.
  * 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 @@ public class TestStressCM {
             "-XX:CompileOnly=" + className + "::sum",
             "-XX:+TraceOptoPipelining", "-XX:+" + stressOpt,
             "-XX:StressSeed=" + stressSeed, className, "10"};
-        ProcessBuilder pb  = ProcessTools.createLimitedTestJavaProcessBuilder(procArgs);
+        ProcessBuilder pb  = ProcessTools.createTestJavaProcessBuilder(procArgs);
         OutputAnalyzer out = new OutputAnalyzer(pb.start());
         out.shouldHaveExitValue(0);
         // Extract the trace of our method (the last one after those of all
diff --git a/test/hotspot/jtreg/compiler/debug/VerifyAdapterSharing.java b/test/hotspot/jtreg/compiler/debug/VerifyAdapterSharing.java
index 89da61a5763..1e76887732f 100644
--- a/test/hotspot/jtreg/compiler/debug/VerifyAdapterSharing.java
+++ b/test/hotspot/jtreg/compiler/debug/VerifyAdapterSharing.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2026, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -42,7 +42,7 @@ public class VerifyAdapterSharing {
         ProcessBuilder pb;
         OutputAnalyzer out;
 
-        pb = ProcessTools.createLimitedTestJavaProcessBuilder("-Xcomp", "-XX:+IgnoreUnrecognizedVMOptions",
+        pb = ProcessTools.createTestJavaProcessBuilder("-Xcomp", "-XX:+IgnoreUnrecognizedVMOptions",
                 "-XX:+VerifyAdapterSharing", "-version");
         out = new OutputAnalyzer(pb.start());
         out.shouldHaveExitValue(0);
diff --git a/test/hotspot/jtreg/compiler/jvmci/TestUncaughtErrorInCompileMethod.java b/test/hotspot/jtreg/compiler/jvmci/TestUncaughtErrorInCompileMethod.java
index bfb617a0a3a..1c2d07d3255 100644
--- a/test/hotspot/jtreg/compiler/jvmci/TestUncaughtErrorInCompileMethod.java
+++ b/test/hotspot/jtreg/compiler/jvmci/TestUncaughtErrorInCompileMethod.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved.
  * 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 @@
  *          which is only read in a debug VM.
  * @requires vm.jvmci
  * @requires vm.debug
+ * @requires vm.flagless
  * @library /test/lib /
  * @modules jdk.internal.vm.ci/jdk.vm.ci.hotspot
  *          jdk.internal.vm.ci/jdk.vm.ci.code
diff --git a/test/hotspot/jtreg/compiler/loopopts/TestStressLongCountedLoopLimitChecks.java b/test/hotspot/jtreg/compiler/loopopts/TestStressLongCountedLoopLimitChecks.java
index fd0143acdb6..764acba567f 100644
--- a/test/hotspot/jtreg/compiler/loopopts/TestStressLongCountedLoopLimitChecks.java
+++ b/test/hotspot/jtreg/compiler/loopopts/TestStressLongCountedLoopLimitChecks.java
@@ -37,6 +37,7 @@ import java.util.stream.Stream;
  * @summary test loop limit checks are inserted when stressing int counted loops to long counted loops
  * @library /test/lib
  * @requires vm.debug == true
+ * @requires vm.flagless
  * @run driver compiler.loopopts.TestStressLongCountedLoopLimitChecks
  */
 public class TestStressLongCountedLoopLimitChecks {
diff --git a/test/hotspot/jtreg/compiler/onSpinWait/TestOnSpinWaitAArch64DefaultFlags.java b/test/hotspot/jtreg/compiler/onSpinWait/TestOnSpinWaitAArch64DefaultFlags.java
index f7ed6096080..337012d834f 100644
--- a/test/hotspot/jtreg/compiler/onSpinWait/TestOnSpinWaitAArch64DefaultFlags.java
+++ b/test/hotspot/jtreg/compiler/onSpinWait/TestOnSpinWaitAArch64DefaultFlags.java
@@ -28,6 +28,7 @@
  * @library /test/lib /
  *
  * @requires os.arch=="aarch64"
+ * @requires vm.flagless
  *
  * @build jdk.test.whitebox.WhiteBox
  * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox

From f31421266f1b1e68fe1dfcc9eb1514af845e74ac Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Manuel=20H=C3=A4ssig?= 
Date: Tue, 7 Apr 2026 07:35:50 +0000
Subject: [PATCH 188/359] 8370416: C2: Optimizing away arraycopy leads to wrong
 execution

Co-authored-by: Olivier Mattmann 
Co-authored-by: Roland Westrelin 
Co-authored-by: Emanuel Peter 
Co-authored-by: Tobias Hartmann 
Co-authored-by: Christian Hagedorn 
Co-authored-by: Quan Anh Mai 
Reviewed-by: epeter, qamai
---
 src/hotspot/share/opto/arraycopynode.cpp      |   6 +-
 src/hotspot/share/opto/arraycopynode.hpp      |   5 +-
 src/hotspot/share/opto/callnode.cpp           |   4 +-
 src/hotspot/share/opto/callnode.hpp           |   8 +-
 src/hotspot/share/opto/macro.cpp              | 191 +++--
 src/hotspot/share/opto/macro.hpp              |   4 +-
 ...ayCopyEliminationUncRematerialization.java | 666 ++++++++++++++++++
 7 files changed, 808 insertions(+), 76 deletions(-)
 create mode 100644 test/hotspot/jtreg/compiler/escapeAnalysis/TestArrayCopyEliminationUncRematerialization.java

diff --git a/src/hotspot/share/opto/arraycopynode.cpp b/src/hotspot/share/opto/arraycopynode.cpp
index 82d17440c56..dab0ca98911 100644
--- a/src/hotspot/share/opto/arraycopynode.cpp
+++ b/src/hotspot/share/opto/arraycopynode.cpp
@@ -383,6 +383,10 @@ const TypePtr* ArrayCopyNode::get_address_type(PhaseGVN* phase, const TypePtr* a
   return atp->add_offset(Type::OffsetBot);
 }
 
+const TypePtr* ArrayCopyNode::get_src_adr_type(PhaseGVN* phase) const {
+  return get_address_type(phase, _src_type, in(Src));
+}
+
 void ArrayCopyNode::array_copy_test_overlap(PhaseGVN *phase, bool can_reshape, bool disjoint_bases, int count, Node*& forward_ctl, Node*& backward_ctl) {
   Node* ctl = in(TypeFunc::Control);
   if (!disjoint_bases && count > 1) {
@@ -688,7 +692,7 @@ Node *ArrayCopyNode::Ideal(PhaseGVN *phase, bool can_reshape) {
   return mem;
 }
 
-bool ArrayCopyNode::may_modify(const TypeOopPtr* t_oop, PhaseValues* phase) {
+bool ArrayCopyNode::may_modify(const TypeOopPtr* t_oop, PhaseValues* phase) const {
   Node* dest = in(ArrayCopyNode::Dest);
   if (dest->is_top()) {
     return false;
diff --git a/src/hotspot/share/opto/arraycopynode.hpp b/src/hotspot/share/opto/arraycopynode.hpp
index 83c085fd5db..483a3a86267 100644
--- a/src/hotspot/share/opto/arraycopynode.hpp
+++ b/src/hotspot/share/opto/arraycopynode.hpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -95,6 +95,7 @@ public:
     _arraycopy_type_Type =  TypeFunc::make(domain, range);
   }
 
+  const TypePtr* get_src_adr_type(PhaseGVN* phase) const;
 private:
   ArrayCopyNode(Compile* C, bool alloc_tightly_coupled, bool has_negative_length_guard);
 
@@ -183,7 +184,7 @@ public:
   virtual bool guaranteed_safepoint()  { return false; }
   virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
 
-  virtual bool may_modify(const TypeOopPtr* t_oop, PhaseValues* phase);
+  virtual bool may_modify(const TypeOopPtr* t_oop, PhaseValues* phase) const;
 
   bool is_alloc_tightly_coupled() const { return _alloc_tightly_coupled; }
 
diff --git a/src/hotspot/share/opto/callnode.cpp b/src/hotspot/share/opto/callnode.cpp
index c7c0810ae85..b2b01079379 100644
--- a/src/hotspot/share/opto/callnode.cpp
+++ b/src/hotspot/share/opto/callnode.cpp
@@ -827,7 +827,7 @@ uint CallNode::match_edge(uint idx) const {
 // Determine whether the call could modify the field of the specified
 // instance at the specified offset.
 //
-bool CallNode::may_modify(const TypeOopPtr* t_oop, PhaseValues* phase) {
+bool CallNode::may_modify(const TypeOopPtr* t_oop, PhaseValues* phase) const {
   assert((t_oop != nullptr), "sanity");
   if (is_call_to_arraycopystub() && strcmp(_name, "unsafe_arraycopy") != 0) {
     const TypeTuple* args = _tf->domain();
@@ -2413,7 +2413,7 @@ void AbstractLockNode::log_lock_optimization(Compile *C, const char * tag, Node*
   }
 }
 
-bool CallNode::may_modify_arraycopy_helper(const TypeOopPtr* dest_t, const TypeOopPtr* t_oop, PhaseValues* phase) {
+bool CallNode::may_modify_arraycopy_helper(const TypeOopPtr* dest_t, const TypeOopPtr* t_oop, PhaseValues* phase) const {
   if (dest_t->is_known_instance() && t_oop->is_known_instance()) {
     return dest_t->instance_id() == t_oop->instance_id();
   }
diff --git a/src/hotspot/share/opto/callnode.hpp b/src/hotspot/share/opto/callnode.hpp
index a5131676347..5241ae6cd2b 100644
--- a/src/hotspot/share/opto/callnode.hpp
+++ b/src/hotspot/share/opto/callnode.hpp
@@ -685,7 +685,7 @@ class CallGenerator;
 class CallNode : public SafePointNode {
 
 protected:
-  bool may_modify_arraycopy_helper(const TypeOopPtr* dest_t, const TypeOopPtr* t_oop, PhaseValues* phase);
+  bool may_modify_arraycopy_helper(const TypeOopPtr* dest_t, const TypeOopPtr* t_oop, PhaseValues* phase) const;
 
 public:
   const TypeFunc* _tf;          // Function type
@@ -734,7 +734,7 @@ public:
   virtual bool needs_deep_clone_jvms(Compile* C) { return _generator != nullptr || C->needs_deep_clone_jvms(); }
 
   // Returns true if the call may modify n
-  virtual bool        may_modify(const TypeOopPtr* t_oop, PhaseValues* phase);
+  virtual bool        may_modify(const TypeOopPtr* t_oop, PhaseValues* phase) const;
   // Does this node have a use of n other than in debug information?
   bool                has_non_debug_use(Node* n);
   // Returns the unique CheckCastPP of a call
@@ -1044,7 +1044,7 @@ public:
   virtual bool        guaranteed_safepoint()  { return false; }
 
   // allocations do not modify their arguments
-  virtual bool        may_modify(const TypeOopPtr* t_oop, PhaseValues* phase) { return false;}
+  virtual bool may_modify(const TypeOopPtr* t_oop, PhaseValues* phase) const { return false; }
 
   // Pattern-match a possible usage of AllocateNode.
   // Return null if no allocation is recognized.
@@ -1208,7 +1208,7 @@ public:
   bool is_balanced();
 
   // locking does not modify its arguments
-  virtual bool may_modify(const TypeOopPtr* t_oop, PhaseValues* phase){ return false; }
+  virtual bool may_modify(const TypeOopPtr* t_oop, PhaseValues* phase) const { return false; }
 
 #ifndef PRODUCT
   void create_lock_counter(JVMState* s);
diff --git a/src/hotspot/share/opto/macro.cpp b/src/hotspot/share/opto/macro.cpp
index 1c54a11e2a4..01c67187883 100644
--- a/src/hotspot/share/opto/macro.cpp
+++ b/src/hotspot/share/opto/macro.cpp
@@ -52,6 +52,7 @@
 #include "prims/jvmtiExport.hpp"
 #include "runtime/continuation.hpp"
 #include "runtime/sharedRuntime.hpp"
+#include "utilities/globalDefinitions.hpp"
 #include "utilities/macros.hpp"
 #include "utilities/powerOfTwo.hpp"
 #if INCLUDE_G1GC
@@ -261,74 +262,128 @@ static Node *scan_mem_chain(Node *mem, int alias_idx, int offset, Node *start_me
   }
 }
 
-// Generate loads from source of the arraycopy for fields of
-// destination needed at a deoptimization point
-Node* PhaseMacroExpand::make_arraycopy_load(ArrayCopyNode* ac, intptr_t offset, Node* ctl, Node* mem, BasicType ft, const Type *ftype, AllocateNode *alloc) {
+// Determine if there is an interfering store between a rematerialization load and an arraycopy that is in the process
+// of being elided. Starting from the given rematerialization load this method starts a BFS traversal upwards through
+// the memory graph towards the provided ArrayCopyNode. For every node encountered on the traversal, check that it is
+// independent from the provided rematerialization. Returns false if every node on the traversal is independent and
+// true otherwise.
+bool has_interfering_store(const ArrayCopyNode* ac, LoadNode* load, PhaseGVN* phase) {
+  assert(ac != nullptr && load != nullptr, "sanity");
+  AccessAnalyzer acc(phase, load);
+  ResourceMark rm;
+  Unique_Node_List to_visit;
+  to_visit.push(load->in(MemNode::Memory));
+
+  for (uint worklist_idx = 0; worklist_idx < to_visit.size(); worklist_idx++) {
+    Node* mem = to_visit.at(worklist_idx);
+
+    if (mem->is_Proj() && mem->in(0) == ac) {
+      // Reached the target, so visit what is left on the worklist.
+      continue;
+    }
+
+    if (mem->is_Phi()) {
+      assert(mem->bottom_type() == Type::MEMORY, "do not leave memory graph");
+      // Add all non-control inputs of phis to be visited.
+      for (uint phi_in = 1; phi_in < mem->len(); phi_in++) {
+        Node* input = mem->in(phi_in);
+        if (input != nullptr) {
+          to_visit.push(input);
+        }
+      }
+      continue;
+    }
+
+    AccessAnalyzer::AccessIndependence ind = acc.detect_access_independence(mem);
+    if (ind.independent) {
+      to_visit.push(ind.mem);
+    } else {
+      return true;
+    }
+  }
+  // Did not find modification of source element in memory graph.
+  return false;
+}
+
+// Generate loads from source of the arraycopy for fields of destination needed at a deoptimization point.
+// Returns nullptr if the load cannot be created because the arraycopy is not suitable for elimination
+// (e.g. copy inside the array with non-constant offsets) or the inputs do not match our assumptions (e.g.
+// the arraycopy does not actually write something at the provided offset).
+Node* PhaseMacroExpand::make_arraycopy_load(ArrayCopyNode* ac, intptr_t offset, Node* ctl, Node* mem, BasicType ft, const Type* ftype, AllocateNode* alloc) {
+  assert((ctl == ac->control() && mem == ac->memory()) != (mem != ac->memory() && ctl->is_Proj() && ctl->as_Proj()->is_uncommon_trap_proj()),
+    "Either the control and memory are the same as for the arraycopy or they are pinned in an uncommon trap.");
   BasicType bt = ft;
   const Type *type = ftype;
   if (ft == T_NARROWOOP) {
     bt = T_OBJECT;
     type = ftype->make_oopptr();
   }
-  Node* res = nullptr;
+  Node* base = ac->in(ArrayCopyNode::Src);
+  Node* adr = nullptr;
+  const TypePtr* adr_type = nullptr;
+
   if (ac->is_clonebasic()) {
     assert(ac->in(ArrayCopyNode::Src) != ac->in(ArrayCopyNode::Dest), "clone source equals destination");
-    Node* base = ac->in(ArrayCopyNode::Src);
-    Node* adr = _igvn.transform(AddPNode::make_with_base(base, _igvn.MakeConX(offset)));
-    const TypePtr* adr_type = _igvn.type(base)->is_ptr()->add_offset(offset);
-    MergeMemNode* mergemen = _igvn.transform(MergeMemNode::make(mem))->as_MergeMem();
-    BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2();
-    res = ArrayCopyNode::load(bs, &_igvn, ctl, mergemen, adr, adr_type, type, bt);
+    adr = _igvn.transform(AddPNode::make_with_base(base, _igvn.MakeConX(offset)));
+    adr_type = _igvn.type(base)->is_ptr()->add_offset(offset);
   } else {
-    if (ac->modifies(offset, offset, &_igvn, true)) {
-      assert(ac->in(ArrayCopyNode::Dest) == alloc->result_cast(), "arraycopy destination should be allocation's result");
-      uint shift = exact_log2(type2aelembytes(bt));
-      Node* src_pos = ac->in(ArrayCopyNode::SrcPos);
-      Node* dest_pos = ac->in(ArrayCopyNode::DestPos);
-      const TypeInt* src_pos_t = _igvn.type(src_pos)->is_int();
-      const TypeInt* dest_pos_t = _igvn.type(dest_pos)->is_int();
+    if (!ac->modifies(offset, offset, &_igvn, true)) {
+      // If the arraycopy does not copy to this offset, we cannot generate a rematerialization load for it.
+      return nullptr;
+    }
+    assert(ac->in(ArrayCopyNode::Dest) == alloc->result_cast(), "arraycopy destination should be allocation's result");
+    uint shift = exact_log2(type2aelembytes(bt));
+    Node* src_pos = ac->in(ArrayCopyNode::SrcPos);
+    Node* dest_pos = ac->in(ArrayCopyNode::DestPos);
+    const TypeInt* src_pos_t = _igvn.type(src_pos)->is_int();
+    const TypeInt* dest_pos_t = _igvn.type(dest_pos)->is_int();
 
-      Node* adr = nullptr;
-      const TypePtr* adr_type = nullptr;
-      if (src_pos_t->is_con() && dest_pos_t->is_con()) {
-        intptr_t off = ((src_pos_t->get_con() - dest_pos_t->get_con()) << shift) + offset;
-        Node* base = ac->in(ArrayCopyNode::Src);
-        adr = _igvn.transform(AddPNode::make_with_base(base, _igvn.MakeConX(off)));
-        adr_type = _igvn.type(base)->is_ptr()->add_offset(off);
-        if (ac->in(ArrayCopyNode::Src) == ac->in(ArrayCopyNode::Dest)) {
-          // Don't emit a new load from src if src == dst but try to get the value from memory instead
-          return value_from_mem(ac->in(TypeFunc::Memory), ctl, ft, ftype, adr_type->isa_oopptr(), alloc);
-        }
-      } else {
-        Node* diff = _igvn.transform(new SubINode(ac->in(ArrayCopyNode::SrcPos), ac->in(ArrayCopyNode::DestPos)));
-#ifdef _LP64
-        diff = _igvn.transform(new ConvI2LNode(diff));
-#endif
-        diff = _igvn.transform(new LShiftXNode(diff, _igvn.intcon(shift)));
-
-        Node* off = _igvn.transform(new AddXNode(_igvn.MakeConX(offset), diff));
-        Node* base = ac->in(ArrayCopyNode::Src);
-        adr = _igvn.transform(AddPNode::make_with_base(base, off));
-        adr_type = _igvn.type(base)->is_ptr()->add_offset(Type::OffsetBot);
-        if (ac->in(ArrayCopyNode::Src) == ac->in(ArrayCopyNode::Dest)) {
-          // Non constant offset in the array: we can't statically
-          // determine the value
-          return nullptr;
-        }
+    if (src_pos_t->is_con() && dest_pos_t->is_con()) {
+      intptr_t off = ((src_pos_t->get_con() - dest_pos_t->get_con()) << shift) + offset;
+      adr = _igvn.transform(AddPNode::make_with_base(base, _igvn.MakeConX(off)));
+      adr_type = _igvn.type(base)->is_ptr()->add_offset(off);
+      if (ac->in(ArrayCopyNode::Src) == ac->in(ArrayCopyNode::Dest)) {
+        // Don't emit a new load from src if src == dst but try to get the value from memory instead
+        return value_from_mem(ac, ctl, ft, ftype, adr_type->isa_oopptr(), alloc);
+      }
+    } else {
+      Node* diff = _igvn.transform(new SubINode(ac->in(ArrayCopyNode::SrcPos), ac->in(ArrayCopyNode::DestPos)));
+#ifdef _LP64
+      diff = _igvn.transform(new ConvI2LNode(diff));
+#endif
+      diff = _igvn.transform(new LShiftXNode(diff, _igvn.intcon(shift)));
+
+      Node* off = _igvn.transform(new AddXNode(_igvn.MakeConX(offset), diff));
+      adr = _igvn.transform(AddPNode::make_with_base(base, off));
+      adr_type = _igvn.type(base)->is_ptr()->add_offset(Type::OffsetBot);
+      if (ac->in(ArrayCopyNode::Src) == ac->in(ArrayCopyNode::Dest)) {
+        // Non constant offset in the array: we can't statically
+        // determine the value
+        return nullptr;
       }
-      MergeMemNode* mergemen = _igvn.transform(MergeMemNode::make(mem))->as_MergeMem();
-      BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2();
-      res = ArrayCopyNode::load(bs, &_igvn, ctl, mergemen, adr, adr_type, type, bt);
     }
   }
-  if (res != nullptr) {
-    if (ftype->isa_narrowoop()) {
-      // PhaseMacroExpand::scalar_replacement adds DecodeN nodes
-      res = _igvn.transform(new EncodePNode(res, ftype));
-    }
-    return res;
+  assert(adr != nullptr && adr_type != nullptr, "sanity");
+
+  // Create the rematerialization load ...
+  MergeMemNode* mergemem = _igvn.transform(MergeMemNode::make(mem))->as_MergeMem();
+  BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2();
+  Node* res = ArrayCopyNode::load(bs, &_igvn, ctl, mergemem, adr, adr_type, type, bt);
+  assert(res != nullptr, "load should have been created");
+
+  // ... and ensure that pinning the rematerialization load inside the uncommon path is safe.
+  if (mem != ac->memory() && ctl->is_Proj() && ctl->as_Proj()->is_uncommon_trap_proj() && res->is_Load() &&
+      has_interfering_store(ac, res->as_Load(), &_igvn)) {
+    // Not safe: use control and memory from the arraycopy to ensure correct memory state.
+    _igvn.remove_dead_node(res, PhaseIterGVN::NodeOrigin::Graph); // Clean up the unusable rematerialization load.
+    return make_arraycopy_load(ac, offset, ac->control(), ac->memory(), ft, ftype, alloc);
   }
-  return nullptr;
+
+  if (ftype->isa_narrowoop()) {
+    // PhaseMacroExpand::scalar_replacement adds DecodeN nodes
+    res = _igvn.transform(new EncodePNode(res, ftype));
+  }
+  return res;
 }
 
 //
@@ -441,21 +496,22 @@ Node *PhaseMacroExpand::value_from_mem_phi(Node *mem, BasicType ft, const Type *
 }
 
 // Search the last value stored into the object's field.
-Node *PhaseMacroExpand::value_from_mem(Node *sfpt_mem, Node *sfpt_ctl, BasicType ft, const Type *ftype, const TypeOopPtr *adr_t, AllocateNode *alloc) {
+Node* PhaseMacroExpand::value_from_mem(Node* origin, Node* ctl, BasicType ft, const Type* ftype, const TypeOopPtr* adr_t, AllocateNode* alloc) {
   assert(adr_t->is_known_instance_field(), "instance required");
   int instance_id = adr_t->instance_id();
   assert((uint)instance_id == alloc->_idx, "wrong allocation");
 
   int alias_idx = C->get_alias_index(adr_t);
   int offset = adr_t->offset();
+  Node* orig_mem = origin->in(TypeFunc::Memory);
   Node *start_mem = C->start()->proj_out_or_null(TypeFunc::Memory);
   Node *alloc_ctrl = alloc->in(TypeFunc::Control);
   Node *alloc_mem = alloc->proj_out_or_null(TypeFunc::Memory, /*io_use:*/false);
   assert(alloc_mem != nullptr, "Allocation without a memory projection.");
   VectorSet visited;
 
-  bool done = sfpt_mem == alloc_mem;
-  Node *mem = sfpt_mem;
+  bool done = orig_mem == alloc_mem;
+  Node *mem = orig_mem;
   while (!done) {
     if (visited.test_set(mem->_idx)) {
       return nullptr;  // found a loop, give up
@@ -535,17 +591,22 @@ Node *PhaseMacroExpand::value_from_mem(Node *sfpt_mem, Node *sfpt_ctl, BasicType
         }
       }
     } else if (mem->is_ArrayCopy()) {
-      Node* ctl = mem->in(0);
-      Node* m = mem->in(TypeFunc::Memory);
-      if (sfpt_ctl->is_Proj() && sfpt_ctl->as_Proj()->is_uncommon_trap_proj()) {
+      // Rematerialize the scalar-replaced array. If possible, pin the loads to the uncommon path of the uncommon trap.
+      // Check for each element of the source array, whether it was modified. If not, pin both memory and control to
+      // the uncommon path. Otherwise, use the control and memory state of the arraycopy. Control and memory state must
+      // come from the same source to prevent anti-dependence problems in the backend.
+      ArrayCopyNode* ac = mem->as_ArrayCopy();
+      Node* ac_ctl = ac->control();
+      Node* ac_mem = ac->memory();
+      if (ctl->is_Proj() && ctl->as_Proj()->is_uncommon_trap_proj()) {
         // pin the loads in the uncommon trap path
-        ctl = sfpt_ctl;
-        m = sfpt_mem;
+        ac_ctl = ctl;
+        ac_mem = orig_mem;
       }
-      return make_arraycopy_load(mem->as_ArrayCopy(), offset, ctl, m, ft, ftype, alloc);
+      return make_arraycopy_load(ac, offset, ac_ctl, ac_mem, ft, ftype, alloc);
     }
   }
-  // Something go wrong.
+  // Something went wrong.
   return nullptr;
 }
 
@@ -852,7 +913,7 @@ SafePointScalarObjectNode* PhaseMacroExpand::create_scalarized_object_descriptio
 
     const TypeOopPtr *field_addr_type = res_type->add_offset(offset)->isa_oopptr();
 
-    Node *field_val = value_from_mem(sfpt->memory(), sfpt->control(), basic_elem_type, field_type, field_addr_type, alloc);
+    Node* field_val = value_from_mem(sfpt, sfpt->control(), basic_elem_type, field_type, field_addr_type, alloc);
 
     // We weren't able to find a value for this field,
     // give up on eliminating this allocation.
diff --git a/src/hotspot/share/opto/macro.hpp b/src/hotspot/share/opto/macro.hpp
index 59a455cae6d..e4b20402e63 100644
--- a/src/hotspot/share/opto/macro.hpp
+++ b/src/hotspot/share/opto/macro.hpp
@@ -104,7 +104,7 @@ private:
                               address slow_call_address,
                               Node* valid_length_test);
   void yank_alloc_node(AllocateNode* alloc);
-  Node *value_from_mem(Node *mem, Node *ctl, BasicType ft, const Type *ftype, const TypeOopPtr *adr_t, AllocateNode *alloc);
+  Node* value_from_mem(Node* start, Node* ctl, BasicType ft, const Type* ftype, const TypeOopPtr* adr_t, AllocateNode* alloc);
   Node *value_from_mem_phi(Node *mem, BasicType ft, const Type *ftype, const TypeOopPtr *adr_t, AllocateNode *alloc, Node_Stack *value_phis, int level);
 
   bool eliminate_boxing_node(CallStaticJavaNode *boxing);
@@ -205,7 +205,7 @@ private:
                           Node* klass_node, Node* length,
                           Node* size_in_bytes);
 
-  Node* make_arraycopy_load(ArrayCopyNode* ac, intptr_t offset, Node* ctl, Node* mem, BasicType ft, const Type *ftype, AllocateNode *alloc);
+  Node* make_arraycopy_load(ArrayCopyNode* ac, intptr_t offset, Node* ctl, Node* mem, BasicType ft, const Type* ftype, AllocateNode* alloc);
 
 public:
   PhaseMacroExpand(PhaseIterGVN &igvn) : Phase(Macro_Expand), _igvn(igvn) {
diff --git a/test/hotspot/jtreg/compiler/escapeAnalysis/TestArrayCopyEliminationUncRematerialization.java b/test/hotspot/jtreg/compiler/escapeAnalysis/TestArrayCopyEliminationUncRematerialization.java
new file mode 100644
index 00000000000..a2a0a1a05f6
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/escapeAnalysis/TestArrayCopyEliminationUncRematerialization.java
@@ -0,0 +1,666 @@
+/*
+ * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please 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 8370416
+ * @key randomness
+ * @summary Ensure that rematerialization loads for a scalarized arraycopy destination use the correct control and memory state.
+ * @library /test/lib /
+ * @run driver ${test.main.class}
+ */
+
+package compiler.escapeAnalysis;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.Random;
+import java.util.stream.Collectors;
+
+import jdk.test.lib.Utils;
+import compiler.lib.compile_framework.*;
+import compiler.lib.template_framework.Template;
+import compiler.lib.template_framework.Template.ZeroArgs;
+import compiler.lib.template_framework.TemplateToken;
+import static compiler.lib.template_framework.Template.scope;
+import static compiler.lib.template_framework.Template.let;
+import compiler.lib.template_framework.library.CodeGenerationDataNameType;
+import compiler.lib.template_framework.library.Hooks;
+import compiler.lib.template_framework.library.PrimitiveType;
+import compiler.lib.template_framework.library.TestFrameworkClass;
+
+
+public class TestArrayCopyEliminationUncRematerialization {
+    private static final Random RANDOM = Utils.getRandomInstance();
+    private static final String PACKAGE = "compiler.escapeAnalysis.templated";
+    private static final String CLASS_NAME = "TestArrayCopyEliminationUncRematerializationGenerated";
+
+    // This generates a test containing test methods of the form
+    //  static int testStore(int[] src, boolean flag) {
+    //      int[] dst = new int[COPY_LEN];
+    //      System.arraycopy(src, 0, dst, 0, COPY_LEN);
+    //      src[WRITE_IDX] = WRITE_VAL_I; // Pollute the element in the source array corresponding to the returned element in dst.
+    //      if (flag) { // Compiles to unstable if trap when called exclusively with flag = false.
+    //          dst[0] = (byte) 0x7f;
+    //      }
+    //      return dst[RETURN_IDX]; // Corresponds to src[WRITE_IDX]
+    //  }
+    // for all primitive types except boolean and for different methods of polluting the source
+    // array and producing an unstable if trap.
+    // The templates below generate an IR test that validates that as many rematerialization loads
+    // as possible are placed in the uncommon path and that the returned result is in fact from
+    // the source array.
+    // Between different runs of the test, it will generate different sized arrays and indices
+    // to read from and store to (see TestConfig below). Further, this generates a variant of the
+    // test method, where the offset into src is provided in an argument. C2 cannot put any rematerialization
+    // loads in the uncommon path then, but it is useful for checking the correct result.
+    public static void main(String[] args) {
+        final CompileFramework comp = new CompileFramework();
+
+        comp.addJavaSourceCode(PACKAGE + "." + CLASS_NAME, generate(comp));
+
+        comp.compile();
+
+        // Ensure consistent results for the node counts in the arraycopy subtests.
+        comp.invoke(PACKAGE + "." + CLASS_NAME, "main", new Object[] { new String[] { } });
+    }
+
+    private record TestConfig(int srcSize, int copyLen, int copyIdx, int writeIdx, int returnIdx) {
+        static TestConfig make() {
+            int copyLen = RANDOM.nextInt(10, 64); // 64 is the default value for -XX:EliminateAllocationArraySizeLimit.
+            int srcSize = RANDOM.nextInt(copyLen + 20, 1000);
+            int copyIdx = RANDOM.nextInt(1, srcSize - copyLen); // The index we start arraycopying src from.
+            int returnIdx = RANDOM.nextInt(0, copyLen); // The index where dst returns from. Must correspond to writeIdx in src.
+            int writeIdx = copyIdx + returnIdx; // The index we write to in src.
+
+            return new TestConfig(srcSize, copyLen, copyIdx, writeIdx, returnIdx);
+        }
+
+        public TemplateToken constDefinitions() {
+            return Template.make(() -> scope(
+                Hooks.CLASS_HOOK.insert(scope(
+                    String.format("private static final int SRC_SIZE = %d;\n", srcSize),
+                    String.format("private static final int COPY_LEN = %d;\n", copyLen),
+                    String.format("private static final int COPY_IDX = %d;\n", copyIdx),
+                    String.format("private static final int WRITE_IDX = %d;\n", writeIdx),
+                    String.format("private static final int RETURN_IDX = %d;\n", returnIdx)
+            )))).asToken();
+        }
+
+        public int copyEnd() {
+            return copyIdx + copyLen;
+        }
+    }
+
+    private static String generate(CompileFramework comp) {
+        TestConfig config = TestConfig.make();
+
+        final List tests = new ArrayList<>();
+        tests.add(config.constDefinitions());
+        tests.add(PrimitiveType.generateLibraryRNG());
+
+        // Generate all testcases for all primitive types except boolean.
+        tests.addAll(CodeGenerationDataNameType.INTEGRAL_AND_FLOATING_TYPES
+                         .stream()
+                         .map(pty -> new TestsPerType(pty).generate(config))
+                         .collect(Collectors.toList()));
+
+        final Set imports = Set.of("java.lang.foreign.MemorySegment",
+                                           "java.lang.foreign.ValueLayout",
+                                           "java.lang.invoke.MethodHandles",
+                                           "java.lang.invoke.VarHandle",
+                                           "java.util.Arrays",
+                                           "java.util.Random",
+                                           "jdk.test.lib.Asserts",
+                                           "jdk.test.lib.Utils",
+                                           "compiler.lib.generators.*");
+
+        return TestFrameworkClass.render(PACKAGE, CLASS_NAME, imports, comp.getEscapedClassPathOfCompiledClasses(), tests);
+    }
+
+    record TestsPerType(PrimitiveType pty) {
+        private record TestTemplates(ZeroArgs store, ZeroArgs trap, ZeroArgs prelude) {
+            TestTemplates(ZeroArgs store, ZeroArgs trap) {
+                this(store, trap, Template.make(() -> scope("")));
+            }
+        }
+
+        TemplateToken generate(TestConfig config) {
+            final String srcArray = "src" + pty.abbrev();
+            final String handle = pty.name().toUpperCase() + "_ARR";
+
+            var runTestConst = Template.make("testName", (String testName) -> scope(
+                let("type", pty),
+                let("typeAbbrev", pty.abbrev()),
+                let("srcField", srcArray),
+                """
+                @Run(test = "test#{testName}")
+                static void run#{testName}(RunInfo info) {
+                    Arrays.fill(#{srcField}, SRC_VAL_#{typeAbbrev});
+                    #type res = test#{testName}(#{srcField}, #{srcField}, info.isWarmUp());
+                    Asserts.assertEQ((#type) SRC_VAL_#{typeAbbrev}, res, "Wrong result from " + info.getTest().getName() + " with flag " + info.isWarmUp());
+                }
+                """
+            ));
+
+            var runTestIdx = Template.make("testName", (String testName) -> scope(
+                let("type", pty),
+                let("typeAbbrev", pty.abbrev()),
+                let("srcField", srcArray),
+                """
+                @Run(test = "test#{testName}")
+                static void run#{testName}(RunInfo info) {
+                    Arrays.fill(#{srcField}, SRC_VAL_#{typeAbbrev});
+                    #type res = test#{testName}(#{srcField}, COPY_IDX, info.isWarmUp());
+                    Asserts.assertEQ((#type) SRC_VAL_#{typeAbbrev}, res, "Wrong result from " + info.getTest().getName() + " with flag " + info.isWarmUp());
+                }
+                """
+            ));
+
+            var testMethodConst = Template.make("testName", "tmp", (String TestName, TestTemplates templates) -> scope(
+                let("type", pty),
+                """
+                static #type test#{testName}(#type[] src, #type[] alias, boolean flag) {
+                    """,
+                    templates.prelude.asToken(),
+                    """
+                    #type[] dst = new #type[COPY_LEN];
+                    System.arraycopy(src, COPY_IDX, dst, 0, COPY_LEN);
+                    """,
+                    templates.store.asToken(),
+                    templates.trap.asToken(),
+                    """
+                    return dst[RETURN_IDX];
+                }
+                """
+            ));
+
+            var testMethodIdx = Template.make("testName", "tmp", (String TestName, TestTemplates templates) -> scope(
+                let("type", pty),
+                """
+                static #type test#{testName}(#type[] src, int idx, boolean flag) {
+                    """,
+                    templates.prelude.asToken(),
+                    """
+                    #type[] dst = new #type[COPY_LEN];
+                    System.arraycopy(src, idx, dst, 0, COPY_LEN);
+                    """,
+                    templates.store.asToken(),
+                    templates.trap.asToken(),
+                    """
+                    return dst[RETURN_IDX];
+                }
+                """
+            ));
+
+            var testMethodClone = Template.make("testName", "tmp", (String testName, TestTemplates templates) -> scope(
+                let("type", pty),
+                """
+                static #type test#{testName}(#type[] realSrc, #type[] alias, boolean flag) {
+                    """,
+                    templates.prelude.asToken(),
+                    """
+                    // Set up a src array with statically known length, so scalar replacement works.
+                    #type[] src = new #type[COPY_LEN];
+                    System.arraycopy(realSrc, COPY_IDX, src, 0, COPY_LEN);
+
+                    // Clone the src array into a dst array to get the clonebasic variant of the ArraycopyNode.
+                    #type[] dst = src.clone();
+                    """,
+                    templates.store.asToken(),
+                    templates.trap.asToken(),
+                    """
+                    return dst[RETURN_IDX];
+                }
+                """
+            ));
+
+            // For methods with a constant offset into src, validate that only the necessary rematerialization nodes are
+            // in the common path.
+            var testCaseConst = Template.make("testName", "loadCount", "tmp", (String testName, Integer loadCount, TestTemplates templates) -> scope(
+                let("typeAbbrev", pty.abbrev().equals("C") ? "US" : pty.abbrev()),
+                runTestConst.asToken(testName),
+                """
+                @Test
+                @IR(counts = { IRNode.LOAD_#{typeAbbrev}, "=#{loadCount}" },
+                    applyIf = { "TieredCompilation", "true"})
+                """,
+                testMethodConst.asToken(testName, templates)
+            ));
+
+            var testCaseConstPlusOne = Template.make("testName", "loadCount", "tmp", (String testName, Integer loadCount, TestTemplates templates) -> scope(
+                let("typeAbbrev", pty.abbrev().equals("C") ? "US" : pty.abbrev()),
+                runTestConst.asToken(testName),
+                let("countPlusOne", loadCount + 1),
+                """
+                @Test
+                @IR(counts = { IRNode.LOAD_#{typeAbbrev}, ">=#{loadCount}",
+                               IRNode.LOAD_#{typeAbbrev}, "<=#{countPlusOne}" },
+                    applyIf = { "TieredCompilation", "true"})
+                """,
+                testMethodConst.asToken(testName, templates)
+            ));
+
+            // Some test cases can not be reliably verified due to varying numbers of loads generated from run to run.
+            var testCaseConstNoVerify = Template.make("testName", "tmp", (String testName, TestTemplates templates) -> scope(
+                runTestConst.asToken(testName),
+                """
+                @Test
+                """,
+                testMethodConst.asToken(testName, templates)
+            ));
+
+            // For methods with a parametrized offset into src, only validate the correctness of the return value.
+            var testCaseIdx = Template.make("testName", "tmp", (String testName, TestTemplates templates) -> scope(
+                runTestIdx.asToken(testName),
+                """
+                @Test
+                """,
+                testMethodIdx.asToken(testName, templates)
+            ));
+
+            // Generates tests with the clonebasic variant of the ArraycopyNode.
+            var testCaseClone = Template.make("testName", "loadCount", "tmp", (String testName, Integer loadCount, TestTemplates templates) -> scope(
+                let("typeAbbrev", pty.abbrev().equals("C") ? "US" : pty.abbrev()),
+                runTestConst.asToken(testName),
+                """
+                @Test
+                @IR(counts = { IRNode.LOAD_#{typeAbbrev}, "=#{loadCount}" },
+                    applyIf = { "TieredCompilation", "true"})
+                """,
+                testMethodClone.asToken(testName, templates)
+            ));
+
+            var storeConst = Template.make(() -> scope(
+                let("typeAbbrev", pty.abbrev()),
+                """
+                    src[WRITE_IDX] = WRITE_VAL_#{typeAbbrev};
+                """
+            ));
+
+            var storeIdx = Template.make(() -> scope(
+                let("typeAbbrev", pty.abbrev()),
+                """
+                    src[idx + RETURN_IDX] = WRITE_VAL_#{typeAbbrev};
+                """
+            ));
+
+            var storeClone = Template.make(() -> scope(
+                let("typeAbbrev", pty.abbrev()),
+                """
+                    src[RETURN_IDX] = WRITE_VAL_#{typeAbbrev};
+                """
+            ));
+
+            var storeAlias = Template.make(() -> scope(
+                let("typeAbbrev", pty.abbrev()),
+                """
+                    alias[WRITE_IDX] = WRITE_VAL_#{typeAbbrev};
+                """
+            ));
+
+            var unstableTrap = Template.make(() -> scope(
+                let("typeAbbrev", pty.abbrev()),
+                """
+                if (flag) {
+                    src[0] = WRITE_VAL_#{typeAbbrev};
+                }
+                """
+            ));
+
+            // This generates test with a store to the returned src element and a simple unstable if trap.
+            // Only one rematerialization load is in the common path.
+            var testStore = Template.make(() -> {
+                final String testName = "Store" + pty.abbrev();
+                return scope(
+                    testCaseConst.asToken("Const" + testName, 2 * config.copyLen - 1, new TestTemplates(storeConst, unstableTrap)),
+                    testCaseIdx.asToken("Idx" + testName, new TestTemplates(storeIdx, unstableTrap)),
+                    testCaseClone.asToken("Clone" + testName, config.copyLen, new TestTemplates(storeClone, unstableTrap)),
+                    testCaseConst.asToken("Alias" + testName, 3 * config.copyLen - 2, new TestTemplates(storeAlias, unstableTrap))
+                );
+            });
+
+            // This generates tests with multiple interfering stores forcing elements to be put into the common path.
+            var testMultiStore = Template.make(() -> {
+                final String testName = "MultiStore" + pty.abbrev();
+                final int numStores = RANDOM.nextInt(1, config.copyLen - 1);
+                // Get numStores different store locations.
+                final Set storeIdxs = new HashSet<>();
+                storeIdxs.add(config.returnIdx); // Always store at the WRITE_IDX to potentially trigger the bug.
+                while (storeIdxs.size() < numStores) {
+                    storeIdxs.add(RANDOM.nextInt(0, config.copyLen));
+                }
+                var multiStoresConst = Template.make(() -> scope(
+                    let("typeAbbrev", pty.abbrev()),
+                    storeIdxs.stream()
+                             .map(idx -> scope(let("idx", idx), "src[COPY_IDX + #idx] = WRITE_VAL_#{typeAbbrev};\n"))
+                             .toList()
+                ));
+                var multiStoresIdx = Template.make(() -> scope(
+                    let("typeAbbrev", pty.abbrev()),
+                    storeIdxs.stream()
+                             .map(idx -> scope(let("idx", idx), "src[idx + #idx] = WRITE_VAL_#{typeAbbrev};\n"))
+                             .toList()
+                ));
+                var multiStoresClone = Template.make(() -> scope(
+                    let("typeAbbrev", pty.abbrev()),
+                    storeIdxs.stream()
+                             .map(idx -> scope(let("idx",  idx), "src[#idx] = WRITE_VAL_#{typeAbbrev};\n"))
+                             .toList()
+                ));
+                var multiStoresAlias = Template.make(() -> scope(
+                    let("typeAbbrev", pty.abbrev()),
+                    storeIdxs.stream()
+                             .map(idx -> scope(let("idx", idx), "alias[COPY_IDX + #idx] = WRITE_VAL_#{typeAbbrev};\n"))
+                             .toList()
+                ));
+                return scope(
+                    // Sometimes we get one more load depending on the position of the range checks of the different stores.
+                    testCaseConstPlusOne.asToken("Const" + testName, 2 * config.copyLen - numStores, new TestTemplates(multiStoresConst, unstableTrap)),
+                    testCaseIdx.asToken("Idx" + testName, new TestTemplates(multiStoresIdx, unstableTrap)),
+                    testCaseClone.asToken("Clone" + testName, config.copyLen, new TestTemplates(multiStoresClone, unstableTrap)),
+                    testCaseConstPlusOne.asToken("Alias" + testName, 3 * config.copyLen - 2 * numStores, new TestTemplates(multiStoresAlias, unstableTrap))
+                );
+            });
+
+            // This generates test with a store to the returned src element and the unstable if trap inside a loop.
+            // Only one rematerialization load is in the common path.
+            var testStoreTrapLoop = Template.make(() -> {
+                final String testName = "StoreTrapLoop" + pty.abbrev();
+                var trapTemplate = Template.make(() -> scope(
+                    """
+                    for (int i = 0; i < 1234; i++) {
+                    """,
+                        unstableTrap.asToken(),
+                    """
+                    }
+                    """
+                ));
+                return scope(
+                    testCaseConst.asToken("Const" + testName, 2 * config.copyLen - 1, new TestTemplates(storeConst, trapTemplate)),
+                    testCaseIdx.asToken("Idx" + testName, new TestTemplates(storeIdx, trapTemplate)),
+                    testCaseConst.asToken("Alias" + testName, 2 * config.copyLen - 1, new TestTemplates(storeAlias, trapTemplate))
+                );
+            });
+
+            // This generates tests with atomic operations (LoadStores) as polluting store.
+            // Only one rematerialization load is in the common path.
+            var testAtomics = Template.make(() -> {
+                var getAndSetStoreConst = Template.make(() -> scope(
+                    let("type", pty),
+                    let("typeAbbrev", pty.abbrev()),
+                    let("handle", handle),
+                    """
+                    #{handle}.getAndSet(src, WRITE_IDX, (#type) WRITE_VAL_#{typeAbbrev});
+                    """
+                ));
+                var getAndSetStoreIdx = Template.make(() -> scope(
+                    let("type", pty),
+                    let("typeAbbrev", pty.abbrev()),
+                    let("handle", handle),
+                    """
+                    #{handle}.getAndSet(src, idx + RETURN_IDX, (#type) WRITE_VAL_#{typeAbbrev});
+                    """
+                ));
+                var casStoreConst = Template.make(() -> scope(
+                    let("type", pty),
+                    let("typeAbbrev", pty.abbrev()),
+                    let("handle", handle),
+                    """
+                    #{handle}.compareAndSet(src, WRITE_IDX, (#type) SRC_VAL_#{typeAbbrev}, (#type) WRITE_VAL_#{typeAbbrev});
+                    """
+                ));
+                var casStoreIdx = Template.make(() -> scope(
+                    let("type", pty),
+                    let("typeAbbrev", pty.abbrev()),
+                    let("handle", handle),
+                    """
+                    #{handle}.compareAndSet(src, idx + RETURN_IDX, (#type) SRC_VAL_#{typeAbbrev}, (#type) WRITE_VAL_#{typeAbbrev});
+                    """
+                ));
+                return scope(let("type", pty),
+                    let("handle", handle),
+                    Hooks.CLASS_HOOK.insert(scope(
+                        """
+                        private static final VarHandle #handle = MethodHandles.arrayElementVarHandle(#type[].class);
+                        """
+                    )),
+                    // We cannot look through MemBars emitted by the atomic operations, so all rematerialization loads are
+                    // commoned up in the common path.
+                    pty.abbrev().equals("S") || pty.abbrev().equals("B") || pty.abbrev().equals("C") ?
+                        testCaseConstNoVerify.asToken("ConstGetAndSet" + pty.abbrev(), new TestTemplates(getAndSetStoreConst, unstableTrap)) :
+                        testCaseConst.asToken("ConstGetAndSet" + pty.abbrev(), config.copyLen, new TestTemplates(getAndSetStoreConst, unstableTrap)),
+                    testCaseIdx.asToken("IdxGetAndSet" + pty.abbrev(), new TestTemplates(getAndSetStoreIdx, unstableTrap)),
+                    testCaseConst.asToken("ConstCompareAndSet" + pty.abbrev(), config.copyLen, new TestTemplates(casStoreConst, unstableTrap)),
+                    testCaseIdx.asToken("IdxCompareAndSet" + pty.abbrev(), new TestTemplates(casStoreIdx, unstableTrap))
+                );
+            });
+
+            var testMemorySegments = Template.make(() -> {
+                final String layout = String.format("JAVA_%s", pty.toString().toUpperCase());
+                var memorySegmentCreation = Template.make(() -> scope(
+                    """
+                    MemorySegment srcMS = MemorySegment.ofArray(src);
+                    """
+                ));
+                var memorySegmentCreationAlias = Template.make(() -> scope(
+                    """
+                    MemorySegment srcMS = MemorySegment.ofArray(alias);
+                    """
+                ));
+                // Just write using a memory segment
+                var memorySegmentStoreConst = Template.make(() -> scope(
+                    let("typeAbbrev", pty.abbrev()),
+                    let("layout", layout),
+                    """
+                    srcMS.setAtIndex(ValueLayout.#{layout}, WRITE_IDX, WRITE_VAL_#{typeAbbrev});
+                    """
+                ));
+                var memorySegmentStoreIdx = Template.make(() -> scope(
+                    let("typeAbbrev", pty.abbrev()),
+                    let("layout", layout),
+                    """
+                    srcMS.setAtIndex(ValueLayout.#{layout}, RETURN_IDX + idx, WRITE_VAL_#{typeAbbrev});
+                    """
+                ));
+                // Write a single byte somewhere within the returned value.
+                var memorySegmentStoreSmallConst = Template.make(() -> scope(
+                    let("offset", RANDOM.nextInt(pty.byteSize())),
+                    let("byteSize", pty.byteSize()),
+                    """
+                    srcMS.set(ValueLayout.JAVA_BYTE, WRITE_IDX * #byteSize - #offset, (byte)-1);
+                    """
+                ));
+                var memorySegmentStoreSmallIdx = Template.make(() -> scope(
+                    let("offset", RANDOM.nextInt(pty.byteSize())),
+                    let("byteSize", pty.byteSize()),
+                    """
+                    srcMS.set(ValueLayout.JAVA_BYTE, (RETURN_IDX + idx) * #byteSize - #offset, (byte)-1);
+                    """
+                ));
+                // Write 8 bytes overlapping multiple array elements.
+                int offsetMut = RANDOM.nextInt(pty.byteSize());
+                if (config.writeIdx * pty.byteSize() - offsetMut + 8 >= config.srcSize * pty.byteSize()) {
+                    // This will not fit. Adjust offset.
+                    offsetMut = (config.writeIdx * pty.byteSize() + 8) - (config.srcSize * pty.byteSize());
+                }
+                final int offset = offsetMut;
+                var memorySegmentStoreOverlappingConst = Template.make(() -> scope(
+                    let("offset", offset),
+                    let("byteSize", pty.byteSize()),
+                    """
+                    srcMS.set(ValueLayout.JAVA_LONG_UNALIGNED, WRITE_IDX * #byteSize - #offset, -1);
+                    """
+                ));
+                var memorySegmentStoreOverlappingIdx = Template.make(() -> scope(
+                    let("offset", offset),
+                    let("byteSize", pty.byteSize()),
+                    """
+                    srcMS.set(ValueLayout.JAVA_LONG_UNALIGNED, (RETURN_IDX + idx) * #byteSize - #offset, -1);
+                    """
+                ));
+                return scope(
+                    let("type", pty),
+                    // The number of loads differs run to run (probably due to the amount of inlining going on), so
+                    // we do not verify the number of loads in the uncommon path, even though only the polluted loads
+                    // end up in the common path for all const cases.
+                    testCaseConstNoVerify.asToken("MemorySegmentStoreConst" + pty.abbrev(), new TestTemplates(memorySegmentStoreConst, unstableTrap, memorySegmentCreation)),
+                    testCaseIdx.asToken("MemorySegmentStoreIdx" + pty.abbrev(), new TestTemplates(memorySegmentStoreIdx, unstableTrap, memorySegmentCreation)),
+                    testCaseConstNoVerify.asToken("MemorySegmentStoreAlias" + pty.abbrev(), new TestTemplates(memorySegmentStoreConst, unstableTrap, memorySegmentCreationAlias)),
+                    testCaseConstNoVerify.asToken("MemorySegmentStoreSmallConst" + pty.abbrev(), new TestTemplates(memorySegmentStoreSmallConst, unstableTrap, memorySegmentCreation)),
+                    testCaseIdx.asToken("MemorySegmentStoreSmallIdx" + pty.abbrev(), new TestTemplates(memorySegmentStoreSmallIdx, unstableTrap, memorySegmentCreation)),
+                    testCaseConstNoVerify.asToken("MemorySegmentStoreSmallAlias" + pty.abbrev(), new TestTemplates(memorySegmentStoreSmallConst, unstableTrap, memorySegmentCreationAlias)),
+                    testCaseConstNoVerify.asToken("MemorySegmentStoreOverlappingConst" + pty.abbrev(), new TestTemplates(memorySegmentStoreOverlappingConst, unstableTrap, memorySegmentCreation)),
+                    testCaseIdx.asToken("MemorySegmentStoreOverlappingIdx" + pty.abbrev(), new TestTemplates(memorySegmentStoreOverlappingIdx, unstableTrap, memorySegmentCreation)),
+                    testCaseConstNoVerify.asToken("MemorySegmentStoreOverlappingAlias" + pty.abbrev(), new TestTemplates(memorySegmentStoreOverlappingConst, unstableTrap, memorySegmentCreationAlias))
+                );
+            });
+
+            // C2 is not able to put any rematerialization load in the uncommon path for this test.
+            // Thus, we do not check the number of loads.
+            var testSwitch = Template.make(() -> {
+                final String testName = "Switch" + pty.abbrev();
+                return scope(
+                    let("type", pty),
+                    let("typeAbbrev", pty.abbrev()),
+                    let("testName", testName),
+                    let("src", srcArray),
+                    """
+                    @Run(test = "test#testName")
+                    @Warmup(10000)
+                    static void run#testName(RunInfo info) {
+                        Arrays.fill(#src, SRC_VAL_#{typeAbbrev});
+                        #type res = test#testName(#src);
+                        Asserts.assertEQ((#type) SRC_VAL_#{typeAbbrev}, res, "Wrong Result from " + info.getTest().getName());
+                    }
+
+                    @Test
+                    static #type test#testName(#type[] src) {
+                        #type[] dst = new #type[COPY_LEN];
+                        System.arraycopy(src, COPY_IDX, dst, 0, COPY_LEN);
+
+                        for (int i = 0; i < 4; i++) {
+                            for (int j = 0; j < 8; j++) {
+                                switch (i) {
+                                    case -1 -> { /*nop*/ }
+                                    case 0 -> src[WRITE_IDX] = WRITE_VAL_#{typeAbbrev};
+                                }
+                            }
+                        }
+
+                        return dst[1];
+                    }
+                    """
+                );
+            });
+
+            // This generates tests where the polluting store to src is an arraycopy.
+            // In this case, the rematerialization loads for all elements that are written to
+            // have to be in the common path.
+            var testArraycopy = Template.make(() -> {
+                final String testName = "Arraycopy" + pty.abbrev();
+                final int arraycopyLen = RANDOM.nextInt(1, Math.min(config.copyLen, config.srcSize - config.writeIdx));
+                final int otherLen = RANDOM.nextInt(arraycopyLen + 1, arraycopyLen + 10);
+                final int copyOtherIdx = RANDOM.nextInt(0, otherLen - arraycopyLen);
+                var arraycopyStoreConst = Template.make(() -> scope(
+                    let("type", pty),
+                    let("typeAbbrev", pty.abbrev()),
+                    let("arraycopyLen", arraycopyLen),
+                    let("other", "other" + pty.abbrev()),
+                    let("otherLen", otherLen),
+                    let("copyOtherIdx", copyOtherIdx),
+                    Hooks.CLASS_HOOK.insert(scope(
+                        """
+                        private static final #type[] #other = new #type[#otherLen];
+                        static { Arrays.fill(#other, WRITE_VAL_#{typeAbbrev}); }
+                        """
+                    )),
+                    """
+                        System.arraycopy(#other, #copyOtherIdx, src, WRITE_IDX, #arraycopyLen);
+                    """
+                ));
+                var arraycopyStoreIdx = Template.make(() -> scope(
+                    let("type", pty),
+                    let("arraycopyLen", arraycopyLen),
+                    let("other", "other" + pty.abbrev()),
+                    let("copyOtherIdx", copyOtherIdx),
+                    """
+                        System.arraycopy(#other, #copyOtherIdx, src, idx + RETURN_IDX, #arraycopyLen);
+                    """
+                ));
+                var arraycopyStoreAlias = Template.make(() -> scope(
+                    let("type", pty),
+                    let("arraycopyLen", arraycopyLen),
+                    let("other", "other" + pty.abbrev()),
+                    let("copyOtherIdx", copyOtherIdx),
+                    """
+                        System.arraycopy(#other, #copyOtherIdx, alias, WRITE_IDX, #arraycopyLen);
+                    """
+                ));
+                // Unfortunately, it is not possible to validate the placement of rematerialization nodes because
+                // the number of uncomon traps is sensitive to changes in the profile, which leads to a bimodal count
+                // of load nodes.
+                return scope(
+                    testCaseConstNoVerify.asToken("Const" + testName, new TestTemplates(arraycopyStoreConst, unstableTrap)),
+                    testCaseIdx.asToken("Idx" + testName, new TestTemplates(arraycopyStoreIdx, unstableTrap)),
+                    testCaseConstNoVerify.asToken("Alias" + testName, new TestTemplates(arraycopyStoreAlias, unstableTrap))
+                );
+            });
+
+            return Template.make(() -> scope(
+                let("type", pty),
+                let("typeAbbrev", pty.abbrev()),
+                let("writeVal", pty.con()),
+                let("rng", pty.callLibraryRNG()),
+                let("src", srcArray),
+                Hooks.CLASS_HOOK.insert(scope(
+                    """
+                    private static final #type SRC_VAL_#{typeAbbrev};
+                    private static final #type WRITE_VAL_#{typeAbbrev} = #writeVal;
+                    private static final #type[] #src = new #type[SRC_SIZE];
+
+                    static {
+                        #type srcVal;
+                        do {
+                            srcVal = #rng;
+                        } while (srcVal == WRITE_VAL_#{typeAbbrev});
+                        SRC_VAL_#{typeAbbrev} = srcVal;
+                    }
+                    """
+                )),
+                List.of(testStore,
+                        testMultiStore,
+                        testStoreTrapLoop,
+                        testAtomics,
+                        testMemorySegments,
+                        testSwitch,
+                        testArraycopy)
+                    .stream()
+                    .map(t -> t.asToken())
+                    .collect(Collectors.toList())
+            )).asToken();
+        }
+    }
+}

From 0b803bd34e7c6da9e5fcf2d544312d0412838820 Mon Sep 17 00:00:00 2001
From: Casper Norrbin 
Date: Tue, 7 Apr 2026 08:09:00 +0000
Subject: [PATCH 189/359] 8380103: Perfdata shared memory file flock failures

Reviewed-by: dholmes, aartemov
---
 src/hotspot/os/posix/perfMemory_posix.cpp     | 110 +++++++++++++-----
 .../jtreg/containers/docker/ShareTmpDir.java  |  10 +-
 2 files changed, 91 insertions(+), 29 deletions(-)

diff --git a/src/hotspot/os/posix/perfMemory_posix.cpp b/src/hotspot/os/posix/perfMemory_posix.cpp
index b8be77c5e05..c5046797e02 100644
--- a/src/hotspot/os/posix/perfMemory_posix.cpp
+++ b/src/hotspot/os/posix/perfMemory_posix.cpp
@@ -701,6 +701,39 @@ static void remove_file(const char* path) {
   }
 }
 
+// Files newer than this threshold are considered to belong to a JVM that may
+// still be starting up and are therefore not candidates for stale-file
+// cleanup. This avoids racing a concurrent JVM startup while scanning the
+// hsperfdata directory.
+static const time_t cleanup_grace_period_seconds = 5;
+
+static bool is_cleanup_candidate(const char* filename, const char* dirname) {
+  struct stat statbuf;
+  int result;
+
+  RESTARTABLE(::lstat(filename, &statbuf), result);
+  if (result == OS_ERR) {
+    log_debug(perf, memops)("lstat failed for %s/%s: %s", dirname, filename, os::strerror(errno));
+    return false;
+  }
+
+  if (!S_ISREG(statbuf.st_mode)) {
+    return false;
+  }
+
+  const time_t now = time(nullptr);
+  if (now == (time_t)-1) {
+    return false;
+  }
+
+  if (statbuf.st_mtime >= now - cleanup_grace_period_seconds) {
+    log_debug(perf, memops)("Skip cleanup of fresh file %s/%s", dirname, filename);
+    return false;
+  }
+
+  return true;
+}
+
 // cleanup stale shared memory files
 //
 // This method attempts to remove all stale shared memory files in
@@ -744,6 +777,11 @@ static void cleanup_sharedmem_files(const char* dirname) {
       continue;
     }
 
+    if (!is_cleanup_candidate(filename, dirname)) {
+      errno = 0;
+      continue;
+    }
+
 #if defined(LINUX)
     // Special case on Linux, if multiple containers share the
     // same /tmp directory:
@@ -872,16 +910,56 @@ static int create_sharedmem_file(const char* dirname, const char* filename, size
     return -1;
   }
 
-  // Open the filename in the current directory.
-  // Cannot use O_TRUNC here; truncation of an existing file has to happen
-  // after the is_file_secure() check below.
-  int fd;
-  RESTARTABLE(os::open(filename, O_RDWR|O_CREAT|O_NOFOLLOW, S_IRUSR|S_IWUSR), fd);
+  int fd = OS_ERR;
+  static const int create_sharedmem_file_retry_count = LINUX_ONLY(3) NOT_LINUX(1);
+  for (int attempt = 0; attempt < create_sharedmem_file_retry_count; attempt++) {
+    // Open the filename in the current directory.
+    // Use O_EXCL so that startup never reuses an existing pid file unless it
+    // has first been proven stale and removed in `cleanup_sharedmem_files`.
+    RESTARTABLE(os::open(filename, O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW, S_IRUSR|S_IWUSR), fd);
+    if (fd == OS_ERR) {
+      break;
+    }
+
+#if defined(LINUX)
+    // On Linux, different containerized processes that share the same /tmp
+    // directory (e.g., with "docker --volume ...") may have the same pid and
+    // try to use the same file. To avoid conflicts among such processes, we
+    // allow only one of them (the winner of the flock() call) to write to the
+    // file. If we lose the race, assume we may have collided with a concurrent
+    // scavenger briefly holding the lock on a fresh file and retry a few times
+    // before giving up.
+    int n;
+    RESTARTABLE(::flock(fd, LOCK_EX|LOCK_NB), n);
+    if (n == 0) {
+      break;
+    }
+
+    const int flock_errno = errno;
+    ::close(fd);
+    fd = OS_ERR;
+
+    if (attempt + 1 == create_sharedmem_file_retry_count || flock_errno != EWOULDBLOCK) {
+      log_warning(perf, memops)("Cannot use file %s/%s because %s (errno = %d)", dirname, filename,
+                                (flock_errno == EWOULDBLOCK) ?
+                                "it is locked by another process" :
+                                "flock() failed", flock_errno);
+      errno = flock_errno;
+      break;
+    }
+
+    // Short sleep to allow the lock to free up.
+    os::naked_short_sleep(1);
+#endif
+  }
+
   if (fd == OS_ERR) {
     if (log_is_enabled(Debug, perf)) {
       LogStreamHandle(Debug, perf) log;
       if (errno == ELOOP) {
         log.print_cr("file %s is a symlink and is not secure", filename);
+      } else if (errno == EEXIST) {
+        log.print_cr("could not create file %s: existing file is not provably stale", filename);
       } else {
         log.print_cr("could not create file %s: %s", filename, os::strerror(errno));
       }
@@ -901,27 +979,7 @@ static int create_sharedmem_file(const char* dirname, const char* filename, size
   }
 
 #if defined(LINUX)
-  // On Linux, different containerized processes that share the same /tmp
-  // directory (e.g., with "docker --volume ...") may have the same pid and
-  // try to use the same file. To avoid conflicts among such
-  // processes, we allow only one of them (the winner of the flock() call)
-  // to write to the file. All the other processes will give up and will
-  // have perfdata disabled.
-  //
-  // Note that the flock will be automatically given up when the winner
-  // process exits.
-  //
-  // The locking protocol works only with other JVMs that have the JDK-8286030
-  // fix. If you are sharing the /tmp difrectory among different containers,
-  // do not use older JVMs that don't have this fix, or the behavior is undefined.
-  int n;
-  RESTARTABLE(::flock(fd, LOCK_EX|LOCK_NB), n);
-  if (n != 0) {
-    log_warning(perf, memops)("Cannot use file %s/%s because %s (errno = %d)", dirname, filename,
-                              (errno == EWOULDBLOCK) ?
-                              "it is locked by another process" :
-                              "flock() failed", errno);
-    ::close(fd);
+  if (fd == OS_ERR) {
     return -1;
   }
 #endif
diff --git a/test/hotspot/jtreg/containers/docker/ShareTmpDir.java b/test/hotspot/jtreg/containers/docker/ShareTmpDir.java
index 986cd044737..4240ba408b7 100644
--- a/test/hotspot/jtreg/containers/docker/ShareTmpDir.java
+++ b/test/hotspot/jtreg/containers/docker/ShareTmpDir.java
@@ -76,7 +76,7 @@ public class ShareTmpDir {
         Object lock = new Object();
         opts.addDockerOpts("--volume", Utils.TEST_CLASSES + ":/test-classes/");
         opts.addDockerOpts("--volume", sharedtmpdir.getAbsolutePath() + ":/tmp/");
-        opts.addJavaOpts("-Xlog:os+container=trace", "-Xlog:perf+memops=debug", "-cp", "/test-classes/");
+        opts.addJavaOpts("-Xlog:os+container=trace", "-Xlog:perf*=debug", "-cp", "/test-classes/");
 
         Thread t1 = new Thread() {
                 public void run() {
@@ -115,12 +115,13 @@ public class ShareTmpDir {
         t1.join();
         t2.join();
 
-        Pattern pattern = Pattern.compile("perf,memops.*Trying to open (/tmp/hsperfdata_[a-z0-9]*/[0-9]*)");
+        Pattern pattern = Pattern.compile("perf,memops.*Trying to open (/tmp/hsperfdata_[a-z0-9]*/(\\d+))");
         Matcher matcher;
 
         matcher = pattern.matcher(out1.getStdout());
         Asserts.assertTrue(matcher.find());
         String file1 =  matcher.group(1);
+        String pid1  = matcher.group(2);
 
         matcher = pattern.matcher(out2.getStdout());
         Asserts.assertTrue(matcher.find());
@@ -134,8 +135,11 @@ public class ShareTmpDir {
             // have pid==1.
             // One of the two containers must fail to create the hsperf file.
             String s = "Cannot use file " + file1 + " because it is locked by another process";
+            String s2 = "could not create file " + pid1 + ": existing file is not provably stale";
             Asserts.assertTrue(out1.getStdout().contains(s) ||
-                               out2.getStdout().contains(s));
+                               out2.getStdout().contains(s) ||
+                               out1.getStdout().contains(s2) ||
+                               out2.getStdout().contains(s2));
         } else {
             throw new SkippedException("Java in the two containers don't have the same pid: " + file1 + " vs " + file2);
         }

From 9cf2b686bd42f0e185a59b0cf89ceb5717cdc910 Mon Sep 17 00:00:00 2001
From: Evgeny Astigeevich 
Date: Tue, 7 Apr 2026 10:35:31 +0000
Subject: [PATCH 190/359] 8381003: [REDO] Mitigate Neoverse-N1 erratum 1542419
 negative impact on GCs and JIT performance

Reviewed-by: aph
---
 .../gc/z/zBarrierSetAssembler_aarch64.cpp     |   4 +-
 src/hotspot/cpu/aarch64/globals_aarch64.hpp   |   4 +
 src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp |   7 +-
 .../cpu/aarch64/vm_version_aarch64.cpp        |  59 +++
 .../cpu/aarch64/vm_version_aarch64.hpp        |  10 +
 .../ic_ivau_probe_linux_aarch64.S             |  69 +++
 .../linux_aarch64/icache_linux_aarch64.cpp    |  28 ++
 .../linux_aarch64/icache_linux_aarch64.hpp    | 104 ++++-
 .../os_cpu/linux_aarch64/os_linux_aarch64.cpp |  11 +
 .../vm_version_linux_aarch64.cpp              |  10 +
 src/hotspot/share/code/codeBlob.cpp           |   5 +
 src/hotspot/share/code/nmethod.cpp            |  32 +-
 src/hotspot/share/code/nmethod.hpp            |   7 +-
 src/hotspot/share/code/relocInfo.cpp          |   9 -
 src/hotspot/share/code/relocInfo.hpp          |   2 -
 src/hotspot/share/gc/z/zBarrierSetNMethod.cpp |  14 +-
 src/hotspot/share/gc/z/zGeneration.cpp        |  14 +-
 src/hotspot/share/gc/z/zMark.cpp              |  31 +-
 src/hotspot/share/gc/z/zNMethod.cpp           |  16 +-
 src/hotspot/share/gc/z/zNMethod.hpp           |   2 +
 src/hotspot/share/runtime/icache.hpp          |  23 +
 ...tDeferredICacheInvalidationCmdOptions.java | 434 ++++++++++++++++++
 .../gc/TestDeferredICacheInvalidation.java    | 316 +++++++++++++
 .../bench/vm/gc/GCPatchingNmethodCost.java    | 206 +++++++++
 24 files changed, 1371 insertions(+), 46 deletions(-)
 create mode 100644 src/hotspot/os_cpu/linux_aarch64/ic_ivau_probe_linux_aarch64.S
 create mode 100644 src/hotspot/os_cpu/linux_aarch64/icache_linux_aarch64.cpp
 create mode 100644 test/hotspot/jtreg/compiler/runtime/TestDeferredICacheInvalidationCmdOptions.java
 create mode 100644 test/hotspot/jtreg/gc/TestDeferredICacheInvalidation.java
 create mode 100644 test/micro/org/openjdk/bench/vm/gc/GCPatchingNmethodCost.java

diff --git a/src/hotspot/cpu/aarch64/gc/z/zBarrierSetAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/z/zBarrierSetAssembler_aarch64.cpp
index 4f0977a414f..f0885fee93d 100644
--- a/src/hotspot/cpu/aarch64/gc/z/zBarrierSetAssembler_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/gc/z/zBarrierSetAssembler_aarch64.cpp
@@ -879,7 +879,9 @@ void ZBarrierSetAssembler::patch_barrier_relocation(address addr, int format) {
     ShouldNotReachHere();
   }
 
-  ICache::invalidate_word((address)patch_addr);
+  if (!UseSingleICacheInvalidation) {
+    ICache::invalidate_word((address)patch_addr);
+  }
 }
 
 #ifdef COMPILER1
diff --git a/src/hotspot/cpu/aarch64/globals_aarch64.hpp b/src/hotspot/cpu/aarch64/globals_aarch64.hpp
index 0ca5cb25e0c..dfeba73bede 100644
--- a/src/hotspot/cpu/aarch64/globals_aarch64.hpp
+++ b/src/hotspot/cpu/aarch64/globals_aarch64.hpp
@@ -131,6 +131,10 @@ define_pd_global(intx, InlineSmallCode,          1000);
           "Branch Protection to use: none, standard, pac-ret")          \
   product(bool, AlwaysMergeDMB, true, DIAGNOSTIC,                       \
           "Always merge DMB instructions in code emission")             \
+  product(bool, NeoverseN1ICacheErratumMitigation, false, DIAGNOSTIC,   \
+          "Enable workaround for Neoverse N1 erratum 1542419")          \
+  product(bool, UseSingleICacheInvalidation, false, DIAGNOSTIC,         \
+          "Defer multiple ICache invalidation to single invalidation")  \
 
 // end of ARCH_FLAGS
 
diff --git a/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp b/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp
index dbec2d76d4f..f1b9fb213a2 100644
--- a/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp
@@ -54,7 +54,12 @@ void Relocation::pd_set_data_value(address x, bool verify_only) {
     bytes = MacroAssembler::pd_patch_instruction_size(addr(), x);
     break;
   }
-  ICache::invalidate_range(addr(), bytes);
+
+  if (UseSingleICacheInvalidation) {
+    assert(_binding != nullptr, "expect to be called with RelocIterator in use");
+  } else {
+    ICache::invalidate_range(addr(), bytes);
+  }
 }
 
 address Relocation::pd_call_destination(address orig_addr) {
diff --git a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp
index b39d1618b3d..15af2d5c4e2 100644
--- a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp
@@ -24,6 +24,7 @@
  *
  */
 
+#include "logging/log.hpp"
 #include "pauth_aarch64.hpp"
 #include "register_aarch64.hpp"
 #include "runtime/arguments.hpp"
@@ -52,6 +53,10 @@ uintptr_t VM_Version::_pac_mask;
 
 SpinWait VM_Version::_spin_wait;
 
+bool VM_Version::_cache_dic_enabled;
+bool VM_Version::_cache_idc_enabled;
+bool VM_Version::_ic_ivau_trapped;
+
 const char* VM_Version::_features_names[MAX_CPU_FEATURES] = { nullptr };
 
 static SpinWait get_spin_wait_desc() {
@@ -85,6 +90,19 @@ static SpinWait get_spin_wait_desc() {
   return spin_wait;
 }
 
+static bool has_neoverse_n1_errata_1542419() {
+  const int major_rev_num = VM_Version::cpu_variant();
+  const int minor_rev_num = VM_Version::cpu_revision();
+  // Neoverse N1: 0xd0c
+  // Erratum 1542419 affects r3p0, r3p1 and r4p0.
+  // It is fixed in r4p1 and later revisions, which are not affected.
+  return (VM_Version::cpu_family() == VM_Version::CPU_ARM &&
+          VM_Version::model_is(0xd0c) &&
+          ((major_rev_num == 3 && minor_rev_num == 0) ||
+           (major_rev_num == 3 && minor_rev_num == 1) ||
+           (major_rev_num == 4 && minor_rev_num == 0)));
+}
+
 void VM_Version::initialize() {
 #define SET_CPU_FEATURE_NAME(id, name, bit) \
   _features_names[bit] = XSTR(name);
@@ -96,6 +114,10 @@ void VM_Version::initialize() {
   _supports_atomic_getset8 = true;
   _supports_atomic_getadd8 = true;
 
+  _cache_dic_enabled = false;
+  _cache_idc_enabled = false;
+  _ic_ivau_trapped = false;
+
   get_os_cpu_info();
   _cpu_features = _features;
 
@@ -676,6 +698,43 @@ void VM_Version::initialize() {
     clear_feature(CPU_SVE);
   }
 
+  if (FLAG_IS_DEFAULT(UseSingleICacheInvalidation) && is_cache_idc_enabled() && is_cache_dic_enabled()) {
+    FLAG_SET_DEFAULT(UseSingleICacheInvalidation, true);
+  }
+
+  if (FLAG_IS_DEFAULT(NeoverseN1ICacheErratumMitigation) && has_neoverse_n1_errata_1542419()
+      && is_cache_idc_enabled() && !is_cache_dic_enabled()) {
+    if (_ic_ivau_trapped) {
+      FLAG_SET_DEFAULT(NeoverseN1ICacheErratumMitigation, true);
+    } else {
+      log_info(os)("IC IVAU is not trapped; disabling NeoverseN1ICacheErratumMitigation");
+      FLAG_SET_DEFAULT(NeoverseN1ICacheErratumMitigation, false);
+    }
+  }
+
+  if (NeoverseN1ICacheErratumMitigation) {
+    if (!has_neoverse_n1_errata_1542419()) {
+      vm_exit_during_initialization("NeoverseN1ICacheErratumMitigation is set for the CPU not having Neoverse N1 errata 1542419");
+    }
+    // If the user explicitly set the flag, verify the trap is active.
+    if (!FLAG_IS_DEFAULT(NeoverseN1ICacheErratumMitigation) && !_ic_ivau_trapped) {
+      vm_exit_during_initialization("NeoverseN1ICacheErratumMitigation is set but IC IVAU is not trapped. "
+                                    "The optimization is not safe on this system.");
+    }
+    if (FLAG_IS_DEFAULT(UseSingleICacheInvalidation)) {
+      FLAG_SET_DEFAULT(UseSingleICacheInvalidation, true);
+    }
+
+    if (!UseSingleICacheInvalidation) {
+      vm_exit_during_initialization("NeoverseN1ICacheErratumMitigation is set but UseSingleICacheInvalidation is not enabled");
+    }
+  }
+
+  if (UseSingleICacheInvalidation
+      && (!is_cache_idc_enabled() || (!is_cache_dic_enabled() && !NeoverseN1ICacheErratumMitigation))) {
+    vm_exit_during_initialization("UseSingleICacheInvalidation is set but neither IDC nor DIC nor NeoverseN1ICacheErratumMitigation is enabled");
+  }
+
   // Construct the "features" string
   stringStream ss(512);
   ss.print("0x%02x:0x%x:0x%03x:%d", _cpu, _variant, _model, _revision);
diff --git a/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp b/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp
index f8274554f1c..30f1a5d86ca 100644
--- a/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp
+++ b/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp
@@ -58,6 +58,12 @@ protected:
   // When _prefer_sve_merging_mode_cpy is true, `cpy (imm, zeroing)` is
   // implemented as `movi; cpy(imm, merging)`.
   static constexpr bool _prefer_sve_merging_mode_cpy = true;
+  static bool _cache_dic_enabled;
+  static bool _cache_idc_enabled;
+
+  // IC IVAU trap probe for Neoverse N1 erratum 1542419.
+  // Set by get_os_cpu_info() on Linux via ic_ivau_probe_linux_aarch64.S.
+  static bool _ic_ivau_trapped;
 
   static SpinWait _spin_wait;
 
@@ -257,6 +263,10 @@ public:
     return vector_length_in_bytes <= 16;
   }
 
+  static bool is_cache_dic_enabled() { return _cache_dic_enabled; }
+  static bool is_cache_idc_enabled() { return _cache_idc_enabled; }
+  static bool is_ic_ivau_trapped()   { return _ic_ivau_trapped; }
+
   static void get_cpu_features_name(void* features_buffer, stringStream& ss);
 
   // Returns names of features present in features_set1 but not in features_set2
diff --git a/src/hotspot/os_cpu/linux_aarch64/ic_ivau_probe_linux_aarch64.S b/src/hotspot/os_cpu/linux_aarch64/ic_ivau_probe_linux_aarch64.S
new file mode 100644
index 00000000000..b82053d37b9
--- /dev/null
+++ b/src/hotspot/os_cpu/linux_aarch64/ic_ivau_probe_linux_aarch64.S
@@ -0,0 +1,69 @@
+/*
+ * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "defs.S.inc"
+
+    # Probe whether IC IVAU is trapped.
+    #
+    # Returns 1 if IC IVAU is trapped (did not fault), 0 if not trapped
+    # (faulted on VA 0x0, signal handler redirected to continuation).
+    #
+    # int ic_ivau_probe(void);
+DECLARE_FUNC(ic_ivau_probe):
+DECLARE_FUNC(_ic_ivau_probe_fault):
+    ic      ivau, xzr
+    mov     x0, #1
+    ret
+DECLARE_FUNC(_ic_ivau_probe_continuation):
+    mov     x0, #0
+    ret
+
+/* Emit .note.gnu.property section in case of PAC or BTI being enabled. */
+#ifdef __ARM_FEATURE_BTI_DEFAULT
+    #ifdef __ARM_FEATURE_PAC_DEFAULT
+        #define GNU_PROPERTY_AARCH64_FEATURE 3
+    #else
+        #define GNU_PROPERTY_AARCH64_FEATURE 1
+    #endif
+#else
+    #ifdef __ARM_FEATURE_PAC_DEFAULT
+        #define GNU_PROPERTY_AARCH64_FEATURE 2
+    #else
+        #define GNU_PROPERTY_AARCH64_FEATURE 0
+    #endif
+#endif
+
+#if (GNU_PROPERTY_AARCH64_FEATURE != 0)
+        .pushsection .note.gnu.property, "a"
+        .align  3
+        .long   4          /* name length */
+        .long   0x10       /* data length */
+        .long   5          /* note type: NT_GNU_PROPERTY_TYPE_0 */
+        .string "GNU"      /* vendor name */
+        .long   0xc0000000 /* GNU_PROPERTY_AARCH64_FEATURE_1_AND */
+        .long   4          /* pr_datasze */
+        .long   GNU_PROPERTY_AARCH64_FEATURE
+        .long   0
+        .popsection
+#endif
diff --git a/src/hotspot/os_cpu/linux_aarch64/icache_linux_aarch64.cpp b/src/hotspot/os_cpu/linux_aarch64/icache_linux_aarch64.cpp
new file mode 100644
index 00000000000..41cad5af325
--- /dev/null
+++ b/src/hotspot/os_cpu/linux_aarch64/icache_linux_aarch64.cpp
@@ -0,0 +1,28 @@
+/*
+ * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "runtime/icache.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+NOT_PRODUCT(THREAD_LOCAL AArch64ICacheInvalidationContext* AArch64ICacheInvalidationContext::_current_context = nullptr;)
diff --git a/src/hotspot/os_cpu/linux_aarch64/icache_linux_aarch64.hpp b/src/hotspot/os_cpu/linux_aarch64/icache_linux_aarch64.hpp
index 8fbaa7a6b6e..444b3c3ebd6 100644
--- a/src/hotspot/os_cpu/linux_aarch64/icache_linux_aarch64.hpp
+++ b/src/hotspot/os_cpu/linux_aarch64/icache_linux_aarch64.hpp
@@ -26,6 +26,11 @@
 #ifndef OS_CPU_LINUX_AARCH64_ICACHE_AARCH64_HPP
 #define OS_CPU_LINUX_AARCH64_ICACHE_AARCH64_HPP
 
+#include "memory/allocation.hpp"
+#include "runtime/vm_version.hpp"
+#include "utilities/globalDefinitions.hpp"
+#include "vm_version_aarch64.hpp"
+
 // Interface for updating the instruction cache.  Whenever the VM
 // modifies code, part of the processor instruction cache potentially
 // has to be flushed.
@@ -37,8 +42,105 @@ class ICache : public AbstractICache {
     __builtin___clear_cache((char *)addr, (char *)(addr + 4));
   }
   static void invalidate_range(address start, int nbytes) {
-    __builtin___clear_cache((char *)start, (char *)(start + nbytes));
+    if (NeoverseN1ICacheErratumMitigation) {
+      assert(VM_Version::is_cache_idc_enabled(),
+             "Expect CTR_EL0.IDC to be enabled for Neoverse N1 with erratum "
+             "1542419");
+      assert(!VM_Version::is_cache_dic_enabled(),
+             "Expect CTR_EL0.DIC to be disabled for Neoverse N1 with erratum "
+             "1542419");
+      assert(VM_Version::is_ic_ivau_trapped(), "Expect 'ic ivau, xzr' to be trapped");
+      asm volatile("dsb ish       \n"
+                   "ic  ivau, xzr \n"
+                   "dsb ish       \n"
+                   "isb           \n"
+                   : : : "memory");
+    } else {
+      __builtin___clear_cache((char *)start, (char *)(start + nbytes));
+    }
   }
 };
 
+class AArch64ICacheInvalidationContext : StackObj {
+ private:
+
+#ifdef ASSERT
+  static THREAD_LOCAL AArch64ICacheInvalidationContext* _current_context;
+#endif
+
+  bool _has_modified_code;
+
+ public:
+  NONCOPYABLE(AArch64ICacheInvalidationContext);
+
+  AArch64ICacheInvalidationContext()
+      : _has_modified_code(false) {
+    assert(_current_context == nullptr, "nested ICacheInvalidationContext not supported");
+#ifdef ASSERT
+    _current_context = this;
+#endif
+  }
+
+  ~AArch64ICacheInvalidationContext() {
+    NOT_PRODUCT(_current_context = nullptr);
+
+    if (!_has_modified_code || !UseSingleICacheInvalidation) {
+      return;
+    }
+
+    assert(VM_Version::is_cache_idc_enabled(), "Expect CTR_EL0.IDC to be enabled");
+
+    asm volatile("dsb ish" : : : "memory");
+
+    if (NeoverseN1ICacheErratumMitigation) {
+      assert(!VM_Version::is_cache_dic_enabled(),
+             "Expect CTR_EL0.DIC to be disabled for Neoverse N1 with erratum "
+             "1542419");
+      assert(VM_Version::is_ic_ivau_trapped(), "Expect 'ic ivau, xzr' to be trapped");
+
+      // Errata 1542419: Neoverse N1 cores with the 'COHERENT_ICACHE' feature
+      // may fetch stale instructions when software depends on
+      // prefetch-speculation-protection instead of explicit synchronization.
+      //
+      // Neoverse-N1 implementation mitigates the errata 1542419 with a
+      // workaround:
+      // - Disable coherent icache.
+      // - Trap IC IVAU instructions.
+      // - Execute:
+      //   - tlbi vae3is, xzr
+      //   - dsb sy
+      // - Ignore trapped IC IVAU instructions.
+      //
+      // `tlbi vae3is, xzr` invalidates all translation entries (all VAs, all
+      // possible levels). It waits for all memory accesses using in-scope old
+      // translation information to complete before it is considered complete.
+      //
+      // As this workaround has significant overhead, Arm Neoverse N1 (MP050)
+      // Software Developer Errata Notice version 29.0 suggests:
+      //
+      // "Since one TLB inner-shareable invalidation is enough to avoid this
+      // erratum, the number of injected TLB invalidations should be minimized
+      // in the trap handler to mitigate the performance impact due to this
+      // workaround."
+      // As the address for icache invalidation is not relevant and
+      // IC IVAU instruction is ignored, we use XZR in it.
+      asm volatile(
+          "ic  ivau, xzr \n"
+          "dsb ish       \n"
+          :
+          :
+          : "memory");
+    } else {
+      assert(VM_Version::is_cache_dic_enabled(), "Expect CTR_EL0.DIC to be enabled");
+    }
+    asm volatile("isb" : : : "memory");
+  }
+
+  void set_has_modified_code() {
+    _has_modified_code = true;
+  }
+};
+
+#define PD_ICACHE_INVALIDATION_CONTEXT AArch64ICacheInvalidationContext
+
 #endif // OS_CPU_LINUX_AARCH64_ICACHE_AARCH64_HPP
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 da9e7e159f1..67e0569bf31 100644
--- a/src/hotspot/os_cpu/linux_aarch64/os_linux_aarch64.cpp
+++ b/src/hotspot/os_cpu/linux_aarch64/os_linux_aarch64.cpp
@@ -77,6 +77,11 @@
 #define REG_LR 30
 #define REG_BCP 22
 
+// IC IVAU trap probe.
+// Defined in ic_ivau_probe_linux_aarch64.S.
+extern "C" char _ic_ivau_probe_fault[] __attribute__ ((visibility ("hidden")));
+extern "C" char _ic_ivau_probe_continuation[] __attribute__ ((visibility ("hidden")));
+
 NOINLINE address os::current_stack_pointer() {
   return (address)__builtin_frame_address(0);
 }
@@ -228,6 +233,12 @@ bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info,
       }
     }
 
+    // IC IVAU trap probe during VM_Version initialization.
+    // If IC IVAU is not trapped, it faults on unmapped VA 0x0.
+    if (sig == SIGSEGV && pc == (address)_ic_ivau_probe_fault) {
+      stub = (address)_ic_ivau_probe_continuation;
+    }
+
     if (thread->thread_state() == _thread_in_Java) {
       // Java thread running in Java code => find exception handler if any
       // a fault inside compiled code, the interpreter, or a stub
diff --git a/src/hotspot/os_cpu/linux_aarch64/vm_version_linux_aarch64.cpp b/src/hotspot/os_cpu/linux_aarch64/vm_version_linux_aarch64.cpp
index 168fc622a0b..ee2d3013c4c 100644
--- a/src/hotspot/os_cpu/linux_aarch64/vm_version_linux_aarch64.cpp
+++ b/src/hotspot/os_cpu/linux_aarch64/vm_version_linux_aarch64.cpp
@@ -31,6 +31,10 @@
 #include 
 #include 
 
+// IC IVAU trap probe.
+// Defined in ic_ivau_probe_linux_aarch64.S.
+extern "C" int ic_ivau_probe(void);
+
 #ifndef HWCAP_AES
 #define HWCAP_AES   (1<<3)
 #endif
@@ -182,6 +186,12 @@ void VM_Version::get_os_cpu_info() {
 
   _icache_line_size = (1 << (ctr_el0 & 0x0f)) * 4;
   _dcache_line_size = (1 << ((ctr_el0 >> 16) & 0x0f)) * 4;
+  _cache_idc_enabled = ((ctr_el0 >> 28) & 0x1) != 0;
+  _cache_dic_enabled = ((ctr_el0 >> 29) & 0x1) != 0;
+
+  // Probe whether IC IVAU is trapped.
+  // Must run before VM_Version::initialize() sets NeoverseN1ICacheErratumMitigation.
+  _ic_ivau_trapped = (ic_ivau_probe() == 1);
 
   if (!(dczid_el0 & 0x10)) {
     _zva_length = 4 << (dczid_el0 & 0xf);
diff --git a/src/hotspot/share/code/codeBlob.cpp b/src/hotspot/share/code/codeBlob.cpp
index a7d939e590d..e0c286937d0 100644
--- a/src/hotspot/share/code/codeBlob.cpp
+++ b/src/hotspot/share/code/codeBlob.cpp
@@ -326,6 +326,11 @@ RuntimeBlob::RuntimeBlob(
   : CodeBlob(name, kind, cb, size, header_size, frame_complete, frame_size, oop_maps, caller_must_gc_arguments,
              align_up(cb->total_relocation_size(), oopSize))
 {
+  if (code_size() == 0) {
+    // Nothing to copy
+    return;
+  }
+
   cb->copy_code_and_locs_to(this);
 
   // Flush generated code
diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp
index 0e2aa208854..de2c826667f 100644
--- a/src/hotspot/share/code/nmethod.cpp
+++ b/src/hotspot/share/code/nmethod.cpp
@@ -1332,6 +1332,7 @@ nmethod::nmethod(
     code_buffer->copy_values_to(this);
 
     post_init();
+    ICache::invalidate_range(code_begin(), code_size());
   }
 
   if (PrintNativeNMethods || PrintDebugInfo || PrintRelocations || PrintDependencies) {
@@ -1811,6 +1812,7 @@ nmethod::nmethod(
     init_immutable_data_ref_count();
 
     post_init();
+    ICache::invalidate_range(code_begin(), code_size());
 
     // we use the information of entry points to find out if a method is
     // static or non static
@@ -2038,7 +2040,7 @@ void nmethod::copy_values(GrowableArray* array) {
   // The code and relocations have already been initialized by the
   // CodeBlob constructor, so it is valid even at this early point to
   // iterate over relocations and patch the code.
-  fix_oop_relocations(nullptr, nullptr, /*initialize_immediates=*/ true);
+  fix_oop_relocations(/*initialize_immediates=*/ true);
 }
 
 void nmethod::copy_values(GrowableArray* array) {
@@ -2050,24 +2052,42 @@ void nmethod::copy_values(GrowableArray* array) {
   }
 }
 
-void nmethod::fix_oop_relocations(address begin, address end, bool initialize_immediates) {
+bool nmethod::fix_oop_relocations(bool initialize_immediates) {
   // re-patch all oop-bearing instructions, just in case some oops moved
-  RelocIterator iter(this, begin, end);
+  RelocIterator iter(this);
+  bool modified_code = false;
   while (iter.next()) {
     if (iter.type() == relocInfo::oop_type) {
       oop_Relocation* reloc = iter.oop_reloc();
-      if (initialize_immediates && reloc->oop_is_immediate()) {
+      if (!reloc->oop_is_immediate()) {
+        // Refresh the oop-related bits of this instruction.
+        reloc->set_value(reloc->value());
+        modified_code = true;
+      } else if (initialize_immediates) {
         oop* dest = reloc->oop_addr();
         jobject obj = *reinterpret_cast(dest);
         initialize_immediate_oop(dest, obj);
       }
-      // Refresh the oop-related bits of this instruction.
-      reloc->fix_oop_relocation();
     } else if (iter.type() == relocInfo::metadata_type) {
       metadata_Relocation* reloc = iter.metadata_reloc();
       reloc->fix_metadata_relocation();
+      modified_code |= !reloc->metadata_is_immediate();
     }
   }
+  return modified_code;
+}
+
+void nmethod::fix_oop_relocations() {
+  ICacheInvalidationContext icic;
+  fix_oop_relocations(&icic);
+}
+
+void nmethod::fix_oop_relocations(ICacheInvalidationContext* icic) {
+  assert(icic != nullptr, "must provide context to track if code was modified");
+  bool modified_code = fix_oop_relocations(/*initialize_immediates=*/ false);
+  if (modified_code) {
+    icic->set_has_modified_code();
+  }
 }
 
 static void install_post_call_nop_displacement(nmethod* nm, address pc) {
diff --git a/src/hotspot/share/code/nmethod.hpp b/src/hotspot/share/code/nmethod.hpp
index 092da181f12..ea8c0e2ad5d 100644
--- a/src/hotspot/share/code/nmethod.hpp
+++ b/src/hotspot/share/code/nmethod.hpp
@@ -41,6 +41,7 @@ class Dependencies;
 class DirectiveSet;
 class DebugInformationRecorder;
 class ExceptionHandlerTable;
+class ICacheInvalidationContext;
 class ImplicitExceptionTable;
 class JvmtiThreadState;
 class MetadataClosure;
@@ -801,15 +802,15 @@ public:
 
   // Relocation support
 private:
-  void fix_oop_relocations(address begin, address end, bool initialize_immediates);
+  bool fix_oop_relocations(bool initialize_immediates);
   inline void initialize_immediate_oop(oop* dest, jobject handle);
 
 protected:
   address oops_reloc_begin() const;
 
 public:
-  void fix_oop_relocations(address begin, address end) { fix_oop_relocations(begin, end, false); }
-  void fix_oop_relocations()                           { fix_oop_relocations(nullptr, nullptr, false); }
+  void fix_oop_relocations(ICacheInvalidationContext* icic);
+  void fix_oop_relocations();
 
   bool is_at_poll_return(address pc);
   bool is_at_poll_or_poll_return(address pc);
diff --git a/src/hotspot/share/code/relocInfo.cpp b/src/hotspot/share/code/relocInfo.cpp
index 2a6335e2118..25d91edc20f 100644
--- a/src/hotspot/share/code/relocInfo.cpp
+++ b/src/hotspot/share/code/relocInfo.cpp
@@ -590,15 +590,6 @@ oop oop_Relocation::oop_value() {
   return *oop_addr();
 }
 
-
-void oop_Relocation::fix_oop_relocation() {
-  if (!oop_is_immediate()) {
-    // get the oop from the pool, and re-insert it into the instruction:
-    set_value(value());
-  }
-}
-
-
 void oop_Relocation::verify_oop_relocation() {
   if (!oop_is_immediate()) {
     // get the oop from the pool, and re-insert it into the instruction:
diff --git a/src/hotspot/share/code/relocInfo.hpp b/src/hotspot/share/code/relocInfo.hpp
index 6f1778ef479..bb2b2b5693f 100644
--- a/src/hotspot/share/code/relocInfo.hpp
+++ b/src/hotspot/share/code/relocInfo.hpp
@@ -988,8 +988,6 @@ class oop_Relocation : public DataRelocation {
   void pack_data_to(CodeSection* dest) override;
   void unpack_data() override;
 
-  void fix_oop_relocation();        // reasserts oop value
-
   void verify_oop_relocation();
 
   address value() override { return *reinterpret_cast(oop_addr()); }
diff --git a/src/hotspot/share/gc/z/zBarrierSetNMethod.cpp b/src/hotspot/share/gc/z/zBarrierSetNMethod.cpp
index d80ce4e149d..a439b3a167b 100644
--- a/src/hotspot/share/gc/z/zBarrierSetNMethod.cpp
+++ b/src/hotspot/share/gc/z/zBarrierSetNMethod.cpp
@@ -33,6 +33,7 @@
 #include "gc/z/zThreadLocalData.hpp"
 #include "gc/z/zUncoloredRoot.inline.hpp"
 #include "logging/log.hpp"
+#include "runtime/icache.hpp"
 #include "runtime/threadWXSetters.inline.hpp"
 
 bool ZBarrierSetNMethod::nmethod_entry_barrier(nmethod* nm) {
@@ -70,12 +71,15 @@ bool ZBarrierSetNMethod::nmethod_entry_barrier(nmethod* nm) {
     return false;
   }
 
-  // Heal barriers
-  ZNMethod::nmethod_patch_barriers(nm);
+  {
+    ICacheInvalidationContext icic;
+    // Heal barriers
+    ZNMethod::nmethod_patch_barriers(nm, &icic);
 
-  // Heal oops
-  ZUncoloredRootProcessWeakOopClosure cl(ZNMethod::color(nm));
-  ZNMethod::nmethod_oops_do_inner(nm, &cl);
+    // Heal oops
+    ZUncoloredRootProcessWeakOopClosure cl(ZNMethod::color(nm));
+    ZNMethod::nmethod_oops_do_inner(nm, &cl, &icic);
+  }
 
   const uintptr_t prev_color = ZNMethod::color(nm);
   const uintptr_t new_color = *ZPointerStoreGoodMaskLowOrderBitsAddr;
diff --git a/src/hotspot/share/gc/z/zGeneration.cpp b/src/hotspot/share/gc/z/zGeneration.cpp
index 27f352a624f..0f9f4e34a5e 100644
--- a/src/hotspot/share/gc/z/zGeneration.cpp
+++ b/src/hotspot/share/gc/z/zGeneration.cpp
@@ -58,6 +58,7 @@
 #include "prims/jvmtiTagMap.hpp"
 #include "runtime/continuation.hpp"
 #include "runtime/handshake.hpp"
+#include "runtime/icache.hpp"
 #include "runtime/safepoint.hpp"
 #include "runtime/threads.hpp"
 #include "runtime/vmOperations.hpp"
@@ -1434,12 +1435,15 @@ public:
   virtual void do_nmethod(nmethod* nm) {
     ZLocker locker(ZNMethod::lock_for_nmethod(nm));
     if (_bs_nm->is_armed(nm)) {
-      // Heal barriers
-      ZNMethod::nmethod_patch_barriers(nm);
+      {
+        ICacheInvalidationContext icic;
+        // Heal barriers
+        ZNMethod::nmethod_patch_barriers(nm, &icic);
 
-      // Heal oops
-      ZUncoloredRootProcessOopClosure cl(ZNMethod::color(nm));
-      ZNMethod::nmethod_oops_do_inner(nm, &cl);
+        // Heal oops
+        ZUncoloredRootProcessOopClosure cl(ZNMethod::color(nm));
+        ZNMethod::nmethod_oops_do_inner(nm, &cl, &icic);
+      }
 
       log_trace(gc, nmethod)("nmethod: " PTR_FORMAT " visited by old remapping", p2i(nm));
 
diff --git a/src/hotspot/share/gc/z/zMark.cpp b/src/hotspot/share/gc/z/zMark.cpp
index 03701ae9998..ac7d86db240 100644
--- a/src/hotspot/share/gc/z/zMark.cpp
+++ b/src/hotspot/share/gc/z/zMark.cpp
@@ -59,6 +59,7 @@
 #include "oops/oop.inline.hpp"
 #include "runtime/continuation.hpp"
 #include "runtime/handshake.hpp"
+#include "runtime/icache.hpp"
 #include "runtime/javaThread.hpp"
 #include "runtime/prefetch.inline.hpp"
 #include "runtime/safepointMechanism.hpp"
@@ -718,12 +719,15 @@ public:
   virtual void do_nmethod(nmethod* nm) {
     ZLocker locker(ZNMethod::lock_for_nmethod(nm));
     if (_bs_nm->is_armed(nm)) {
-      // Heal barriers
-      ZNMethod::nmethod_patch_barriers(nm);
+      {
+         ICacheInvalidationContext icic;
+         // Heal barriers
+         ZNMethod::nmethod_patch_barriers(nm, &icic);
 
-      // Heal oops
-      ZUncoloredRootMarkOopClosure cl(ZNMethod::color(nm));
-      ZNMethod::nmethod_oops_do_inner(nm, &cl);
+         // Heal oops
+         ZUncoloredRootMarkOopClosure cl(ZNMethod::color(nm));
+         ZNMethod::nmethod_oops_do_inner(nm, &cl, &icic);
+      }
 
       // CodeCache unloading support
       nm->mark_as_maybe_on_stack();
@@ -753,10 +757,6 @@ public:
     if (_bs_nm->is_armed(nm)) {
       const uintptr_t prev_color = ZNMethod::color(nm);
 
-      // Heal oops
-      ZUncoloredRootMarkYoungOopClosure cl(prev_color);
-      ZNMethod::nmethod_oops_do_inner(nm, &cl);
-
       // Disarm only the young marking, not any potential old marking cycle
 
       const uintptr_t old_marked_mask = ZPointerMarkedMask ^ (ZPointerMarkedYoung0 | ZPointerMarkedYoung1);
@@ -767,9 +767,16 @@ public:
       // Check if disarming for young mark, completely disarms the nmethod entry barrier
       const bool complete_disarm = ZPointer::is_store_good(new_disarm_value_ptr);
 
-      if (complete_disarm) {
-        // We are about to completely disarm the nmethod, must take responsibility to patch all barriers before disarming
-        ZNMethod::nmethod_patch_barriers(nm);
+      {
+        ICacheInvalidationContext icic;
+        if (complete_disarm) {
+          // We are about to completely disarm the nmethod, must take responsibility to patch all barriers before disarming
+          ZNMethod::nmethod_patch_barriers(nm, &icic);
+        }
+
+        // Heal oops
+        ZUncoloredRootMarkYoungOopClosure cl(prev_color);
+        ZNMethod::nmethod_oops_do_inner(nm, &cl, &icic);
       }
 
       _bs_nm->guard_with(nm, (int)untype(new_disarm_value_ptr));
diff --git a/src/hotspot/share/gc/z/zNMethod.cpp b/src/hotspot/share/gc/z/zNMethod.cpp
index 780bc9e3bf7..a1348b63b6f 100644
--- a/src/hotspot/share/gc/z/zNMethod.cpp
+++ b/src/hotspot/share/gc/z/zNMethod.cpp
@@ -50,6 +50,7 @@
 #include "oops/oop.inline.hpp"
 #include "runtime/atomicAccess.hpp"
 #include "runtime/continuation.hpp"
+#include "runtime/icache.hpp"
 #include "utilities/debug.hpp"
 
 static ZNMethodData* gc_data(const nmethod* nm) {
@@ -245,8 +246,16 @@ void ZNMethod::set_guard_value(nmethod* nm, int value) {
 }
 
 void ZNMethod::nmethod_patch_barriers(nmethod* nm) {
+  ICacheInvalidationContext icic;
+  nmethod_patch_barriers(nm, &icic);
+}
+
+void ZNMethod::nmethod_patch_barriers(nmethod* nm, ICacheInvalidationContext* icic) {
   ZBarrierSetAssembler* const bs_asm = ZBarrierSet::assembler();
   ZArrayIterator iter(gc_data(nm)->barriers());
+  if (gc_data(nm)->barriers()->is_nonempty()) {
+    icic->set_has_modified_code();
+  }
   for (ZNMethodDataBarrier barrier; iter.next(&barrier);) {
     bs_asm->patch_barrier_relocation(barrier._reloc_addr, barrier._reloc_format);
   }
@@ -258,6 +267,11 @@ void ZNMethod::nmethod_oops_do(nmethod* nm, OopClosure* cl) {
 }
 
 void ZNMethod::nmethod_oops_do_inner(nmethod* nm, OopClosure* cl) {
+  ICacheInvalidationContext icic;
+  nmethod_oops_do_inner(nm, cl, &icic);
+}
+
+void ZNMethod::nmethod_oops_do_inner(nmethod* nm, OopClosure* cl, ICacheInvalidationContext* icic) {
   // Process oops table
   {
     oop* const begin = nm->oops_begin();
@@ -283,7 +297,7 @@ void ZNMethod::nmethod_oops_do_inner(nmethod* nm, OopClosure* cl) {
 
   // Process non-immediate oops
   if (data->has_non_immediate_oops()) {
-    nm->fix_oop_relocations();
+    nm->fix_oop_relocations(icic);
   }
 }
 
diff --git a/src/hotspot/share/gc/z/zNMethod.hpp b/src/hotspot/share/gc/z/zNMethod.hpp
index 865ea11e7b9..2779151c576 100644
--- a/src/hotspot/share/gc/z/zNMethod.hpp
+++ b/src/hotspot/share/gc/z/zNMethod.hpp
@@ -56,9 +56,11 @@ public:
   static void set_guard_value(nmethod* nm, int value);
 
   static void nmethod_patch_barriers(nmethod* nm);
+  static void nmethod_patch_barriers(nmethod* nm, ICacheInvalidationContext* icic);
 
   static void nmethod_oops_do(nmethod* nm, OopClosure* cl);
   static void nmethod_oops_do_inner(nmethod* nm, OopClosure* cl);
+  static void nmethod_oops_do_inner(nmethod* nm, OopClosure* cl, ICacheInvalidationContext* icic);
 
   static void nmethods_do_begin(bool secondary);
   static void nmethods_do_end(bool secondary);
diff --git a/src/hotspot/share/runtime/icache.hpp b/src/hotspot/share/runtime/icache.hpp
index bc153862323..692a876d9a6 100644
--- a/src/hotspot/share/runtime/icache.hpp
+++ b/src/hotspot/share/runtime/icache.hpp
@@ -129,4 +129,27 @@ class ICacheStubGenerator : public StubCodeGenerator {
   void generate_icache_flush(ICache::flush_icache_stub_t* flush_icache_stub);
 };
 
+class DefaultICacheInvalidationContext : StackObj {
+ public:
+  NONCOPYABLE(DefaultICacheInvalidationContext);
+
+  DefaultICacheInvalidationContext() {}
+
+  ~DefaultICacheInvalidationContext() {}
+
+  void set_has_modified_code() {}
+};
+
+#ifndef PD_ICACHE_INVALIDATION_CONTEXT
+#define PD_ICACHE_INVALIDATION_CONTEXT DefaultICacheInvalidationContext
+#endif // PD_ICACHE_INVALIDATION_CONTEXT
+
+class ICacheInvalidationContext final : public PD_ICACHE_INVALIDATION_CONTEXT {
+ private:
+  NONCOPYABLE(ICacheInvalidationContext);
+
+ public:
+  using PD_ICACHE_INVALIDATION_CONTEXT::PD_ICACHE_INVALIDATION_CONTEXT;
+};
+
 #endif // SHARE_RUNTIME_ICACHE_HPP
diff --git a/test/hotspot/jtreg/compiler/runtime/TestDeferredICacheInvalidationCmdOptions.java b/test/hotspot/jtreg/compiler/runtime/TestDeferredICacheInvalidationCmdOptions.java
new file mode 100644
index 00000000000..c46f1ecab98
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/runtime/TestDeferredICacheInvalidationCmdOptions.java
@@ -0,0 +1,434 @@
+/*
+ * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package compiler.runtime;
+
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.process.ProcessTools;
+import jdk.test.whitebox.WhiteBox;
+import jtreg.SkippedException;
+
+/*
+ * @test
+ * @bug 8370947 8381003
+ * @summary Test command-line options for UseSingleICacheInvalidation and NeoverseN1ICacheErratumMitigation
+ * @library /test/lib
+ * @requires os.arch == "aarch64"
+ * @requires os.family == "linux"
+ * @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.runtime.TestDeferredICacheInvalidationCmdOptions
+ */
+
+public class TestDeferredICacheInvalidationCmdOptions {
+
+    // CPU identifiers
+    private static final int CPU_ARM = 0x41;
+    private static final int NEOVERSE_N1_MODEL = 0xd0c;
+
+    // Known ARM Neoverse models where we can predict UseSingleICacheInvalidation
+    // behavior.
+    private static final int[] KNOWN_NEOVERSE_MODELS = {
+        NEOVERSE_N1_MODEL,
+        0xd40, // Neoverse V1
+        0xd49, // Neoverse N2
+        0xd4f, // Neoverse V2
+        0xd83, // Neoverse V3AE
+        0xd84, // Neoverse V3
+        0xd8e, // Neoverse N3
+    };
+
+    private static boolean isAffected;
+    private static boolean isKnownModel;
+
+    public static void main(String[] args) throws Exception {
+        // This test does not depend on CPU identification — run it first.
+        testDisableBothFlags();
+
+        // Parse CPU features and print CPU info
+        parseCPUFeatures();
+
+        if (!isKnownModel) {
+            throw new SkippedException("Unknown CPU model - skipping remaining tests.");
+        }
+
+        if (isAffected) {
+            // Detect whether IC IVAU is trapped on this system.
+            ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder(
+                "-XX:+UnlockDiagnosticVMOptions",
+                "-XX:+NeoverseN1ICacheErratumMitigation",
+                "-version");
+            OutputAnalyzer output = new OutputAnalyzer(pb.start());
+
+            if (output.getExitValue() != 0) {
+                // Verify the failure is the expected probe error, not something else.
+                output.shouldContain("IC IVAU is not trapped");
+                throw new SkippedException("IC IVAU is not trapped - skipping remaining tests.");
+            } else {
+                System.out.println("IC IVAU trap active.");
+            }
+        }
+
+        if (isAffected) {
+            // Check defaults on Neoverse N1 pre-r4p1
+            testCase_DefaultsOnNeoverseN1();
+
+            // Check if NeoverseN1ICacheErratumMitigation is set to false on affected CPUs,
+            // UseSingleICacheInvalidation is also set to false
+            testCase_ExplicitlyDisableErrataAffectsDeferred();
+
+            // Check JVM error if UseSingleICacheInvalidation=true
+            // but NeoverseN1ICacheErratumMitigation=false on affected CPUs
+            testCase_ConflictingFlagsOnAffectedCPUs();
+
+            // Check explicit NeoverseN1ICacheErratumMitigation=true enables UseSingleICacheInvalidation
+            testCase_ExplicitlyEnableErrataEnablesDeferred();
+
+            // Check UseSingleICacheInvalidation=false with NeoverseN1ICacheErratumMitigation=true
+            testCase_ConflictingErrataWithoutDeferred();
+        } else {
+            // Check NeoverseN1ICacheErratumMitigation is false on unaffected CPUs
+            testCase_DefaultsOnUnaffectedCPUs();
+
+            // Check setting NeoverseN1ICacheErratumMitigation=true on unaffected CPU causes an error
+            testCase_EnablingErrataOnUnaffectedCPU();
+        }
+
+        System.out.println("All test cases passed!");
+    }
+
+    /**
+     * Parse CPU features string from WhiteBox.getCPUFeatures() to extract:
+     * - cpuFamily: 0x41 for ARM
+     * - cpuVariant: major revision
+     * - cpuModel: e.g., 0xd0c for Neoverse N1
+     * - cpuRevision: minor revision
+     * - cpuModel2: secondary model (if present, in parentheses)
+     *
+     * Sets the static fields isAffected and isKnownModel, and prints CPU info.
+     *
+     * Format: 0x%02x:0x%x:0x%03x:%d[(0x%03x)]
+     * Example: "0x41:0x3:0xd0c:0" or "0x41:0x3:0xd0c:0(0xd0c)"
+     *
+     * @throws SkippedException if not running on ARM CPU
+     */
+    private static void parseCPUFeatures() {
+        WhiteBox wb = WhiteBox.getWhiteBox();
+        String cpuFeatures = wb.getCPUFeatures();
+        System.out.println("CPU Features string: " + cpuFeatures);
+
+        if (cpuFeatures == null || cpuFeatures.isEmpty()) {
+            throw new RuntimeException("No CPU features available");
+        }
+
+        int commaIndex = cpuFeatures.indexOf(",");
+        if (commaIndex == -1) {
+            throw new RuntimeException("Unexpected CPU features format (no comma): " + cpuFeatures);
+        }
+
+        String cpuPart = cpuFeatures.substring(0, commaIndex).trim();
+
+        String[] parts = cpuPart.split(":");
+        if (parts.length < 4) {
+            throw new RuntimeException("Unexpected CPU features format: " + cpuPart);
+        }
+
+        int cpuFamily = Integer.parseInt(parts[0].substring(2), 16);
+        if (cpuFamily != CPU_ARM) {
+            throw new SkippedException("Not running on ARM CPU (cpuFamily=0x" + Integer.toHexString(cpuFamily) + ")");
+        }
+
+        int cpuVariant = Integer.parseInt(parts[1].substring(2), 16);
+        int cpuModel = Integer.parseInt(parts[2].substring(2), 16);
+        int cpuModel2 = 0;
+
+        int model2Start = parts[3].indexOf("(");
+        String revisionStr = parts[3];
+        if (model2Start != -1) {
+            if (!parts[3].endsWith(")")) {
+                throw new RuntimeException("Unexpected CPU features format (missing closing parenthesis): " + parts[3]);
+            }
+            String model2Str = parts[3].substring(model2Start + 1, parts[3].length() - 1);
+            cpuModel2 = Integer.parseInt(model2Str.substring(2), 16);
+            revisionStr = parts[3].substring(0, model2Start);
+        }
+        int cpuRevision = Integer.parseInt(revisionStr);
+
+        // Neoverse N1 errata 1542419 affects r3p0, r3p1 and r4p0.
+        // It is fixed in r4p1 and later revisions.
+        if (cpuModel == NEOVERSE_N1_MODEL || cpuModel2 == NEOVERSE_N1_MODEL) {
+            isAffected = (cpuVariant == 3 && cpuRevision == 0) ||
+                         (cpuVariant == 3 && cpuRevision == 1) ||
+                         (cpuVariant == 4 && cpuRevision == 0);
+        }
+
+        // Check if this is a known Neoverse model.
+        isKnownModel = false;
+        for (int model : KNOWN_NEOVERSE_MODELS) {
+            if (cpuModel == model || cpuModel2 == model) {
+                isKnownModel = true;
+                break;
+            }
+        }
+
+        printCPUInfo(cpuFamily, cpuVariant, cpuModel, cpuModel2, cpuRevision);
+    }
+
+    private static void printCPUInfo(int cpuFamily, int cpuVariant, int cpuModel, int cpuModel2, int cpuRevision) {
+        boolean isNeoverseN1 = (cpuFamily == CPU_ARM) &&
+                               (cpuModel == NEOVERSE_N1_MODEL || cpuModel2 == NEOVERSE_N1_MODEL);
+        System.out.println("\n=== CPU Information ===");
+        System.out.println("CPU Family: 0x" + Integer.toHexString(cpuFamily));
+        System.out.println("CPU Variant: 0x" + Integer.toHexString(cpuVariant));
+        System.out.println("CPU Model: 0x" + Integer.toHexString(cpuModel));
+        if (cpuModel2 != 0) {
+            System.out.println("CPU Model2: 0x" + Integer.toHexString(cpuModel2));
+        }
+        System.out.println("CPU Revision: " + cpuRevision);
+        System.out.println("Is Neoverse N1: " + isNeoverseN1);
+        System.out.println("Is affected by errata 1542419: " + isAffected);
+        System.out.println("Is known model: " + isKnownModel);
+        System.out.println("======================\n");
+    }
+
+    /**
+     * Test that UseSingleICacheInvalidation and NeoverseN1ICacheErratumMitigation flags
+     * can be explicitly set to false on any system.
+     */
+    private static void testDisableBothFlags() throws Exception {
+        System.out.println("\nTest: Explicitly disable both flags");
+
+        ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder(
+            "-XX:+UnlockDiagnosticVMOptions",
+            "-XX:-UseSingleICacheInvalidation",
+            "-XX:-NeoverseN1ICacheErratumMitigation",
+            "-XX:+PrintFlagsFinal",
+            "-version");
+
+        OutputAnalyzer output = new OutputAnalyzer(pb.start());
+        output.shouldHaveExitValue(0);
+
+        String output_str = output.getOutput();
+        boolean hasSingleDisabled = output_str.matches("(?s).*bool\\s+UseSingleICacheInvalidation\\s*=\\s*false.*");
+        boolean hasErrataDisabled = output_str.matches("(?s).*bool\\s+NeoverseN1ICacheErratumMitigation\\s*=\\s*false.*");
+
+        System.out.println("UseSingleICacheInvalidation disabled: " + hasSingleDisabled);
+        System.out.println("NeoverseN1ICacheErratumMitigation disabled: " + hasErrataDisabled);
+
+        if (!hasErrataDisabled) {
+            throw new RuntimeException("Failed to disable NeoverseN1ICacheErratumMitigation via command line");
+        }
+
+        if (!hasSingleDisabled) {
+            throw new RuntimeException("Failed to disable UseSingleICacheInvalidation via command line");
+        }
+
+        System.out.println("Successfully disabled both flags");
+    }
+
+    /**
+     * Check defaults on Neoverse N1 affected revisions.
+     * UseSingleICacheInvalidation and NeoverseN1ICacheErratumMitigation flags should be true.
+     */
+    private static void testCase_DefaultsOnNeoverseN1() throws Exception {
+        System.out.println("\nTest: Check defaults on Neoverse N1 affected revisions");
+
+        ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder(
+            "-XX:+UnlockDiagnosticVMOptions",
+            "-XX:+PrintFlagsFinal",
+            "-version");
+
+        OutputAnalyzer output = new OutputAnalyzer(pb.start());
+        output.shouldHaveExitValue(0);
+
+        String output_str = output.getOutput();
+        boolean hasSingleEnabled = output_str.matches("(?s).*bool\\s+UseSingleICacheInvalidation\\s*=\\s*true.*");
+        boolean hasErrataEnabled = output_str.matches("(?s).*bool\\s+NeoverseN1ICacheErratumMitigation\\s*=\\s*true.*");
+
+        System.out.println("UseSingleICacheInvalidation enabled: " + hasSingleEnabled);
+        System.out.println("NeoverseN1ICacheErratumMitigation enabled: " + hasErrataEnabled);
+
+        if (!hasSingleEnabled || !hasErrataEnabled) {
+            throw new RuntimeException("On affected Neoverse N1 with trap active, " +
+                 "UseSingleICacheInvalidation and NeoverseN1ICacheErratumMitigation flags should be enabled by default");
+        }
+        System.out.println("Correctly enabled on affected Neoverse N1");
+    }
+
+    /**
+     * Check NeoverseN1ICacheErratumMitigation is false on unaffected CPUs.
+     */
+    private static void testCase_DefaultsOnUnaffectedCPUs() throws Exception {
+        System.out.println("\nTest: Check NeoverseN1ICacheErratumMitigation is false on unaffected CPUs");
+
+        ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder(
+            "-XX:+UnlockDiagnosticVMOptions",
+            "-XX:+PrintFlagsFinal",
+            "-version");
+
+        OutputAnalyzer output = new OutputAnalyzer(pb.start());
+        output.shouldHaveExitValue(0);
+
+        String output_str = output.getOutput();
+        boolean hasErrataEnabled = output_str.matches("(?s).*bool\\s+NeoverseN1ICacheErratumMitigation\\s*=\\s*true.*");
+
+        System.out.println("NeoverseN1ICacheErratumMitigation enabled: " + hasErrataEnabled);
+
+        if (hasErrataEnabled) {
+            throw new RuntimeException("On unaffected CPUs, NeoverseN1ICacheErratumMitigation should be disabled");
+        }
+        System.out.println("Correctly disabled on unaffected CPU");
+    }
+
+    /**
+     * Check if NeoverseN1ICacheErratumMitigation is set to false via cmd on affected CPUs,
+     * UseSingleICacheInvalidation is set to false.
+     */
+    private static void testCase_ExplicitlyDisableErrataAffectsDeferred() throws Exception {
+        System.out.println("\nTest: Explicitly disable NeoverseN1ICacheErratumMitigation, check UseSingleICacheInvalidation");
+
+        ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder(
+            "-XX:+UnlockDiagnosticVMOptions",
+            "-XX:-NeoverseN1ICacheErratumMitigation",
+            "-XX:+PrintFlagsFinal",
+            "-version");
+
+        OutputAnalyzer output = new OutputAnalyzer(pb.start());
+        output.shouldHaveExitValue(0);
+
+        String output_str = output.getOutput();
+        boolean hasSingleDisabled = output_str.matches("(?s).*bool\\s+UseSingleICacheInvalidation\\s*=\\s*false.*");
+        boolean hasErrataDisabled = output_str.matches("(?s).*bool\\s+NeoverseN1ICacheErratumMitigation\\s*=\\s*false.*");
+
+        System.out.println("NeoverseN1ICacheErratumMitigation disabled: " + hasErrataDisabled);
+        System.out.println("UseSingleICacheInvalidation disabled: " + hasSingleDisabled);
+
+        if (!hasErrataDisabled) {
+            throw new RuntimeException("Failed to disable NeoverseN1ICacheErratumMitigation via command line");
+        }
+
+        if (!hasSingleDisabled) {
+            throw new RuntimeException("On affected CPU, disabling NeoverseN1ICacheErratumMitigation should also disable UseSingleICacheInvalidation");
+        }
+        System.out.println("Correctly synchronized on affected CPU");
+    }
+
+    /**
+     * Check JVM reports an error if UseSingleICacheInvalidation is set to true
+     * but NeoverseN1ICacheErratumMitigation is set to false on affected CPUs.
+     */
+    private static void testCase_ConflictingFlagsOnAffectedCPUs() throws Exception {
+        System.out.println("\nTest: Try to set UseSingleICacheInvalidation=true with NeoverseN1ICacheErratumMitigation=false");
+
+        ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder(
+            "-XX:+UnlockDiagnosticVMOptions",
+            "-XX:+UseSingleICacheInvalidation",
+            "-XX:-NeoverseN1ICacheErratumMitigation",
+            "-version");
+
+        OutputAnalyzer output = new OutputAnalyzer(pb.start());
+
+        if (output.getExitValue() == 0) {
+            throw new RuntimeException("On affected CPU, setting UseSingleICacheInvalidation=true " +
+                "with NeoverseN1ICacheErratumMitigation=false should cause error");
+        }
+        output.shouldContain("Error");
+        System.out.println("JVM correctly rejected conflicting flags on affected CPU");
+    }
+
+    /**
+     * Check explicit NeoverseN1ICacheErratumMitigation=true enables UseSingleICacheInvalidation.
+     */
+    private static void testCase_ExplicitlyEnableErrataEnablesDeferred() throws Exception {
+        System.out.println("\nTest: Explicitly enable NeoverseN1ICacheErratumMitigation, check UseSingleICacheInvalidation");
+
+        ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder(
+            "-XX:+UnlockDiagnosticVMOptions",
+            "-XX:+NeoverseN1ICacheErratumMitigation",
+            "-XX:+PrintFlagsFinal",
+            "-version");
+
+        OutputAnalyzer output = new OutputAnalyzer(pb.start());
+        output.shouldHaveExitValue(0);
+
+        String output_str = output.getOutput();
+        boolean hasSingleEnabled = output_str.matches("(?s).*bool\\s+UseSingleICacheInvalidation\\s*=\\s*true.*");
+        boolean hasErrataEnabled = output_str.matches("(?s).*bool\\s+NeoverseN1ICacheErratumMitigation\\s*=\\s*true.*");
+
+        System.out.println("NeoverseN1ICacheErratumMitigation enabled: " + hasErrataEnabled);
+        System.out.println("UseSingleICacheInvalidation enabled: " + hasSingleEnabled);
+
+        if (!hasErrataEnabled) {
+            throw new RuntimeException("Failed to enable NeoverseN1ICacheErratumMitigation via command line");
+        }
+
+        if (!hasSingleEnabled) {
+            throw new RuntimeException("On affected CPU, enabling NeoverseN1ICacheErratumMitigation should also enable UseSingleICacheInvalidation");
+        }
+        System.out.println("Correctly synchronized on affected CPU");
+    }
+
+    /**
+     * Check JVM reports an error if UseSingleICacheInvalidation is set to false
+     * and NeoverseN1ICacheErratumMitigation is set to true on affected CPUs.
+     */
+    private static void testCase_ConflictingErrataWithoutDeferred() throws Exception {
+        System.out.println("\nTest: Try to set NeoverseN1ICacheErratumMitigation=true with UseSingleICacheInvalidation=false");
+
+        ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder(
+            "-XX:+UnlockDiagnosticVMOptions",
+            "-XX:-UseSingleICacheInvalidation",
+            "-XX:+NeoverseN1ICacheErratumMitigation",
+            "-XX:+PrintFlagsFinal",
+            "-version");
+
+        OutputAnalyzer output = new OutputAnalyzer(pb.start());
+
+        if (output.getExitValue() == 0) {
+            throw new RuntimeException("On affected CPU, setting NeoverseN1ICacheErratumMitigation=true with UseSingleICacheInvalidation=false should cause an error");
+        }
+        output.shouldContain("Error");
+        System.out.println("JVM correctly rejected conflicting flags on affected CPU");
+    }
+
+    /**
+     * Check setting NeoverseN1ICacheErratumMitigation=true on unaffected CPU causes an error.
+     */
+    private static void testCase_EnablingErrataOnUnaffectedCPU() throws Exception {
+        System.out.println("\nTest: Try to set NeoverseN1ICacheErratumMitigation=true on unaffected CPU");
+
+        ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder(
+            "-XX:+UnlockDiagnosticVMOptions",
+            "-XX:+NeoverseN1ICacheErratumMitigation",
+            "-version");
+
+        OutputAnalyzer output = new OutputAnalyzer(pb.start());
+
+        if (output.getExitValue() == 0) {
+            throw new RuntimeException("On unaffected CPU, setting NeoverseN1ICacheErratumMitigation=true should cause error");
+        }
+        output.shouldContain("Error");
+        System.out.println("JVM correctly rejected enabling errata flag on unaffected CPU");
+    }
+}
diff --git a/test/hotspot/jtreg/gc/TestDeferredICacheInvalidation.java b/test/hotspot/jtreg/gc/TestDeferredICacheInvalidation.java
new file mode 100644
index 00000000000..dc7e500ec9d
--- /dev/null
+++ b/test/hotspot/jtreg/gc/TestDeferredICacheInvalidation.java
@@ -0,0 +1,316 @@
+/*
+ * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package gc;
+
+/*
+ * @test id=parallel
+ * @bug 8370947
+ * @summary Check no assertion is triggered when UseSingleICacheInvalidation is enabled for ParallelGC
+ * @library /test/lib
+ * @requires vm.debug
+ * @requires vm.gc.Parallel
+ * @requires os.arch == "aarch64"
+ * @requires os.family == "linux"
+ * @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 -XX:+UseParallelGC -XX:-UseCodeCacheFlushing gc.TestDeferredICacheInvalidation youngGC C1
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseParallelGC -XX:-UseCodeCacheFlushing gc.TestDeferredICacheInvalidation fullGC C1
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseParallelGC -XX:-UseCodeCacheFlushing gc.TestDeferredICacheInvalidation youngGC C2
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseParallelGC -XX:-UseCodeCacheFlushing gc.TestDeferredICacheInvalidation fullGC C2
+ */
+
+/*
+ * @test id=g1
+ * @bug 8370947
+ * @summary Check no assertion is triggered when UseSingleICacheInvalidation is enabled for G1GC
+ * @library /test/lib
+ * @requires vm.debug
+ * @requires vm.gc.G1
+ * @requires os.arch == "aarch64"
+ * @requires os.family == "linux"
+ * @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 -XX:+UseG1GC -XX:-UseCodeCacheFlushing gc.TestDeferredICacheInvalidation youngGC C1
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseG1GC -XX:-UseCodeCacheFlushing gc.TestDeferredICacheInvalidation fullGC C1
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseG1GC -XX:-UseCodeCacheFlushing gc.TestDeferredICacheInvalidation youngGC C2
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseG1GC -XX:-UseCodeCacheFlushing gc.TestDeferredICacheInvalidation fullGC C2
+ */
+
+/*
+ * @test id=shenandoah
+ * @bug 8370947
+ * @summary Check no assertion is triggered when UseSingleICacheInvalidation is enabled for ShenandoahGC
+ * @library /test/lib
+ * @requires vm.debug
+ * @requires vm.gc.Shenandoah
+ * @requires os.arch == "aarch64"
+ * @requires os.family == "linux"
+ * @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 -XX:+UseShenandoahGC -XX:-UseCodeCacheFlushing gc.TestDeferredICacheInvalidation fullGC C1
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseShenandoahGC -XX:-UseCodeCacheFlushing gc.TestDeferredICacheInvalidation fullGC C2
+ */
+
+/*
+ * @test id=genshen
+ * @bug 8370947
+ * @summary Check no assertion is triggered when UseSingleICacheInvalidation is enabled for generational ShenandoahGC
+ * @library /test/lib
+ * @requires vm.debug
+ * @requires vm.gc.Shenandoah
+ * @requires os.arch == "aarch64"
+ * @requires os.family == "linux"
+ * @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 -XX:+UseShenandoahGC -XX:+UnlockExperimentalVMOptions -XX:ShenandoahGCMode=generational -XX:-UseCodeCacheFlushing gc.TestDeferredICacheInvalidation youngGC C1
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseShenandoahGC -XX:+UnlockExperimentalVMOptions -XX:ShenandoahGCMode=generational -XX:-UseCodeCacheFlushing gc.TestDeferredICacheInvalidation fullGC C1
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseShenandoahGC -XX:+UnlockExperimentalVMOptions -XX:ShenandoahGCMode=generational -XX:-UseCodeCacheFlushing gc.TestDeferredICacheInvalidation youngGC C2
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseShenandoahGC -XX:+UnlockExperimentalVMOptions -XX:ShenandoahGCMode=generational -XX:-UseCodeCacheFlushing gc.TestDeferredICacheInvalidation fullGC C2
+ */
+
+/*
+ * @test id=z
+ * @bug 8370947
+ * @summary Check no assertion is triggered when UseSingleICacheInvalidation is enabled for ZGC
+ * @library /test/lib
+ * @requires vm.debug
+ * @requires vm.gc.Z
+ * @requires os.arch == "aarch64"
+ * @requires os.family == "linux"
+ * @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 -XX:+UseZGC -XX:-UseCodeCacheFlushing gc.TestDeferredICacheInvalidation youngGC C1
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseZGC -XX:-UseCodeCacheFlushing gc.TestDeferredICacheInvalidation fullGC C1
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseZGC -XX:-UseCodeCacheFlushing gc.TestDeferredICacheInvalidation youngGC C2
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseZGC -XX:-UseCodeCacheFlushing gc.TestDeferredICacheInvalidation fullGC C2
+ */
+
+/*
+ * Nmethods have GC barriers and OOPs embedded into their code. GCs can patch nmethod's code
+ * which requires icache invalidation. Doing invalidation per instruction can be expensive.
+ * CPU can support hardware dcache and icache coherence. This would allow to defer cache
+ * invalidation.
+ *
+ * There are assertions for deferred cache invalidation. This test checks that all of them
+ * are passed.
+ */
+
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+import jdk.test.whitebox.WhiteBox;
+import jtreg.SkippedException;
+
+public class TestDeferredICacheInvalidation {
+
+    private static final WhiteBox WB = WhiteBox.getWhiteBox();
+
+    public static class A {
+        public String s1;
+        public String s2;
+        public String s3;
+        public String s4;
+        public String s5;
+        public String s6;
+        public String s7;
+        public String s8;
+        public String s9;
+    }
+
+    public static A a = new A();
+
+    private static int compLevel;
+
+    public static class B {
+        public static void test0() {
+        }
+
+        public static void test1() {
+            a.s1 = a.s1 + "1";
+        }
+
+        public static void test2() {
+            a.s1 = a.s1 + "1";
+            a.s2 = a.s2 + "2";
+        }
+
+        public static void test3() {
+            a.s1 = a.s1 + "1";
+            a.s2 = a.s2 + "2";
+            a.s3 = a.s3 + "3";
+        }
+
+        public static void test4() {
+            a.s1 = a.s1 + "1";
+            a.s2 = a.s2 + "2";
+            a.s3 = a.s3 + "3";
+            a.s4 = a.s4 + "4";
+        }
+
+        public static void test5() {
+            a.s1 = a.s1 + "1";
+            a.s2 = a.s2 + "2";
+            a.s3 = a.s3 + "3";
+            a.s4 = a.s4 + "4";
+            a.s5 = a.s5 + "5";
+        }
+
+        public static void test6() {
+            a.s1 = a.s1 + "1";
+            a.s2 = a.s2 + "2";
+            a.s3 = a.s3 + "3";
+            a.s4 = a.s4 + "4";
+            a.s5 = a.s5 + "5";
+            a.s6 = a.s6 + "6";
+        }
+
+        public static void test7() {
+            a.s1 = a.s1 + "1";
+            a.s2 = a.s2 + "2";
+            a.s3 = a.s3 + "3";
+            a.s4 = a.s4 + "4";
+            a.s5 = a.s5 + "5";
+            a.s6 = a.s6 + "6";
+            a.s7 = a.s7 + "7";
+        }
+
+        public static void test8() {
+            a.s1 = a.s1 + "1";
+            a.s2 = a.s2 + "2";
+            a.s3 = a.s3 + "3";
+            a.s4 = a.s4 + "4";
+            a.s5 = a.s5 + "5";
+            a.s6 = a.s6 + "6";
+            a.s7 = a.s7 + "7";
+            a.s8 = a.s8 + "8";
+        }
+
+        public static void test9() {
+            a.s1 = a.s1 + "1";
+            a.s2 = a.s2 + "2";
+            a.s3 = a.s3 + "3";
+            a.s4 = a.s4 + "4";
+            a.s5 = a.s5 + "5";
+            a.s6 = a.s6 + "6";
+            a.s7 = a.s7 + "7";
+            a.s8 = a.s8 + "8";
+            a.s9 = a.s9 + "9";
+        }
+    }
+
+    private static void compileMethods() throws Exception {
+        for (var m : B.class.getDeclaredMethods()) {
+            if (!m.getName().startsWith("test")) {
+                continue;
+            }
+            m.invoke(null);
+            WB.markMethodProfiled(m);
+            WB.enqueueMethodForCompilation(m, compLevel);
+            while (WB.isMethodQueuedForCompilation(m)) {
+                Thread.sleep(100);
+            }
+            if (WB.getMethodCompilationLevel(m) != compLevel) {
+                throw new IllegalStateException("Method " + m + " is not compiled at the compilation level: " + compLevel + ". Got: " + WB.getMethodCompilationLevel(m));
+            }
+        }
+    }
+
+    public static void youngGC() throws Exception {
+        a = null;
+        WB.youngGC();
+    }
+
+    public static void fullGC() throws Exception {
+        // Thread synchronization
+        final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
+        final ReentrantReadWriteLock.ReadLock readLock = rwLock.readLock();
+        final ReentrantReadWriteLock.WriteLock writeLock = rwLock.writeLock();
+        final AtomicBoolean running = new AtomicBoolean(true);
+
+        // Thread 1: GC thread that runs for 1 second with 100ms sleep intervals
+        Thread gcThread = new Thread(() -> {
+            final long startTime = System.currentTimeMillis();
+            final long duration = 1000;
+            try {
+                while (System.currentTimeMillis() - startTime < duration) {
+                    writeLock.lock();
+                    try {
+                        a = new A();
+                        WB.fullGC();
+                    } finally {
+                        writeLock.unlock();
+                    }
+                    Thread.sleep(100);
+                }
+            } catch (InterruptedException e) {
+                // Thread interrupted, exit
+            }
+            running.set(false);
+        });
+
+        // Threads 2-11: Test threads that execute test0() through test9()
+        Thread[] testThreads = new Thread[10];
+        for (int i = 0; i < 10; i++) {
+            final int testIdx = i;
+            testThreads[i] = new Thread(() -> {
+                try {
+                    var method = B.class.getDeclaredMethod("test" + testIdx);
+                    while (running.get()) {
+                        readLock.lock();
+                        try {
+                            method.invoke(null);
+                        } finally {
+                            readLock.unlock();
+                        }
+                    }
+                } catch (Exception e) {
+                    e.printStackTrace();
+                    System.exit(10);
+                }
+            });
+        }
+
+        // Start all threads
+        gcThread.start();
+        for (Thread t : testThreads) {
+            t.start();
+        }
+
+        // Wait for all threads to complete
+        gcThread.join();
+        for (Thread t : testThreads) {
+            t.join();
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        if (!Boolean.TRUE.equals(WB.getBooleanVMFlag("UseSingleICacheInvalidation"))) {
+            throw new SkippedException("Skip. Test requires UseSingleICacheInvalidation enabled.");
+        }
+        compLevel = (args[1].equals("C1")) ? 1 : 4;
+        compileMethods();
+        TestDeferredICacheInvalidation.class.getMethod(args[0]).invoke(null);
+    }
+}
diff --git a/test/micro/org/openjdk/bench/vm/gc/GCPatchingNmethodCost.java b/test/micro/org/openjdk/bench/vm/gc/GCPatchingNmethodCost.java
new file mode 100644
index 00000000000..53fa2378ead
--- /dev/null
+++ b/test/micro/org/openjdk/bench/vm/gc/GCPatchingNmethodCost.java
@@ -0,0 +1,206 @@
+/*
+ * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package org.openjdk.bench.vm.gc;
+
+import java.lang.reflect.Method;
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.BenchmarkMode;
+import org.openjdk.jmh.annotations.CompilerControl;
+import org.openjdk.jmh.annotations.Fork;
+import org.openjdk.jmh.annotations.Level;
+import org.openjdk.jmh.annotations.Mode;
+import org.openjdk.jmh.annotations.Measurement;
+import org.openjdk.jmh.annotations.OutputTimeUnit;
+import org.openjdk.jmh.annotations.Param;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.Setup;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.annotations.Warmup;
+
+import org.openjdk.bench.util.InMemoryJavaCompiler;
+
+import jdk.test.whitebox.WhiteBox;
+import jdk.test.whitebox.code.NMethod;
+
+/*
+ * Nmethods have OOPs and GC barriers emmedded into their code.
+ * GCs patch them which causes invalidation of nmethods' code.
+ *
+ * This benchmark can be used to estimate the cost of patching
+ * OOPs and GC barriers.
+ *
+ * We create 5000 nmethods which access fields of a class.
+ * We measure the time of different GC cycles to see
+ * the impact of patching nmethods.
+ *
+ * The benchmark parameters are method count and accessed field count.
+ */
+
+@BenchmarkMode(Mode.SingleShotTime)
+@OutputTimeUnit(TimeUnit.MILLISECONDS)
+@State(Scope.Benchmark)
+@Fork(value = 1, jvmArgsAppend = {
+    "-XX:+UnlockDiagnosticVMOptions",
+    "-XX:+UnlockExperimentalVMOptions",
+    "-XX:+WhiteBoxAPI",
+    "-Xbootclasspath/a:lib-test/wb.jar",
+    "-XX:-UseCodeCacheFlushing"
+})
+@Warmup(iterations = 5)
+@Measurement(iterations = 5)
+public class GCPatchingNmethodCost {
+
+    private static final int COMP_LEVEL = 1;
+    private static final String FIELD_USER = "FieldUser";
+
+    public static Fields fields;
+
+    private static TestMethod[] methods = {};
+    private static byte[] BYTE_CODE;
+    private static WhiteBox WB;
+
+    @Param({"5000"})
+    public int methodCount;
+
+    @Param({"0", "2", "4", "8"})
+    public int accessedFieldCount;
+
+    public static class Fields {
+        public String f1;
+        public String f2;
+        public String f3;
+        public String f4;
+        public String f5;
+        public String f6;
+        public String f7;
+        public String f8;
+        public String f9;
+    }
+
+    private static final class TestMethod {
+        private final Method method;
+
+        public TestMethod(Method method) throws Exception {
+            this.method = method;
+            WB.testSetDontInlineMethod(method, true);
+        }
+
+        public void profile() throws Exception {
+            method.invoke(null);
+            WB.markMethodProfiled(method);
+        }
+
+        public void invoke() throws Exception {
+            method.invoke(null);
+        }
+
+        public void compile() throws Exception {
+            WB.enqueueMethodForCompilation(method, COMP_LEVEL);
+            while (WB.isMethodQueuedForCompilation(method)) {
+                Thread.onSpinWait();
+            }
+            if (WB.getMethodCompilationLevel(method) != COMP_LEVEL) {
+                throw new IllegalStateException("Method " + method + " is not compiled at the compilation level: " + COMP_LEVEL + ". Got: " + WB.getMethodCompilationLevel(method));
+            }
+        }
+
+        public NMethod getNMethod() {
+            return NMethod.get(method, false);
+        }
+    }
+
+    private static ClassLoader createClassLoader() {
+        return new ClassLoader() {
+            @Override
+            public Class loadClass(String name) throws ClassNotFoundException {
+                if (!name.equals(FIELD_USER)) {
+                    return super.loadClass(name);
+                }
+
+                return defineClass(name, BYTE_CODE, 0, BYTE_CODE.length);
+            }
+        };
+    }
+
+    private static void createTestMethods(int accessedFieldCount, int count) throws Exception {
+        String javaCode = "public class " + FIELD_USER + " {";
+        String field = GCPatchingNmethodCost.class.getName() + ".fields.f";
+        javaCode += "public static void accessFields() {";
+        for (int i = 1; i <= accessedFieldCount; i++) {
+            javaCode += field + i + "= " + field + i + " + " + i + ";";
+        }
+        javaCode += "}}";
+
+        BYTE_CODE = InMemoryJavaCompiler.compile(FIELD_USER, javaCode);
+
+        fields = new Fields();
+
+        methods = new TestMethod[count];
+        for (int i = 0; i < count; i++) {
+            var cl = createClassLoader().loadClass(FIELD_USER);
+            Method method = cl.getMethod("accessFields");
+            methods[i] = new TestMethod(method);
+            methods[i].profile();
+            methods[i].compile();
+        }
+    }
+
+    private static void initWhiteBox() {
+        WB = WhiteBox.getWhiteBox();
+    }
+
+    @Setup(Level.Trial)
+    public void setupCodeCache() throws Exception {
+        initWhiteBox();
+        createTestMethods(accessedFieldCount, methodCount);
+        System.gc();
+    }
+
+    @Setup(Level.Iteration)
+    public void setupIteration() {
+        fields = new Fields();
+    }
+
+    @Benchmark
+    public void youngGC() throws Exception {
+        fields = null;
+        WB.youngGC();
+    }
+
+    @Benchmark
+    public void fullGC() throws Exception {
+        fields = null;
+        WB.fullGC();
+    }
+
+    @Benchmark
+    public void systemGC() throws Exception {
+        fields = null;
+        System.gc();
+    }
+}

From c267c84ff62e3ed4991a789eaf54c51c41eff12b Mon Sep 17 00:00:00 2001
From: Anton Seoane Ampudia 
Date: Tue, 7 Apr 2026 11:27:18 +0000
Subject: [PATCH 191/359] 8358766: Improve detection of changes to print IGVN
 steps

Reviewed-by: qamai, bmaillard, krk
---
 src/hotspot/share/opto/phaseX.cpp | 8 +++++---
 src/hotspot/share/opto/phaseX.hpp | 2 +-
 2 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/src/hotspot/share/opto/phaseX.cpp b/src/hotspot/share/opto/phaseX.cpp
index 06963eff4cf..0fecc14f31a 100644
--- a/src/hotspot/share/opto/phaseX.cpp
+++ b/src/hotspot/share/opto/phaseX.cpp
@@ -909,9 +909,9 @@ void PhaseIterGVN::verify_step(Node* n) {
   }
 }
 
-void PhaseIterGVN::trace_PhaseIterGVN(Node* n, Node* nn, const Type* oldtype) {
+void PhaseIterGVN::trace_PhaseIterGVN(Node* n, Node* nn, const Type* oldtype, bool progress) {
   const Type* newtype = type_or_null(n);
-  if (nn != n || oldtype != newtype) {
+  if (progress) {
     C->print_method(PHASE_AFTER_ITER_GVN_STEP, 5, n);
   }
   if (TraceIterativeGVN) {
@@ -1092,7 +1092,9 @@ bool PhaseIterGVN::drain_worklist() {
       NOT_PRODUCT(const Type* oldtype = type_or_null(n));
       // Do the transformation
       DEBUG_ONLY(int live_nodes_before = C->live_nodes();)
+      NOT_PRODUCT(uint progress_before = made_progress();)
       Node* nn = transform_old(n);
+      NOT_PRODUCT(bool progress = (made_progress() - progress_before) > 0;)
       DEBUG_ONLY(int live_nodes_after = C->live_nodes();)
       // Ensure we did not increase the live node count with more than
       // max_live_nodes_increase_per_iteration during the call to transform_old.
@@ -1101,7 +1103,7 @@ bool PhaseIterGVN::drain_worklist() {
              "excessive live node increase in single iteration of IGVN: %d "
              "(should be at most %d)",
              increase, max_live_nodes_increase_per_iteration);
-      NOT_PRODUCT(trace_PhaseIterGVN(n, nn, oldtype);)
+      NOT_PRODUCT(trace_PhaseIterGVN(n, nn, oldtype, progress);)
     } else if (!n->is_top()) {
       remove_dead_node(n, NodeOrigin::Graph);
     }
diff --git a/src/hotspot/share/opto/phaseX.hpp b/src/hotspot/share/opto/phaseX.hpp
index cef273ff3df..014d16f92f6 100644
--- a/src/hotspot/share/opto/phaseX.hpp
+++ b/src/hotspot/share/opto/phaseX.hpp
@@ -548,7 +548,7 @@ public:
 #endif
 
 #ifndef PRODUCT
-  void trace_PhaseIterGVN(Node* n, Node* nn, const Type* old_type);
+  void trace_PhaseIterGVN(Node* n, Node* nn, const Type* old_type, bool progress);
   void init_verifyPhaseIterGVN();
   void verify_PhaseIterGVN(bool deep_revisit_converged);
 #endif

From 69c4a211ee0a1a1701f6aa61c95e2ce3f2bd8a6d Mon Sep 17 00:00:00 2001
From: Stefan Karlsson 
Date: Tue, 7 Apr 2026 11:30:23 +0000
Subject: [PATCH 192/359] 8381561: G1: Cleanup patch in preparation for eager
 reclamation of flat arrays

Reviewed-by: tschatzl, ayang, iwalulya
---
 src/hotspot/share/gc/g1/g1ConcurrentMark.cpp  | 18 +++-----
 src/hotspot/share/gc/g1/g1ConcurrentMark.hpp  |  7 +--
 .../share/gc/g1/g1ConcurrentMark.inline.hpp   | 44 +++++++++----------
 3 files changed, 31 insertions(+), 38 deletions(-)

diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp
index 84a0b7588ef..4c646c82b8a 100644
--- a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp
+++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp
@@ -2341,20 +2341,16 @@ void G1CMTask::drain_local_queue(bool partially) {
   }
 }
 
-size_t G1CMTask::start_partial_array_processing(oop obj) {
-  assert(should_be_sliced(obj), "Must be an array object %d and large %zu", obj->is_objArray(), obj->size());
-
-  objArrayOop obj_array = objArrayOop(obj);
-  size_t array_length = obj_array->length();
-
-  size_t initial_chunk_size = _partial_array_splitter.start(_task_queue, obj_array, nullptr, array_length);
+size_t G1CMTask::start_partial_array_processing(objArrayOop obj) {
+  assert(obj->length() >= (int)ObjArrayMarkingStride, "Must be a large array object %d", obj->length());
 
   // Mark objArray klass metadata
-  if (_cm_oop_closure->do_metadata()) {
-    _cm_oop_closure->do_klass(obj_array->klass());
-  }
+  process_klass(obj->klass());
 
-  process_array_chunk(obj_array, 0, initial_chunk_size);
+  size_t array_length = obj->length();
+  size_t initial_chunk_size = _partial_array_splitter.start(_task_queue, obj, nullptr, array_length);
+
+  process_array_chunk(obj, 0, initial_chunk_size);
 
   // Include object header size
   return objArrayOopDesc::object_size(checked_cast(initial_chunk_size));
diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp
index 7aa93947204..f9287f673d2 100644
--- a/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp
+++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp
@@ -844,12 +844,10 @@ private:
   // mark bitmap scan, and so needs to be pushed onto the mark stack.
   bool is_below_finger(oop obj, HeapWord* global_finger) const;
 
-  template void process_grey_task_entry(G1TaskQueueEntry task_entry, bool stolen);
-
   static bool should_be_sliced(oop obj);
   // Start processing the given objArrayOop by first pushing its continuations and
   // then scanning the first chunk including the header.
-  size_t start_partial_array_processing(oop obj);
+  size_t start_partial_array_processing(objArrayOop obj);
   // Process the given continuation. Returns the number of words scanned.
   size_t process_partial_array(const G1TaskQueueEntry& task, bool stolen);
   // Apply the closure to the given range of elements in the objArray.
@@ -918,6 +916,9 @@ public:
   template 
   inline bool deal_with_reference(T* p);
 
+  // Scan the klass and visit its children.
+  inline void process_klass(Klass* klass);
+
   // Scans an object and visits its children.
   inline void process_entry(G1TaskQueueEntry task_entry, bool stolen);
 
diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.inline.hpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.inline.hpp
index 21167d5cae9..094f4dca994 100644
--- a/src/hotspot/share/gc/g1/g1ConcurrentMark.inline.hpp
+++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.inline.hpp
@@ -106,9 +106,27 @@ inline void G1CMMarkStack::iterate(Fn fn) const {
 }
 #endif
 
+inline void G1CMTask::process_klass(Klass* klass) {
+  _cm_oop_closure->do_klass(klass);
+}
+
 // It scans an object and visits its children.
 inline void G1CMTask::process_entry(G1TaskQueueEntry task_entry, bool stolen) {
-  process_grey_task_entry(task_entry, stolen);
+  assert(task_entry.is_partial_array_state() || _mark_bitmap->is_marked(cast_from_oop(task_entry.to_oop())),
+         "Any stolen object should be a slice or marked");
+
+  if (task_entry.is_partial_array_state()) {
+    _words_scanned += process_partial_array(task_entry, stolen);
+  } else {
+    oop obj = task_entry.to_oop();
+    if (should_be_sliced(obj)) {
+      _words_scanned += start_partial_array_processing(objArrayOop(obj));
+    } else {
+      _words_scanned += obj->oop_iterate_size(_cm_oop_closure);
+    }
+  }
+
+  check_limits();
 }
 
 inline void G1CMTask::push(G1TaskQueueEntry task_entry) {
@@ -160,27 +178,6 @@ inline bool G1CMTask::is_below_finger(oop obj, HeapWord* global_finger) const {
   return objAddr < global_finger;
 }
 
-template
-inline void G1CMTask::process_grey_task_entry(G1TaskQueueEntry task_entry, bool stolen) {
-  assert(scan || (!task_entry.is_partial_array_state() && task_entry.to_oop()->is_typeArray()), "Skipping scan of grey non-typeArray");
-  assert(task_entry.is_partial_array_state() || _mark_bitmap->is_marked(cast_from_oop(task_entry.to_oop())),
-         "Any stolen object should be a slice or marked");
-
-  if (scan) {
-    if (task_entry.is_partial_array_state()) {
-      _words_scanned += process_partial_array(task_entry, stolen);
-    } else {
-      oop obj = task_entry.to_oop();
-      if (should_be_sliced(obj)) {
-        _words_scanned += start_partial_array_processing(obj);
-      } else {
-        _words_scanned += obj->oop_iterate_size(_cm_oop_closure);
-      }
-    }
-  }
-  check_limits();
-}
-
 inline bool G1CMTask::should_be_sliced(oop obj) {
   return obj->is_objArray() && ((objArrayOop)obj)->length() >= (int)ObjArrayMarkingStride;
 }
@@ -272,7 +269,6 @@ inline bool G1CMTask::make_reference_grey(oop obj) {
   // be pushed on the stack. So, some duplicate work, but no
   // correctness problems.
   if (is_below_finger(obj, global_finger)) {
-    G1TaskQueueEntry entry(obj);
     if (obj->is_typeArray()) {
       // Immediately process arrays of primitive types, rather
       // than pushing on the mark stack.  This keeps us from
@@ -284,8 +280,8 @@ inline bool G1CMTask::make_reference_grey(oop obj) {
       // by only doing a bookkeeping update and avoiding the
       // actual scan of the object - a typeArray contains no
       // references, and the metadata is built-in.
-      process_grey_task_entry(entry, false /* stolen */);
     } else {
+      G1TaskQueueEntry entry(obj);
       push(entry);
     }
   }

From 547ebe7236fee5b85888a808922e33c03ee3df23 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Daniel=20Jeli=C5=84ski?= 
Date: Tue, 7 Apr 2026 11:48:01 +0000
Subject: [PATCH 193/359] 8381316: HttpClient / Http3: poor exception messages
 on SSL handshake errors

Reviewed-by: dfuchs
---
 .../sun/security/ssl/QuicTLSEngineImpl.java   |  4 +-
 .../net/http/quic/TerminationCause.java       |  5 +-
 .../net/httpclient/InvalidSSLContextTest.java | 62 +++++++++++--------
 3 files changed, 42 insertions(+), 29 deletions(-)

diff --git a/src/java.base/share/classes/sun/security/ssl/QuicTLSEngineImpl.java b/src/java.base/share/classes/sun/security/ssl/QuicTLSEngineImpl.java
index 74975fc1e5b..b5f1eff179c 100644
--- a/src/java.base/share/classes/sun/security/ssl/QuicTLSEngineImpl.java
+++ b/src/java.base/share/classes/sun/security/ssl/QuicTLSEngineImpl.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -660,7 +660,7 @@ public final class QuicTLSEngineImpl implements QuicTLSEngine, SSLTransport {
             }
             Alert alert = ((QuicEngineOutputRecord)
                     conContext.outputRecord).getAlert();
-            throw new QuicTransportException(alert.description, keySpace, 0,
+            throw new QuicTransportException(e.getMessage(), keySpace, 0,
                     BASE_CRYPTO_ERROR + alert.id, e);
         } catch (IOException e) {
             throw new RuntimeException(e);
diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/quic/TerminationCause.java b/src/java.net.http/share/classes/jdk/internal/net/http/quic/TerminationCause.java
index 9e441cf7873..df8c229a000 100644
--- a/src/java.net.http/share/classes/jdk/internal/net/http/quic/TerminationCause.java
+++ b/src/java.net.http/share/classes/jdk/internal/net/http/quic/TerminationCause.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -128,6 +128,9 @@ public abstract sealed class TerminationCause {
                     ? new IOException("connection terminated")
                     : new IOException(fallbackExceptionMsg);
         } else if (original instanceof QuicTransportException qte) {
+            if (qte.getCause() instanceof IOException ioe) {
+                return ioe;
+            }
             return new IOException(qte.getMessage());
         } else if (original instanceof IOException ioe) {
             return ioe;
diff --git a/test/jdk/java/net/httpclient/InvalidSSLContextTest.java b/test/jdk/java/net/httpclient/InvalidSSLContextTest.java
index 0027a7956d5..bbbd1e486ca 100644
--- a/test/jdk/java/net/httpclient/InvalidSSLContextTest.java
+++ b/test/jdk/java/net/httpclient/InvalidSSLContextTest.java
@@ -23,10 +23,12 @@
 
 /*
  * @test
+ * @bug 8381316
  * @summary Test to ensure the HTTP client throws an appropriate SSL exception
  *          when SSL context is not valid.
- * @library /test/lib
+ * @library /test/lib /test/jdk/java/net/httpclient/lib
  * @build jdk.test.lib.net.SimpleSSLContext
+ *        jdk.httpclient.test.lib.common.HttpServerAdapters
  * @run junit/othervm -Djdk.internal.httpclient.debug=true InvalidSSLContextTest
  */
 
@@ -44,14 +46,18 @@ import javax.net.ssl.SSLServerSocket;
 import javax.net.ssl.SSLSocket;
 import java.net.http.HttpClient;
 import java.net.http.HttpClient.Version;
+import java.net.http.HttpOption;
 import java.net.http.HttpRequest;
 import java.net.http.HttpResponse;
 import java.net.http.HttpResponse.BodyHandlers;
+
+import jdk.httpclient.test.lib.common.HttpServerAdapters.HttpTestServer;
 import jdk.test.lib.net.SimpleSSLContext;
 
 import static java.net.http.HttpClient.Builder.NO_PROXY;
-import static java.net.http.HttpClient.Version.HTTP_1_1;
-import static java.net.http.HttpClient.Version.HTTP_2;
+import static java.net.http.HttpClient.Version.*;
+import static java.net.http.HttpOption.Http3DiscoveryMode.HTTP_3_URI_ONLY;
+import static jdk.httpclient.test.lib.common.HttpServerAdapters.createClientBuilderForH3;
 
 import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.Assertions;
@@ -64,25 +70,29 @@ public class InvalidSSLContextTest {
     private static final SSLContext sslContext = SimpleSSLContext.findSSLContext();
     static volatile SSLServerSocket sslServerSocket;
     static volatile String uri;
+    private static HttpTestServer h3Server;
+    private static String h3Uri;
 
     public static Object[][] versions() {
         return new Object[][]{
-                { HTTP_1_1 },
-                { HTTP_2   }
+                { HTTP_1_1, uri },
+                { HTTP_2  , uri },
+                { HTTP_3  , h3Uri }
         };
     }
 
     @ParameterizedTest
     @MethodSource("versions")
-    public void testSync(Version version) throws Exception {
+    public void testSync(Version version, String uri) throws Exception {
         // client-side uses a different context to that of the server-side
-        HttpClient client = HttpClient.newBuilder()
+        HttpClient client = createClientBuilderForH3()
                 .proxy(NO_PROXY)
                 .sslContext(SSLContext.getDefault())
                 .build();
 
         HttpRequest request = HttpRequest.newBuilder(URI.create(uri))
                 .version(version)
+                .setOption(HttpOption.H3_DISCOVERY, HTTP_3_URI_ONLY)
                 .build();
 
         try {
@@ -90,21 +100,22 @@ public class InvalidSSLContextTest {
             Assertions.fail("UNEXPECTED response" + response);
         } catch (IOException ex) {
             System.out.println("Caught expected: " + ex);
-            assertExceptionOrCause(SSLException.class, ex);
+            assertException(SSLException.class, ex);
         }
     }
 
     @ParameterizedTest
     @MethodSource("versions")
-    public void testAsync(Version version) throws Exception {
+    public void testAsync(Version version, String uri) throws Exception {
         // client-side uses a different context to that of the server-side
-        HttpClient client = HttpClient.newBuilder()
+        HttpClient client = createClientBuilderForH3()
                 .proxy(NO_PROXY)
                 .sslContext(SSLContext.getDefault())
                 .build();
 
         HttpRequest request = HttpRequest.newBuilder(URI.create(uri))
                 .version(version)
+                .setOption(HttpOption.H3_DISCOVERY, HTTP_3_URI_ONLY)
                 .build();
 
         assertExceptionally(SSLException.class,
@@ -123,26 +134,20 @@ public class InvalidSSLContextTest {
                 if (cause == null) {
                     Assertions.fail("Unexpected null cause: " + error);
                 }
-                assertExceptionOrCause(clazz, cause);
+                System.out.println("Caught expected: " + cause);
+                assertException(clazz, cause);
             } else {
-                assertExceptionOrCause(clazz, error);
+                System.out.println("Caught expected: " + error);
+                assertException(clazz, error);
             }
             return null;
         }).join();
     }
 
-    static void assertExceptionOrCause(Class clazz, Throwable t) {
-        if (t == null) {
-            Assertions.fail("Expected " + clazz + ", caught nothing");
-        }
-        final Throwable original = t;
-        do {
-            if (clazz.isInstance(t)) {
-                return; // found
-            }
-        } while ((t = t.getCause()) != null);
-        original.printStackTrace(System.out);
-        Assertions.fail("Expected " + clazz + "in " + original);
+    static void assertException(Class clazz, Throwable t) {
+        Assertions.assertInstanceOf(clazz, t);
+        Assertions.assertTrue(t.getMessage().contains("unable to find valid certification path to requested target"),
+                "Unexpected exception message: " + t);
     }
 
     @BeforeAll
@@ -159,7 +164,7 @@ public class InvalidSSLContextTest {
         Thread t = new Thread("SSL-Server-Side") {
             @Override
             public void run() {
-                while (true) {
+                while (!sslServerSocket.isClosed()) {
                     try {
                         SSLSocket s = (SSLSocket) sslServerSocket.accept();
                         System.out.println("SERVER: accepted: " + s);
@@ -177,7 +182,6 @@ public class InvalidSSLContextTest {
                         if (!sslServerSocket.isClosed()) {
                             throw new UncheckedIOException(e);
                         }
-                        break;
                     } catch (InterruptedException ie) {
                         throw new RuntimeException(ie);
                     }
@@ -185,10 +189,16 @@ public class InvalidSSLContextTest {
             }
         };
         t.start();
+
+        h3Server = HttpTestServer.create(HTTP_3_URI_ONLY, sslContext);
+        h3Server.addHandler((exchange) -> exchange.sendResponseHeaders(200, 0), "/hello");
+        h3Server.start();
+        h3Uri = "https://" + h3Server.serverAuthority() + "/hello";
     }
 
     @AfterAll
     public static void teardown() throws Exception {
+        h3Server.stop();
         sslServerSocket.close();
     }
 }

From 34ac926d9ccc3256112340355ea587a0f5d63a1c Mon Sep 17 00:00:00 2001
From: Daisuke Yamazaki 
Date: Tue, 7 Apr 2026 12:23:03 +0000
Subject: [PATCH 194/359] 8378157: Section hyperlink in doc/testing.md refers
 to building.html instead of building.md

Reviewed-by: erikj, iris, ayang
---
 doc/testing.html | 7 ++++---
 doc/testing.md   | 4 ++--
 2 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/doc/testing.html b/doc/testing.html
index 195153c8612..c8d0b928bb0 100644
--- a/doc/testing.html
+++ b/doc/testing.html
@@ -284,9 +284,10 @@ possible, or if you want to use a fully qualified test descriptor, add
 

Gtest

Note: To be able to run the Gtest suite, you need to configure your build to be able to find a proper version of the gtest -source. For details, see the section "Running Tests" in the build -documentation.

+source. For details, see the section "Running Tests" in the +build documentation (html, markdown).

Since the Hotspot Gtest suite is so quick, the default is to run all tests. This is specified by just gtest, or as a fully qualified test descriptor gtest:all.

diff --git a/doc/testing.md b/doc/testing.md index d0e54aab02b..5f70f2796ad 100644 --- a/doc/testing.md +++ b/doc/testing.md @@ -198,8 +198,8 @@ use a fully qualified test descriptor, add `jtreg:`, e.g. **Note:** To be able to run the Gtest suite, you need to configure your build to be able to find a proper version of the gtest source. For details, see the -section ["Running Tests" in the build -documentation](building.html#running-tests). +section **"Running Tests" in the build +documentation** ([html](building.html#running-tests), [markdown](building.md#running-tests)). Since the Hotspot Gtest suite is so quick, the default is to run all tests. This is specified by just `gtest`, or as a fully qualified test descriptor From b297f59dc9f8eca19d54b5966f8ced6c9b278538 Mon Sep 17 00:00:00 2001 From: Vladimir Kozlov Date: Tue, 7 Apr 2026 14:01:55 +0000 Subject: [PATCH 195/359] 8381659: Determine actual jump instruction when AOT and JITed code are used Reviewed-by: dlong, iveresov --- src/hotspot/cpu/aarch64/compiledIC_aarch64.cpp | 13 +++++++++---- src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp | 5 ++++- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/hotspot/cpu/aarch64/compiledIC_aarch64.cpp b/src/hotspot/cpu/aarch64/compiledIC_aarch64.cpp index 6fe3315014b..640cd495383 100644 --- a/src/hotspot/cpu/aarch64/compiledIC_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/compiledIC_aarch64.cpp @@ -89,16 +89,21 @@ void CompiledDirectCall::set_to_interpreted(const methodHandle& callee, address NativeMovConstReg* method_holder = nativeMovConstReg_at(stub + NativeInstruction::instruction_size); + // In AOT "production" run we have mixture of AOTed and normal JITed code. + // Static call stub in AOTed nmethod always has far jump. + // Normal JITed nmethod may have short or far jump depending on distance. + // Determine actual jump instruction we have in code. + address next_instr = method_holder->next_instruction_address(); + bool is_general_jump = nativeInstruction_at(next_instr)->is_general_jump(); + #ifdef ASSERT - NativeJump* jump = MacroAssembler::codestub_branch_needs_far_jump() - ? nativeGeneralJump_at(method_holder->next_instruction_address()) - : nativeJump_at(method_holder->next_instruction_address()); + NativeJump* jump = is_general_jump ? nativeGeneralJump_at(next_instr) : nativeJump_at(next_instr); verify_mt_safe(callee, entry, method_holder, jump); #endif // Update stub. method_holder->set_data((intptr_t)callee()); - MacroAssembler::pd_patch_instruction(method_holder->next_instruction_address(), entry); + MacroAssembler::pd_patch_instruction(next_instr, entry); ICache::invalidate_range(stub, to_interp_stub_size()); // Update jump to call. set_destination_mt_safe(stub); diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp index ebbc35ce20a..b5e15402941 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp @@ -952,7 +952,10 @@ void MacroAssembler::emit_static_call_stub() { } int MacroAssembler::static_call_stub_size() { - if (!codestub_branch_needs_far_jump()) { + // During AOT production run AOT and JIT compiled code + // are used at the same time. We need this size + // to be the same for both types of code. + if (!codestub_branch_needs_far_jump() && !AOTCodeCache::is_on_for_use()) { // isb; movk; movz; movz; b return 5 * NativeInstruction::instruction_size; } From da16b409c3784d1ff5cd3076c1aebfe7c76664cc Mon Sep 17 00:00:00 2001 From: Vladimir Kozlov Date: Tue, 7 Apr 2026 14:18:01 +0000 Subject: [PATCH 196/359] 8381656: Take into account trampoline stub size and its relocations on Aarch64 Reviewed-by: dlong --- src/hotspot/cpu/aarch64/aarch64.ad | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad index 05b2514a456..53fa4e3066c 100644 --- a/src/hotspot/cpu/aarch64/aarch64.ad +++ b/src/hotspot/cpu/aarch64/aarch64.ad @@ -1182,12 +1182,12 @@ class CallStubImpl { public: // Size of call trampoline stub. static uint size_call_trampoline() { - return 0; // no call trampolines on this platform + return MacroAssembler::max_trampoline_stub_size(); } // number of relocations needed by a call trampoline stub static uint reloc_call_trampoline() { - return 0; // no call trampolines on this platform + return 5; // metadata; call dest; trampoline address; trampoline destination; trampoline_owner_metadata } }; From 67c6990f9aaa54246c2e816e1ff1f0af15c71486 Mon Sep 17 00:00:00 2001 From: Daisuke Yamazaki Date: Tue, 7 Apr 2026 16:30:17 +0000 Subject: [PATCH 197/359] 8344212: Bring back @see GraphicsConfiguration to MouseInfo.getPointerInfo() Reviewed-by: aivanov, dmarkov, serb --- src/java.desktop/share/classes/java/awt/MouseInfo.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/java.desktop/share/classes/java/awt/MouseInfo.java b/src/java.desktop/share/classes/java/awt/MouseInfo.java index 6b913adf06e..7a30243b06c 100644 --- a/src/java.desktop/share/classes/java/awt/MouseInfo.java +++ b/src/java.desktop/share/classes/java/awt/MouseInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +58,7 @@ public class MouseInfo { * * @throws HeadlessException if GraphicsEnvironment.isHeadless() returns true * @return location of the mouse pointer + * @see GraphicsConfiguration * @since 1.5 */ public static PointerInfo getPointerInfo() throws HeadlessException { From f6baab704e868386c66b79072ae05d2b24bf8632 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Wed, 8 Apr 2026 06:23:42 +0000 Subject: [PATCH 198/359] 8379550: Bad bytecode offset after JDK-8371155 Reviewed-by: vromero, abimpoudis --- .../sun/tools/javac/code/TypeAnnotations.java | 8 + .../TypeAnnotationsOnVariables.java | 245 ++++++++++++++++-- 2 files changed, 237 insertions(+), 16 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java index 0393ed79897..452d15ed219 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java @@ -154,6 +154,14 @@ public class TypeAnnotations { } else { pos.push(env.enclMethod); } + Env env1 = env; + while (env1 != null && !env1.tree.hasTag(Tag.CLASSDEF)) { + if (env1.tree instanceof JCLambda l) { + pos.currentLambda = l; + break; + } + env1 = env1.next; + } pos.scan(tree); } finally { log.useSource(oldSource); diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/TypeAnnotationsOnVariables.java b/test/langtools/tools/javac/annotations/typeAnnotations/TypeAnnotationsOnVariables.java index 2e68e18f8f7..e5a1e5650d3 100644 --- a/test/langtools/tools/javac/annotations/typeAnnotations/TypeAnnotationsOnVariables.java +++ b/test/langtools/tools/javac/annotations/typeAnnotations/TypeAnnotationsOnVariables.java @@ -23,15 +23,16 @@ /* * @test - * @bug 8371155 + * @bug 8371155 8379550 * @summary Verify type annotations on local-like variables are propagated to * their types at an appropriate time. * @library /tools/lib * @modules * jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.main + * jdk.jdeps/com.sun.tools.javap * @build toolbox.ToolBox toolbox.JavacTask - * @run main TypeAnnotationsOnVariables + * @run junit TypeAnnotationsOnVariables */ import com.sun.source.tree.LambdaExpressionTree; @@ -41,31 +42,44 @@ import com.sun.source.util.TaskEvent; import com.sun.source.util.TaskListener; import com.sun.source.util.TreePathScanner; import com.sun.source.util.Trees; +import java.io.IOException; +import java.lang.classfile.Attributes; +import java.lang.classfile.ClassFile; +import java.lang.classfile.ClassModel; +import java.lang.classfile.MethodModel; +import java.lang.classfile.attribute.RuntimeInvisibleTypeAnnotationsAttribute; +import java.lang.classfile.constantpool.ConstantPool; +import java.lang.classfile.constantpool.Utf8Entry; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import java.util.stream.Collectors; import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; import javax.lang.model.type.UnionType; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInfo; import toolbox.JavacTask; +import toolbox.JavapTask; +import toolbox.Task; import toolbox.ToolBox; public class TypeAnnotationsOnVariables { - public static void main(String... args) throws Exception { - new TypeAnnotationsOnVariables().run(); - } + private static final Pattern CP_REFERENCE = Pattern.compile("#([1-9][0-9]*)"); + final ToolBox tb = new ToolBox(); + Path base; - ToolBox tb = new ToolBox(); - - void run() throws Exception { - typeAnnotationInConstantExpressionFieldInit(Paths.get(".")); - } - - void typeAnnotationInConstantExpressionFieldInit(Path base) throws Exception { + @Test + void typeAnnotationInConstantExpressionFieldInit() throws Exception { Path src = base.resolve("src"); Path classes = base.resolve("classes"); tb.writeJavaFiles(src, @@ -203,9 +217,208 @@ public class TypeAnnotationsOnVariables { } static String treeToString(Tree tree) { - if (tree.toString().contains("\n")) { - System.err.println("!!!"); - } return String.valueOf(tree).replaceAll("\\R", " "); } + + @Test + void properPathForLocalVarsInLambdas() throws Exception { + Path src = base.resolve("src"); + Path classes = base.resolve("classes"); + tb.writeJavaFiles(src, + """ + import java.lang.annotation.ElementType; + import java.lang.annotation.Target; + import java.util.function.Supplier; + + class Test { + @Target(ElementType.TYPE_USE) + @interface TypeAnno { } + + void o() { + Runnable r = () -> { + @TypeAnno long test1 = 0; + while (true) { + @TypeAnno long test2 = 0; + System.err.println(test2); + try (@TypeAnno AutoCloseable ac = null) { + System.err.println(ac); + } catch (@TypeAnno Exception e1) { + System.err.println(e1); + } + try { + "".length(); + } catch (@TypeAnno final Exception e2) { + System.err.println(e2); + } + try { + "".length(); + } catch (@TypeAnno IllegalStateException | @TypeAnno NullPointerException | IllegalArgumentException e3) { + System.err.println(e3); + } + Runnable r2 = () -> { + @TypeAnno long test3 = 0; + while (true) { + @TypeAnno long test4 = 0; + System.err.println(test4); + } + }; + Object o = null; + if (o instanceof @TypeAnno String s) { + System.err.println(s); + } + } + }; + } + void lambdaInClass() { + class C { + Runnable r = () -> { + @TypeAnno long test1 = 0; + System.err.println(test1); + }; + } + } + void classInLambda() { + Runnable r = () -> { + class C { + void method() { + @TypeAnno long test1 = 0; + System.err.println(test1); + } + } + }; + } + } + """); + Files.createDirectories(classes); + new JavacTask(tb) + .options("-d", classes.toString()) + .files(tb.findJavaFiles(src)) + .run() + .writeAll(); + + Path testClass = classes.resolve("Test.class"); + TestClassDesc testClassDesc = TestClassDesc.create(testClass); + MethodModel oMethod = singletonValue(testClassDesc.name2Method().get("o")); + var oTypeAnnos = getAnnotations(oMethod); + assertFalse(oTypeAnnos.isPresent(), () -> oTypeAnnos.toString()); + + checkTypeAnnotations(testClassDesc, + "lambda$o$0", + " 0: LTest$TypeAnno;(): LOCAL_VARIABLE, {start_pc=2, length=151, index=0}", + " Test$TypeAnno", + " 1: LTest$TypeAnno;(): LOCAL_VARIABLE, {start_pc=4, length=146, index=2}", + " Test$TypeAnno", + " 2: LTest$TypeAnno;(): RESOURCE_VARIABLE, {start_pc=14, length=52, index=4}", + " Test$TypeAnno", + " 3: LTest$TypeAnno;(): EXCEPTION_PARAMETER, exception_index=2", + " Test$TypeAnno", + " 4: LTest$TypeAnno;(): EXCEPTION_PARAMETER, exception_index=3", + " Test$TypeAnno", + " 5: LTest$TypeAnno;(): EXCEPTION_PARAMETER, exception_index=4", + " Test$TypeAnno", + " 6: LTest$TypeAnno;(): EXCEPTION_PARAMETER, exception_index=5", + " Test$TypeAnno", + " 7: LTest$TypeAnno;(): LOCAL_VARIABLE, {start_pc=142, length=8, index=6}", + " Test$TypeAnno"); + + checkTypeAnnotations(testClassDesc, + "lambda$o$1", + " 0: LTest$TypeAnno;(): LOCAL_VARIABLE, {start_pc=2, length=12, index=0}", + " Test$TypeAnno", + " 1: LTest$TypeAnno;(): LOCAL_VARIABLE, {start_pc=4, length=7, index=2}", + " Test$TypeAnno"); + + checkTypeAnnotations(testClassDesc, + "lambda$classInLambda$0"); + + checkTypeAnnotations(TestClassDesc.create(classes.resolve("Test$1C.class")), + "lambda$new$0", + " 0: LTest$TypeAnno;(): LOCAL_VARIABLE, {start_pc=2, length=8, index=0}", + " Test$TypeAnno"); + } + + private void checkTypeAnnotations(TestClassDesc testClassDesc, + String lambdaMethodName, + String... expectedEntries) throws IOException { + MethodModel lambdaMethod = singletonValue(testClassDesc.name2Method().get(lambdaMethodName)); + var lambdaTypeAnnos = getAnnotations(lambdaMethod); + if (expectedEntries.length == 0) { + assertFalse(lambdaTypeAnnos.isPresent(), () -> lambdaTypeAnnos.toString()); + } else { + assertTrue(lambdaTypeAnnos.isPresent(), () -> lambdaTypeAnnos.toString()); + assertEquals(expectedEntries.length / 2, + lambdaTypeAnnos.orElseThrow().annotations().size(), + () -> lambdaTypeAnnos.orElseThrow().annotations().toString()); + + checkJavapOutput(testClassDesc, + List.of(expectedEntries)); + } + } + + private T singletonValue(List values) { + assertEquals(1, values.size()); + return values.get(0); + } + + private Optional getAnnotations(MethodModel m) { + return m.findAttribute(Attributes.code()) + .orElseThrow() + .findAttribute(Attributes.runtimeInvisibleTypeAnnotations()); + } + + void checkJavapOutput(TestClassDesc testClassDesc, List expectedOutput) throws IOException { + String javapOut = new JavapTask(tb) + .options("-v", "-p") + .classes(testClassDesc.pathToClass().toString()) + .run() + .getOutput(Task.OutputKind.DIRECT); + + StringBuilder expandedJavapOutBuilder = new StringBuilder(); + Matcher m = CP_REFERENCE.matcher(javapOut); + + while (m.find()) { + String cpIndexText = m.group(1); + int cpIndex = Integer.parseInt(cpIndexText); + m.appendReplacement(expandedJavapOutBuilder, Matcher.quoteReplacement(testClassDesc.cpIndex2Name().getOrDefault(cpIndex, cpIndexText))); + } + + m.appendTail(expandedJavapOutBuilder); + + String expandedJavapOut = expandedJavapOutBuilder.toString(); + + for (String expected : expectedOutput) { + if (!expandedJavapOut.contains(expected)) { + System.err.println(expandedJavapOut); + throw new AssertionError("unexpected output"); + } + } + } + + record TestClassDesc(Path pathToClass, + Map> name2Method, + Map cpIndex2Name) { + public static TestClassDesc create(Path pathToClass) throws IOException{ + ClassModel model = ClassFile.of().parse(pathToClass); + Map> name2Method = + model.methods() + .stream() + .collect(Collectors.groupingBy(m -> m.methodName().stringValue())); + ConstantPool cp = model.constantPool(); + int cpSize = cp.size(); + Map cpIndex2Name = new HashMap<>(); + + for (int i = 1; i < cpSize; i++) { + if (cp.entryByIndex(i) instanceof Utf8Entry string) { + cpIndex2Name.put(i, string.stringValue()); + } + } + + return new TestClassDesc(pathToClass, name2Method, cpIndex2Name); + } + } + + @BeforeEach + void setUp(TestInfo thisTest) { + base = Path.of(thisTest.getTestMethod().orElseThrow().getName()); + } } From 7a11bdd25725749aa98a5fb865020b57f7c15869 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Jeli=C5=84ski?= Date: Wed, 8 Apr 2026 06:58:46 +0000 Subject: [PATCH 199/359] 8381722: Incremental build fails with FileAlreadyExistsException: PreviewFeature.java Reviewed-by: jpai, erikj, jlahoda --- make/langtools/tools/previewfeature/SetupPreviewFeature.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/make/langtools/tools/previewfeature/SetupPreviewFeature.java b/make/langtools/tools/previewfeature/SetupPreviewFeature.java index 2d5207f0e17..5f9b00edc6d 100644 --- a/make/langtools/tools/previewfeature/SetupPreviewFeature.java +++ b/make/langtools/tools/previewfeature/SetupPreviewFeature.java @@ -30,6 +30,7 @@ import java.io.StringWriter; import java.lang.reflect.Field; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.StandardCopyOption; import java.util.HashSet; import java.util.Set; import java.util.stream.Collectors; @@ -76,7 +77,7 @@ public class SetupPreviewFeature { var target = Path.of(args[1]); Files.createDirectories(target.getParent()); if (constantsToAdd.isEmpty()) { - Files.copy(source, target); + Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING); } else { String sourceCode = Files.readString(source); try (var out = Files.newBufferedWriter(target)) { From cbef44cbc0bfcf0b5314b05292ff24d7e4322df7 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Wed, 8 Apr 2026 08:21:52 +0000 Subject: [PATCH 200/359] 8381008: [aix] Test java/net/DatagramSocket/SendReceiveMaxSize.java#preferIPv6Loopback fails after JDK-8380824 Co-authored-by: Daniel Fuchs Reviewed-by: mdoerr, jpai, dfuchs --- test/jdk/java/net/DatagramSocket/SendReceiveMaxSize.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/jdk/java/net/DatagramSocket/SendReceiveMaxSize.java b/test/jdk/java/net/DatagramSocket/SendReceiveMaxSize.java index 86936ae41d0..97a415dd6f8 100644 --- a/test/jdk/java/net/DatagramSocket/SendReceiveMaxSize.java +++ b/test/jdk/java/net/DatagramSocket/SendReceiveMaxSize.java @@ -115,8 +115,8 @@ public class SendReceiveMaxSize { private int BUF_LIMIT; private InetAddress HOST_ADDR; - private final static int IPV4_SNDBUF = 65507; - private final static int IPV6_SNDBUF = 65527; + private final static int IPV4_SNDBUF = IPSupport.getMaxUDPSendBufSizeIPv4(); + private final static int IPV6_SNDBUF = IPSupport.getMaxUDPSendBufSizeIPv6(); private final static Class IOE = IOException.class; private final static Random random = RandomFactory.getRandom(); From 6e1a1f927f123cbb48f328d53e5b13b97079cf85 Mon Sep 17 00:00:00 2001 From: Dingli Zhang Date: Wed, 8 Apr 2026 08:43:19 +0000 Subject: [PATCH 201/359] 8381724: RISC-V: Pass temp registers and use them in CardTableBarrierSetAssembler::store_check() Reviewed-by: fyang, ayang, wenanjian --- .../cardTableBarrierSetAssembler_riscv.cpp | 24 ++++++++++--------- .../cardTableBarrierSetAssembler_riscv.hpp | 4 ++-- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/hotspot/cpu/riscv/gc/shared/cardTableBarrierSetAssembler_riscv.cpp b/src/hotspot/cpu/riscv/gc/shared/cardTableBarrierSetAssembler_riscv.cpp index d94bf428fd2..9eb546a1888 100644 --- a/src/hotspot/cpu/riscv/gc/shared/cardTableBarrierSetAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/gc/shared/cardTableBarrierSetAssembler_riscv.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -56,8 +56,10 @@ void CardTableBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet d } } -void CardTableBarrierSetAssembler::store_check(MacroAssembler* masm, Register obj, Register tmp) { - assert_different_registers(obj, tmp); +void CardTableBarrierSetAssembler::store_check(MacroAssembler* masm, Register obj, Register tmp1, Register tmp2) { + precond(tmp1 != noreg); + precond(tmp2 != noreg); + assert_different_registers(obj, tmp1, tmp2); BarrierSet* bs = BarrierSet::barrier_set(); assert(bs->kind() == BarrierSet::CardTableBarrierSet, "Wrong barrier set kind"); @@ -65,17 +67,17 @@ void CardTableBarrierSetAssembler::store_check(MacroAssembler* masm, Register ob assert(CardTable::dirty_card_val() == 0, "must be"); - __ load_byte_map_base(tmp); - __ add(tmp, obj, tmp); + __ load_byte_map_base(tmp1); + __ add(tmp1, obj, tmp1); if (UseCondCardMark) { Label L_already_dirty; - __ lbu(t1, Address(tmp)); - __ beqz(t1, L_already_dirty); - __ sb(zr, Address(tmp)); + __ lbu(tmp2, Address(tmp1)); + __ beqz(tmp2, L_already_dirty); + __ sb(zr, Address(tmp1)); __ bind(L_already_dirty); } else { - __ sb(zr, Address(tmp)); + __ sb(zr, Address(tmp1)); } } @@ -119,10 +121,10 @@ void CardTableBarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorS if (needs_post_barrier) { // flatten object address if needed if (!precise || dst.offset() == 0) { - store_check(masm, dst.base(), tmp3); + store_check(masm, dst.base(), tmp1, tmp2); } else { __ la(tmp3, dst); - store_check(masm, tmp3, t0); + store_check(masm, tmp3, tmp1, tmp2); } } } diff --git a/src/hotspot/cpu/riscv/gc/shared/cardTableBarrierSetAssembler_riscv.hpp b/src/hotspot/cpu/riscv/gc/shared/cardTableBarrierSetAssembler_riscv.hpp index 6f6e9065103..1576f0a6dd8 100644 --- a/src/hotspot/cpu/riscv/gc/shared/cardTableBarrierSetAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/gc/shared/cardTableBarrierSetAssembler_riscv.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -31,7 +31,7 @@ class CardTableBarrierSetAssembler: public BarrierSetAssembler { protected: - void store_check(MacroAssembler* masm, Register obj, Register tmp); + void store_check(MacroAssembler* masm, Register obj, Register tmp1, Register tmp2); virtual void gen_write_ref_array_pre_barrier(MacroAssembler* masm, DecoratorSet decorators, Register addr, Register count, RegSet saved_regs) {} From cfae18fa606d8924f1f020b0f2de8617dd648bb2 Mon Sep 17 00:00:00 2001 From: Alexey Ivanov Date: Wed, 8 Apr 2026 08:56:58 +0000 Subject: [PATCH 202/359] 8381745: Ensure Modal/FileDialog tests explicitly reference Asserts class Reviewed-by: serb, dmarkov --- .../FileDialog/FileDialogAppModal1Test.java | 3 ++- .../FileDialog/FileDialogAppModal2Test.java | 3 ++- .../FileDialog/FileDialogAppModal3Test.java | 3 ++- .../FileDialog/FileDialogAppModal4Test.java | 3 ++- .../FileDialog/FileDialogAppModal5Test.java | 3 ++- .../FileDialog/FileDialogAppModal6Test.java | 3 ++- .../Modal/FileDialog/FileDialogDWDTest.java | 8 +++++-- .../FileDialog/FileDialogDocModal1Test.java | 3 ++- .../FileDialog/FileDialogDocModal2Test.java | 3 ++- .../FileDialog/FileDialogDocModal3Test.java | 3 ++- .../FileDialog/FileDialogDocModal4Test.java | 3 ++- .../FileDialog/FileDialogDocModal5Test.java | 3 ++- .../FileDialog/FileDialogDocModal6Test.java | 3 ++- .../FileDialog/FileDialogDocModal7Test.java | 3 ++- .../Modal/FileDialog/FileDialogFWDTest.java | 9 +++++--- .../FileDialog/FileDialogModal1Test.java | 3 ++- .../FileDialog/FileDialogModal2Test.java | 3 ++- .../FileDialog/FileDialogModal3Test.java | 3 ++- .../FileDialog/FileDialogModal4Test.java | 3 ++- .../FileDialog/FileDialogModal5Test.java | 3 ++- .../FileDialog/FileDialogModal6Test.java | 3 ++- .../FileDialog/FileDialogModalityTest.java | 8 +++++-- .../FileDialog/FileDialogNonModal1Test.java | 3 ++- .../FileDialog/FileDialogNonModal2Test.java | 3 ++- .../FileDialog/FileDialogNonModal3Test.java | 3 ++- .../FileDialog/FileDialogNonModal4Test.java | 3 ++- .../FileDialog/FileDialogNonModal5Test.java | 3 ++- .../FileDialog/FileDialogNonModal6Test.java | 3 ++- .../FileDialog/FileDialogNonModal7Test.java | 3 ++- .../FileDialog/FileDialogTKModal1Test.java | 3 ++- .../FileDialog/FileDialogTKModal2Test.java | 3 ++- .../FileDialog/FileDialogTKModal3Test.java | 3 ++- .../FileDialog/FileDialogTKModal4Test.java | 3 ++- .../FileDialog/FileDialogTKModal5Test.java | 3 ++- .../FileDialog/FileDialogTKModal6Test.java | 3 ++- .../FileDialog/FileDialogTKModal7Test.java | 3 ++- .../java/awt/Modal/helpers/TestDialog.java | 22 ++++++++++++++----- .../jdk/java/awt/Modal/helpers/TestFrame.java | 21 +++++++++++++----- .../java/awt/Modal/helpers/TestWindow.java | 22 ++++++++++++++----- 39 files changed, 134 insertions(+), 55 deletions(-) diff --git a/test/jdk/java/awt/Modal/FileDialog/FileDialogAppModal1Test.java b/test/jdk/java/awt/Modal/FileDialog/FileDialogAppModal1Test.java index 7f2ae2361ae..7ee265cf34f 100644 --- a/test/jdk/java/awt/Modal/FileDialog/FileDialogAppModal1Test.java +++ b/test/jdk/java/awt/Modal/FileDialog/FileDialogAppModal1Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * 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,7 @@ import java.awt.Dialog; * @library ../helpers /lib/client/ * @library /test/lib * @build ExtendedRobot + * @build jdk.test.lib.Asserts * @build Flag * @build TestDialog * @build TestFrame diff --git a/test/jdk/java/awt/Modal/FileDialog/FileDialogAppModal2Test.java b/test/jdk/java/awt/Modal/FileDialog/FileDialogAppModal2Test.java index 5fef862611d..53a7d002a49 100644 --- a/test/jdk/java/awt/Modal/FileDialog/FileDialogAppModal2Test.java +++ b/test/jdk/java/awt/Modal/FileDialog/FileDialogAppModal2Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * 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,7 @@ import java.awt.Dialog; * @library ../helpers /lib/client/ * @library /test/lib * @build ExtendedRobot + * @build jdk.test.lib.Asserts * @build Flag * @build TestDialog * @build TestFrame diff --git a/test/jdk/java/awt/Modal/FileDialog/FileDialogAppModal3Test.java b/test/jdk/java/awt/Modal/FileDialog/FileDialogAppModal3Test.java index d054050faba..9718a05e53b 100644 --- a/test/jdk/java/awt/Modal/FileDialog/FileDialogAppModal3Test.java +++ b/test/jdk/java/awt/Modal/FileDialog/FileDialogAppModal3Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * 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,7 @@ import java.awt.Dialog; * @library ../helpers /lib/client/ * @library /test/lib * @build ExtendedRobot + * @build jdk.test.lib.Asserts * @build Flag * @build TestDialog * @build TestFrame diff --git a/test/jdk/java/awt/Modal/FileDialog/FileDialogAppModal4Test.java b/test/jdk/java/awt/Modal/FileDialog/FileDialogAppModal4Test.java index c3dea7cd590..7ae3898637e 100644 --- a/test/jdk/java/awt/Modal/FileDialog/FileDialogAppModal4Test.java +++ b/test/jdk/java/awt/Modal/FileDialog/FileDialogAppModal4Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * 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,7 @@ import java.awt.Dialog; * @library ../helpers /lib/client/ * @library /test/lib * @build ExtendedRobot + * @build jdk.test.lib.Asserts * @build Flag * @build TestDialog * @build TestFrame diff --git a/test/jdk/java/awt/Modal/FileDialog/FileDialogAppModal5Test.java b/test/jdk/java/awt/Modal/FileDialog/FileDialogAppModal5Test.java index 503c2f1cd01..026baab2229 100644 --- a/test/jdk/java/awt/Modal/FileDialog/FileDialogAppModal5Test.java +++ b/test/jdk/java/awt/Modal/FileDialog/FileDialogAppModal5Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * 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,7 @@ import java.awt.Dialog; * @library ../helpers /lib/client/ * @library /test/lib * @build ExtendedRobot + * @build jdk.test.lib.Asserts * @build Flag * @build TestDialog * @build TestFrame diff --git a/test/jdk/java/awt/Modal/FileDialog/FileDialogAppModal6Test.java b/test/jdk/java/awt/Modal/FileDialog/FileDialogAppModal6Test.java index 5fbbf040c58..0a93c77a7fa 100644 --- a/test/jdk/java/awt/Modal/FileDialog/FileDialogAppModal6Test.java +++ b/test/jdk/java/awt/Modal/FileDialog/FileDialogAppModal6Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * 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,7 @@ import java.awt.Dialog; * @library ../helpers /lib/client/ * @library /test/lib * @build ExtendedRobot + * @build jdk.test.lib.Asserts * @build Flag * @build TestDialog * @build TestFrame diff --git a/test/jdk/java/awt/Modal/FileDialog/FileDialogDWDTest.java b/test/jdk/java/awt/Modal/FileDialog/FileDialogDWDTest.java index 045c7e5ad49..5424744ad43 100644 --- a/test/jdk/java/awt/Modal/FileDialog/FileDialogDWDTest.java +++ b/test/jdk/java/awt/Modal/FileDialog/FileDialogDWDTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * 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,11 @@ */ -import java.awt.*; +import java.awt.Dialog; +import java.awt.EventQueue; +import java.awt.FileDialog; +import java.awt.Frame; +import java.awt.Toolkit; // DWD: Dialog, Window, Dialog diff --git a/test/jdk/java/awt/Modal/FileDialog/FileDialogDocModal1Test.java b/test/jdk/java/awt/Modal/FileDialog/FileDialogDocModal1Test.java index c115fde948b..1f5871caf6d 100644 --- a/test/jdk/java/awt/Modal/FileDialog/FileDialogDocModal1Test.java +++ b/test/jdk/java/awt/Modal/FileDialog/FileDialogDocModal1Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * 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,7 @@ import java.awt.Dialog; * @library ../helpers /lib/client/ * @library /test/lib * @build ExtendedRobot + * @build jdk.test.lib.Asserts * @build Flag * @build TestDialog * @build TestFrame diff --git a/test/jdk/java/awt/Modal/FileDialog/FileDialogDocModal2Test.java b/test/jdk/java/awt/Modal/FileDialog/FileDialogDocModal2Test.java index 604d3d41f1b..3b4092d3b01 100644 --- a/test/jdk/java/awt/Modal/FileDialog/FileDialogDocModal2Test.java +++ b/test/jdk/java/awt/Modal/FileDialog/FileDialogDocModal2Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * 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,7 @@ import java.awt.Dialog; * @library ../helpers /lib/client/ * @library /test/lib * @build ExtendedRobot + * @build jdk.test.lib.Asserts * @build Flag * @build TestDialog * @build TestFrame diff --git a/test/jdk/java/awt/Modal/FileDialog/FileDialogDocModal3Test.java b/test/jdk/java/awt/Modal/FileDialog/FileDialogDocModal3Test.java index b0a12d43cd4..d59cbd31396 100644 --- a/test/jdk/java/awt/Modal/FileDialog/FileDialogDocModal3Test.java +++ b/test/jdk/java/awt/Modal/FileDialog/FileDialogDocModal3Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * 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,7 @@ import java.awt.Dialog; * @library ../helpers /lib/client/ * @library /test/lib * @build ExtendedRobot + * @build jdk.test.lib.Asserts * @build Flag * @build TestDialog * @build TestFrame diff --git a/test/jdk/java/awt/Modal/FileDialog/FileDialogDocModal4Test.java b/test/jdk/java/awt/Modal/FileDialog/FileDialogDocModal4Test.java index 4a392c399db..6a4a967672c 100644 --- a/test/jdk/java/awt/Modal/FileDialog/FileDialogDocModal4Test.java +++ b/test/jdk/java/awt/Modal/FileDialog/FileDialogDocModal4Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * 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,7 @@ import java.awt.Dialog; * @library ../helpers /lib/client/ * @library /test/lib * @build ExtendedRobot + * @build jdk.test.lib.Asserts * @build Flag * @build TestDialog * @build TestFrame diff --git a/test/jdk/java/awt/Modal/FileDialog/FileDialogDocModal5Test.java b/test/jdk/java/awt/Modal/FileDialog/FileDialogDocModal5Test.java index 8eacf51cd5e..6bcb7fa6c54 100644 --- a/test/jdk/java/awt/Modal/FileDialog/FileDialogDocModal5Test.java +++ b/test/jdk/java/awt/Modal/FileDialog/FileDialogDocModal5Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * 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,7 @@ import java.awt.Dialog; * @library ../helpers /lib/client/ * @library /test/lib * @build ExtendedRobot + * @build jdk.test.lib.Asserts * @build Flag * @build TestDialog * @build TestFrame diff --git a/test/jdk/java/awt/Modal/FileDialog/FileDialogDocModal6Test.java b/test/jdk/java/awt/Modal/FileDialog/FileDialogDocModal6Test.java index 0d50231522c..aff84c3b40f 100644 --- a/test/jdk/java/awt/Modal/FileDialog/FileDialogDocModal6Test.java +++ b/test/jdk/java/awt/Modal/FileDialog/FileDialogDocModal6Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * 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,7 @@ import java.awt.Dialog; * @library ../helpers /lib/client/ * @library /test/lib * @build ExtendedRobot + * @build jdk.test.lib.Asserts * @build Flag * @build TestDialog * @build TestFrame diff --git a/test/jdk/java/awt/Modal/FileDialog/FileDialogDocModal7Test.java b/test/jdk/java/awt/Modal/FileDialog/FileDialogDocModal7Test.java index cde4592be91..9fd7d72a399 100644 --- a/test/jdk/java/awt/Modal/FileDialog/FileDialogDocModal7Test.java +++ b/test/jdk/java/awt/Modal/FileDialog/FileDialogDocModal7Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * 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 java.awt.Dialog; * @library ../helpers /lib/client/ * @library /test/lib * @build ExtendedRobot + * @build jdk.test.lib.Asserts * @build Flag * @build TestDialog * @build TestFrame diff --git a/test/jdk/java/awt/Modal/FileDialog/FileDialogFWDTest.java b/test/jdk/java/awt/Modal/FileDialog/FileDialogFWDTest.java index 0026c0da50f..e77024d68e2 100644 --- a/test/jdk/java/awt/Modal/FileDialog/FileDialogFWDTest.java +++ b/test/jdk/java/awt/Modal/FileDialog/FileDialogFWDTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,8 +21,11 @@ * questions. */ -import java.awt.*; - +import java.awt.Dialog; +import java.awt.EventQueue; +import java.awt.FileDialog; +import java.awt.Frame; +import java.awt.Toolkit; // FWD: Frame, Window, Dialog diff --git a/test/jdk/java/awt/Modal/FileDialog/FileDialogModal1Test.java b/test/jdk/java/awt/Modal/FileDialog/FileDialogModal1Test.java index cd845cf3a75..b7080d2081b 100644 --- a/test/jdk/java/awt/Modal/FileDialog/FileDialogModal1Test.java +++ b/test/jdk/java/awt/Modal/FileDialog/FileDialogModal1Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +34,7 @@ * @library ../helpers /lib/client/ * @library /test/lib * @build ExtendedRobot + * @build jdk.test.lib.Asserts * @build Flag * @build TestDialog * @build TestFrame diff --git a/test/jdk/java/awt/Modal/FileDialog/FileDialogModal2Test.java b/test/jdk/java/awt/Modal/FileDialog/FileDialogModal2Test.java index 5fe63428bb7..349c5900a41 100644 --- a/test/jdk/java/awt/Modal/FileDialog/FileDialogModal2Test.java +++ b/test/jdk/java/awt/Modal/FileDialog/FileDialogModal2Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +34,7 @@ * @library ../helpers /lib/client/ * @library /test/lib * @build ExtendedRobot + * @build jdk.test.lib.Asserts * @build Flag * @build TestDialog * @build TestFrame diff --git a/test/jdk/java/awt/Modal/FileDialog/FileDialogModal3Test.java b/test/jdk/java/awt/Modal/FileDialog/FileDialogModal3Test.java index 37da58a4bfe..911a2fb068a 100644 --- a/test/jdk/java/awt/Modal/FileDialog/FileDialogModal3Test.java +++ b/test/jdk/java/awt/Modal/FileDialog/FileDialogModal3Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +34,7 @@ * @library ../helpers /lib/client/ * @library /test/lib * @build ExtendedRobot + * @build jdk.test.lib.Asserts * @build Flag * @build TestDialog * @build TestFrame diff --git a/test/jdk/java/awt/Modal/FileDialog/FileDialogModal4Test.java b/test/jdk/java/awt/Modal/FileDialog/FileDialogModal4Test.java index 2761a842c86..431e2302215 100644 --- a/test/jdk/java/awt/Modal/FileDialog/FileDialogModal4Test.java +++ b/test/jdk/java/awt/Modal/FileDialog/FileDialogModal4Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +34,7 @@ * @library ../helpers /lib/client/ * @library /test/lib * @build ExtendedRobot + * @build jdk.test.lib.Asserts * @build Flag * @build TestDialog * @build TestFrame diff --git a/test/jdk/java/awt/Modal/FileDialog/FileDialogModal5Test.java b/test/jdk/java/awt/Modal/FileDialog/FileDialogModal5Test.java index d8e29db02b7..29ad342b71a 100644 --- a/test/jdk/java/awt/Modal/FileDialog/FileDialogModal5Test.java +++ b/test/jdk/java/awt/Modal/FileDialog/FileDialogModal5Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +34,7 @@ * @library ../helpers /lib/client/ * @library /test/lib * @build ExtendedRobot + * @build jdk.test.lib.Asserts * @build Flag * @build TestDialog * @build TestFrame diff --git a/test/jdk/java/awt/Modal/FileDialog/FileDialogModal6Test.java b/test/jdk/java/awt/Modal/FileDialog/FileDialogModal6Test.java index d70bd001ad1..88c7dd5e29e 100644 --- a/test/jdk/java/awt/Modal/FileDialog/FileDialogModal6Test.java +++ b/test/jdk/java/awt/Modal/FileDialog/FileDialogModal6Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +34,7 @@ * @library ../helpers /lib/client/ * @library /test/lib * @build ExtendedRobot + * @build jdk.test.lib.Asserts * @build Flag * @build TestDialog * @build TestFrame diff --git a/test/jdk/java/awt/Modal/FileDialog/FileDialogModalityTest.java b/test/jdk/java/awt/Modal/FileDialog/FileDialogModalityTest.java index 7f69d6176d0..00a6a58bd73 100644 --- a/test/jdk/java/awt/Modal/FileDialog/FileDialogModalityTest.java +++ b/test/jdk/java/awt/Modal/FileDialog/FileDialogModalityTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * 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,11 @@ * questions. */ -import java.awt.*; +import java.awt.Dialog; +import java.awt.EventQueue; +import java.awt.FileDialog; +import java.awt.Frame; +import java.awt.Toolkit; public class FileDialogModalityTest { diff --git a/test/jdk/java/awt/Modal/FileDialog/FileDialogNonModal1Test.java b/test/jdk/java/awt/Modal/FileDialog/FileDialogNonModal1Test.java index a02860c25fb..e6463081a81 100644 --- a/test/jdk/java/awt/Modal/FileDialog/FileDialogNonModal1Test.java +++ b/test/jdk/java/awt/Modal/FileDialog/FileDialogNonModal1Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +34,7 @@ * @library ../helpers /lib/client/ * @library /test/lib * @build ExtendedRobot + * @build jdk.test.lib.Asserts * @build Flag * @build TestDialog * @build TestFrame diff --git a/test/jdk/java/awt/Modal/FileDialog/FileDialogNonModal2Test.java b/test/jdk/java/awt/Modal/FileDialog/FileDialogNonModal2Test.java index 47667d4b7ba..0fff3b3c43f 100644 --- a/test/jdk/java/awt/Modal/FileDialog/FileDialogNonModal2Test.java +++ b/test/jdk/java/awt/Modal/FileDialog/FileDialogNonModal2Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +34,7 @@ * @library ../helpers /lib/client/ * @library /test/lib * @build ExtendedRobot + * @build jdk.test.lib.Asserts * @build Flag * @build TestDialog * @build TestFrame diff --git a/test/jdk/java/awt/Modal/FileDialog/FileDialogNonModal3Test.java b/test/jdk/java/awt/Modal/FileDialog/FileDialogNonModal3Test.java index 6d3354a7472..31c1f42ca93 100644 --- a/test/jdk/java/awt/Modal/FileDialog/FileDialogNonModal3Test.java +++ b/test/jdk/java/awt/Modal/FileDialog/FileDialogNonModal3Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +34,7 @@ * @library ../helpers /lib/client/ * @library /test/lib * @build ExtendedRobot + * @build jdk.test.lib.Asserts * @build Flag * @build TestDialog * @build TestFrame diff --git a/test/jdk/java/awt/Modal/FileDialog/FileDialogNonModal4Test.java b/test/jdk/java/awt/Modal/FileDialog/FileDialogNonModal4Test.java index 1854dd367c5..0050d57839b 100644 --- a/test/jdk/java/awt/Modal/FileDialog/FileDialogNonModal4Test.java +++ b/test/jdk/java/awt/Modal/FileDialog/FileDialogNonModal4Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +34,7 @@ * @library ../helpers /lib/client/ * @library /test/lib * @build ExtendedRobot + * @build jdk.test.lib.Asserts * @build Flag * @build TestDialog * @build TestFrame diff --git a/test/jdk/java/awt/Modal/FileDialog/FileDialogNonModal5Test.java b/test/jdk/java/awt/Modal/FileDialog/FileDialogNonModal5Test.java index 9425fe5288d..c05af4c399e 100644 --- a/test/jdk/java/awt/Modal/FileDialog/FileDialogNonModal5Test.java +++ b/test/jdk/java/awt/Modal/FileDialog/FileDialogNonModal5Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +34,7 @@ * @library ../helpers /lib/client/ * @library /test/lib * @build ExtendedRobot + * @build jdk.test.lib.Asserts * @build Flag * @build TestDialog * @build TestFrame diff --git a/test/jdk/java/awt/Modal/FileDialog/FileDialogNonModal6Test.java b/test/jdk/java/awt/Modal/FileDialog/FileDialogNonModal6Test.java index 70ec49a038c..98cb842e65c 100644 --- a/test/jdk/java/awt/Modal/FileDialog/FileDialogNonModal6Test.java +++ b/test/jdk/java/awt/Modal/FileDialog/FileDialogNonModal6Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +34,7 @@ * @library ../helpers /lib/client/ * @library /test/lib * @build ExtendedRobot + * @build jdk.test.lib.Asserts * @build Flag * @build TestDialog * @build TestFrame diff --git a/test/jdk/java/awt/Modal/FileDialog/FileDialogNonModal7Test.java b/test/jdk/java/awt/Modal/FileDialog/FileDialogNonModal7Test.java index c34e9201f40..7c29610e205 100644 --- a/test/jdk/java/awt/Modal/FileDialog/FileDialogNonModal7Test.java +++ b/test/jdk/java/awt/Modal/FileDialog/FileDialogNonModal7Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * 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 java.awt.Dialog; * @library ../helpers /lib/client/ * @library /test/lib * @build ExtendedRobot + * @build jdk.test.lib.Asserts * @build Flag * @build TestDialog * @build TestFrame diff --git a/test/jdk/java/awt/Modal/FileDialog/FileDialogTKModal1Test.java b/test/jdk/java/awt/Modal/FileDialog/FileDialogTKModal1Test.java index 7278a9db0a1..8578a69bed4 100644 --- a/test/jdk/java/awt/Modal/FileDialog/FileDialogTKModal1Test.java +++ b/test/jdk/java/awt/Modal/FileDialog/FileDialogTKModal1Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * 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,7 @@ import java.awt.Dialog; * @library ../helpers /lib/client/ * @library /test/lib * @build ExtendedRobot + * @build jdk.test.lib.Asserts * @build Flag * @build TestDialog * @build TestFrame diff --git a/test/jdk/java/awt/Modal/FileDialog/FileDialogTKModal2Test.java b/test/jdk/java/awt/Modal/FileDialog/FileDialogTKModal2Test.java index 282c84f64dc..182ebfd43ec 100644 --- a/test/jdk/java/awt/Modal/FileDialog/FileDialogTKModal2Test.java +++ b/test/jdk/java/awt/Modal/FileDialog/FileDialogTKModal2Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * 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,7 @@ import java.awt.Dialog; * @library ../helpers /lib/client/ * @library /test/lib * @build ExtendedRobot + * @build jdk.test.lib.Asserts * @build Flag * @build TestDialog * @build TestFrame diff --git a/test/jdk/java/awt/Modal/FileDialog/FileDialogTKModal3Test.java b/test/jdk/java/awt/Modal/FileDialog/FileDialogTKModal3Test.java index e09227564ef..78344558b40 100644 --- a/test/jdk/java/awt/Modal/FileDialog/FileDialogTKModal3Test.java +++ b/test/jdk/java/awt/Modal/FileDialog/FileDialogTKModal3Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * 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,7 @@ import java.awt.Dialog; * @library ../helpers /lib/client/ * @library /test/lib * @build ExtendedRobot + * @build jdk.test.lib.Asserts * @build Flag * @build TestDialog * @build TestFrame diff --git a/test/jdk/java/awt/Modal/FileDialog/FileDialogTKModal4Test.java b/test/jdk/java/awt/Modal/FileDialog/FileDialogTKModal4Test.java index d23e781a3c8..3157ebe9a2c 100644 --- a/test/jdk/java/awt/Modal/FileDialog/FileDialogTKModal4Test.java +++ b/test/jdk/java/awt/Modal/FileDialog/FileDialogTKModal4Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * 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,7 @@ import java.awt.Dialog; * @library ../helpers /lib/client/ * @library /test/lib * @build ExtendedRobot + * @build jdk.test.lib.Asserts * @build Flag * @build TestDialog * @build TestFrame diff --git a/test/jdk/java/awt/Modal/FileDialog/FileDialogTKModal5Test.java b/test/jdk/java/awt/Modal/FileDialog/FileDialogTKModal5Test.java index 515bd0072c2..11d10557006 100644 --- a/test/jdk/java/awt/Modal/FileDialog/FileDialogTKModal5Test.java +++ b/test/jdk/java/awt/Modal/FileDialog/FileDialogTKModal5Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * 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,7 @@ import java.awt.Dialog; * @library ../helpers /lib/client/ * @library /test/lib * @build ExtendedRobot + * @build jdk.test.lib.Asserts * @build Flag * @build TestDialog * @build TestFrame diff --git a/test/jdk/java/awt/Modal/FileDialog/FileDialogTKModal6Test.java b/test/jdk/java/awt/Modal/FileDialog/FileDialogTKModal6Test.java index 725924ca1c5..4ef7699fb0b 100644 --- a/test/jdk/java/awt/Modal/FileDialog/FileDialogTKModal6Test.java +++ b/test/jdk/java/awt/Modal/FileDialog/FileDialogTKModal6Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * 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,7 @@ import java.awt.Dialog; * @library ../helpers /lib/client/ * @library /test/lib * @build ExtendedRobot + * @build jdk.test.lib.Asserts * @build Flag * @build TestDialog * @build TestFrame diff --git a/test/jdk/java/awt/Modal/FileDialog/FileDialogTKModal7Test.java b/test/jdk/java/awt/Modal/FileDialog/FileDialogTKModal7Test.java index f6e5bb80a38..bb416493a36 100644 --- a/test/jdk/java/awt/Modal/FileDialog/FileDialogTKModal7Test.java +++ b/test/jdk/java/awt/Modal/FileDialog/FileDialogTKModal7Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * 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 java.awt.Dialog; * @library ../helpers /lib/client/ * @library /test/lib * @build ExtendedRobot + * @build jdk.test.lib.Asserts * @build Flag * @build TestDialog * @build TestFrame diff --git a/test/jdk/java/awt/Modal/helpers/TestDialog.java b/test/jdk/java/awt/Modal/helpers/TestDialog.java index 2ae93f835b9..a56ce1f5164 100644 --- a/test/jdk/java/awt/Modal/helpers/TestDialog.java +++ b/test/jdk/java/awt/Modal/helpers/TestDialog.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * 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,11 +22,23 @@ */ -import java.awt.*; -import java.awt.event.*; - -import static jdk.test.lib.Asserts.*; +import java.awt.Button; +import java.awt.Dialog; +import java.awt.Frame; +import java.awt.GridLayout; +import java.awt.Panel; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.awt.event.KeyEvent; +import java.awt.event.WindowEvent; +import java.awt.event.WindowFocusListener; +import java.awt.event.WindowListener; +import static jdk.test.lib.Asserts.assertEQ; +import static jdk.test.lib.Asserts.assertFalse; +import static jdk.test.lib.Asserts.assertTrue; public class TestDialog extends Dialog implements ActionListener, diff --git a/test/jdk/java/awt/Modal/helpers/TestFrame.java b/test/jdk/java/awt/Modal/helpers/TestFrame.java index dd8ed1530ef..d002d6faf8e 100644 --- a/test/jdk/java/awt/Modal/helpers/TestFrame.java +++ b/test/jdk/java/awt/Modal/helpers/TestFrame.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * 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,11 +21,22 @@ * questions. */ -import java.awt.*; -import java.awt.event.*; - -import static jdk.test.lib.Asserts.*; +import java.awt.Button; +import java.awt.Frame; +import java.awt.GridLayout; +import java.awt.Panel; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.awt.event.KeyEvent; +import java.awt.event.WindowEvent; +import java.awt.event.WindowFocusListener; +import java.awt.event.WindowListener; +import static jdk.test.lib.Asserts.assertEQ; +import static jdk.test.lib.Asserts.assertFalse; +import static jdk.test.lib.Asserts.assertTrue; public class TestFrame extends Frame implements ActionListener, diff --git a/test/jdk/java/awt/Modal/helpers/TestWindow.java b/test/jdk/java/awt/Modal/helpers/TestWindow.java index 1e2ffb078c8..249f56ead7d 100644 --- a/test/jdk/java/awt/Modal/helpers/TestWindow.java +++ b/test/jdk/java/awt/Modal/helpers/TestWindow.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * 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,11 +21,23 @@ * questions. */ -import java.awt.*; -import java.awt.event.*; - -import static jdk.test.lib.Asserts.*; +import java.awt.Button; +import java.awt.Frame; +import java.awt.GridLayout; +import java.awt.Panel; +import java.awt.Window; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.awt.event.KeyEvent; +import java.awt.event.WindowEvent; +import java.awt.event.WindowFocusListener; +import java.awt.event.WindowListener; +import static jdk.test.lib.Asserts.assertEQ; +import static jdk.test.lib.Asserts.assertFalse; +import static jdk.test.lib.Asserts.assertTrue; public class TestWindow extends Window implements ActionListener, From d7bace12ff72d9ab5be53cd1ef3a2b839ff9ddea Mon Sep 17 00:00:00 2001 From: Serhiy Sachkov Date: Wed, 8 Apr 2026 09:29:59 +0000 Subject: [PATCH 203/359] 8380990: Update testng and junit tests to use diagnoseConfigurationIssue() method and post processing Reviewed-by: dfuchs --- .../lang/ProcessBuilder/ReaderWriterTest.java | 5 ++--- .../net/DatagramSocket/SendReceiveMaxSize.java | 17 +++++++---------- .../java/net/InetSocketAddress/ToString.java | 12 +++++++++--- .../java/net/MulticastSocket/IPMulticastIF.java | 12 +++++++++--- .../NetworkInterfaceStreamTest.java | 11 ++++++++--- .../net/NetworkInterface/NullMacAddress.java | 12 +++++++++--- .../java/net/SocketOption/ImmutableOptions.java | 13 +++++++++---- .../net/httpclient/quic/VariableLengthTest.java | 5 ++--- .../LookupPolicyMappingTest.java | 4 +++- .../DatagramChannel/AfterDisconnect.java | 6 +++++- .../DatagramChannel/SendReceiveMaxSize.java | 8 ++++---- .../channels/etc/LocalSocketAddressType.java | 9 ++------- .../java/nio/channels/etc/OpenAndConnect.java | 8 +------- .../java/nio/channels/etc/ProtocolFamilies.java | 8 +------- .../text/Format/DecimalFormat/CloneTest.java | 8 ++++---- .../AsynchronousSocketChannelNAPITest.java | 10 +++++++--- .../DatagramChannelNAPITest.java | 10 +++++++--- .../DatagramSocketNAPITest.java | 10 +++++++--- .../SocketChannelNAPITest.java | 10 +++++++--- .../ExtendedSocketOption/SocketNAPITest.java | 10 +++++++--- 20 files changed, 110 insertions(+), 78 deletions(-) diff --git a/test/jdk/java/lang/ProcessBuilder/ReaderWriterTest.java b/test/jdk/java/lang/ProcessBuilder/ReaderWriterTest.java index 6bff8d5e592..0f5acf607ba 100644 --- a/test/jdk/java/lang/ProcessBuilder/ReaderWriterTest.java +++ b/test/jdk/java/lang/ProcessBuilder/ReaderWriterTest.java @@ -37,12 +37,11 @@ import java.nio.charset.StandardCharsets; import java.nio.charset.UnsupportedCharsetException; import java.util.stream.Stream; -import jtreg.SkippedException; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; +import org.opentest4j.TestAbortedException; /* * @test @@ -180,7 +179,7 @@ public class ReaderWriterTest { cs = Charset.forName(encoding); System.out.println("Charset: " + cs); } catch (UnsupportedCharsetException use) { - throw new SkippedException("Charset not supported: " + encoding); + throw new TestAbortedException("Charset not supported: " + encoding); } String cleanCSName = cleanCharsetName(cs); diff --git a/test/jdk/java/net/DatagramSocket/SendReceiveMaxSize.java b/test/jdk/java/net/DatagramSocket/SendReceiveMaxSize.java index 97a415dd6f8..2b68af9cbf2 100644 --- a/test/jdk/java/net/DatagramSocket/SendReceiveMaxSize.java +++ b/test/jdk/java/net/DatagramSocket/SendReceiveMaxSize.java @@ -87,8 +87,6 @@ import jdk.test.lib.RandomFactory; import jdk.test.lib.Platform; -import jdk.test.lib.net.IPSupport; -import jtreg.SkippedException; import org.testng.SkipException; import org.testng.annotations.BeforeTest; import org.testng.annotations.DataProvider; @@ -102,9 +100,11 @@ import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.MulticastSocket; import java.nio.channels.DatagramChannel; +import java.util.Optional; import java.util.Random; import static java.net.StandardSocketOptions.SO_RCVBUF; +import static jdk.test.lib.net.IPSupport.diagnoseConfigurationIssue; import static org.testng.Assert.assertTrue; import static org.testng.Assert.assertEquals; import static org.testng.Assert.expectThrows; @@ -127,14 +127,11 @@ public class SendReceiveMaxSize { @BeforeTest public void setUp() throws IOException { - try { - // This method throws jtreg.SkippedException, which is - // interpreted as a test failure by testng - IPSupport.throwSkippedExceptionIfNonOperational(); - } catch (SkippedException skip) { - // throws the appropriate TestNG SkipException - throw new SkipException(skip.getMessage(), skip); - } + Optional configurationIssue = diagnoseConfigurationIssue(); + configurationIssue.map(SkipException::new).ifPresent(x -> { + throw x; + }); + HOST_ADDR = PREFER_LOOPBACK ? InetAddress.getLoopbackAddress() : InetAddress.getLocalHost(); BUF_LIMIT = (HOST_ADDR instanceof Inet6Address) ? IPV6_SNDBUF : IPV4_SNDBUF; System.out.printf("Host address: %s, Buffer limit: %d%n", HOST_ADDR, BUF_LIMIT); diff --git a/test/jdk/java/net/InetSocketAddress/ToString.java b/test/jdk/java/net/InetSocketAddress/ToString.java index 33fd1dd6a73..12eb599b872 100644 --- a/test/jdk/java/net/InetSocketAddress/ToString.java +++ b/test/jdk/java/net/InetSocketAddress/ToString.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * 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,15 @@ */ import java.net.*; +import java.util.Optional; -import jdk.test.lib.net.IPSupport; +import org.testng.SkipException; import org.testng.annotations.BeforeTest; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; +import static jdk.test.lib.net.IPSupport.diagnoseConfigurationIssue; + public class ToString { private static final String loopbackAddr; @@ -74,7 +77,10 @@ public class ToString { @BeforeTest public void setup() { - IPSupport.throwSkippedExceptionIfNonOperational(); + Optional configurationIssue = diagnoseConfigurationIssue(); + configurationIssue.map(SkipException::new).ifPresent(x -> { + throw x; + }); } @Test diff --git a/test/jdk/java/net/MulticastSocket/IPMulticastIF.java b/test/jdk/java/net/MulticastSocket/IPMulticastIF.java index 3909f6d6276..6f6e7dd1942 100644 --- a/test/jdk/java/net/MulticastSocket/IPMulticastIF.java +++ b/test/jdk/java/net/MulticastSocket/IPMulticastIF.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * 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,10 @@ import java.net.MulticastSocket; import java.net.NetworkInterface; import java.util.ArrayList; import java.util.List; +import java.util.Optional; + import jdk.test.lib.NetworkConfiguration; -import jdk.test.lib.net.IPSupport; +import org.testng.SkipException; import org.testng.annotations.BeforeTest; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; @@ -36,6 +38,7 @@ import static java.lang.String.format; import static java.lang.System.out; import static java.net.StandardSocketOptions.IP_MULTICAST_IF; import static java.util.stream.Collectors.toList; +import static jdk.test.lib.net.IPSupport.diagnoseConfigurationIssue; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; @@ -53,7 +56,10 @@ public class IPMulticastIF { @BeforeTest public void sanity() { - IPSupport.throwSkippedExceptionIfNonOperational(); + Optional configurationIssue = diagnoseConfigurationIssue(); + configurationIssue.map(SkipException::new).ifPresent(x -> { + throw x; + }); NetworkConfiguration.printSystemConfiguration(out); } diff --git a/test/jdk/java/net/NetworkInterface/NetworkInterfaceStreamTest.java b/test/jdk/java/net/NetworkInterface/NetworkInterfaceStreamTest.java index 63093e4b9fa..000b802d9a9 100644 --- a/test/jdk/java/net/NetworkInterface/NetworkInterfaceStreamTest.java +++ b/test/jdk/java/net/NetworkInterface/NetworkInterfaceStreamTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,7 @@ * @run testng/othervm -Djava.net.preferIPv4Stack=true NetworkInterfaceStreamTest */ +import org.testng.SkipException; import org.testng.annotations.BeforeTest; import org.testng.annotations.Test; @@ -39,12 +40,13 @@ import java.net.SocketException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.Optional; import java.util.function.Supplier; import java.util.stream.OpTestCase; import java.util.stream.Stream; import java.util.stream.TestData; -import jdk.test.lib.net.IPSupport; +import static jdk.test.lib.net.IPSupport.diagnoseConfigurationIssue; public class NetworkInterfaceStreamTest extends OpTestCase { @@ -52,7 +54,10 @@ public class NetworkInterfaceStreamTest extends OpTestCase { @BeforeTest void setup() { - IPSupport.throwSkippedExceptionIfNonOperational(); + Optional configurationIssue = diagnoseConfigurationIssue(); + configurationIssue.map(SkipException::new).ifPresent(x -> { + throw x; + }); } @Test diff --git a/test/jdk/java/net/NetworkInterface/NullMacAddress.java b/test/jdk/java/net/NetworkInterface/NullMacAddress.java index b31e93d39f2..8161670860e 100644 --- a/test/jdk/java/net/NetworkInterface/NullMacAddress.java +++ b/test/jdk/java/net/NetworkInterface/NullMacAddress.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,8 +31,11 @@ * @run testng/othervm -Djava.net.preferIPv4Stack=true NullMacAddress */ +import org.testng.SkipException; import org.testng.annotations.BeforeTest; import org.testng.annotations.Test; + +import static jdk.test.lib.net.IPSupport.diagnoseConfigurationIssue; import static org.testng.Assert.*; import java.io.UncheckedIOException; @@ -40,14 +43,17 @@ import java.math.BigInteger; import java.net.NetworkInterface; import java.net.SocketException; import java.util.Locale; +import java.util.Optional; -import jdk.test.lib.net.IPSupport; public class NullMacAddress { @BeforeTest void setup() { - IPSupport.throwSkippedExceptionIfNonOperational(); + Optional configurationIssue = diagnoseConfigurationIssue(); + configurationIssue.map(SkipException::new).ifPresent(x -> { + throw x; + }); } @Test diff --git a/test/jdk/java/net/SocketOption/ImmutableOptions.java b/test/jdk/java/net/SocketOption/ImmutableOptions.java index f15734edddc..372a0322a35 100644 --- a/test/jdk/java/net/SocketOption/ImmutableOptions.java +++ b/test/jdk/java/net/SocketOption/ImmutableOptions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * 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,18 +33,23 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.*; +import java.util.Optional; import java.util.Set; -import jdk.test.lib.net.IPSupport; - +import org.testng.SkipException; import org.testng.annotations.BeforeTest; import org.testng.annotations.Test; +import static jdk.test.lib.net.IPSupport.diagnoseConfigurationIssue; + public class ImmutableOptions { @BeforeTest void setupServerSocketFactory() throws IOException { - IPSupport.throwSkippedExceptionIfNonOperational(); + Optional configurationIssue = diagnoseConfigurationIssue(); + configurationIssue.map(SkipException::new).ifPresent(x -> { + throw x; + }); ServerSocket.setSocketFactory(new ServerSocketImplFactory()); } diff --git a/test/jdk/java/net/httpclient/quic/VariableLengthTest.java b/test/jdk/java/net/httpclient/quic/VariableLengthTest.java index cf05b91b18f..6d805fbad5a 100644 --- a/test/jdk/java/net/httpclient/quic/VariableLengthTest.java +++ b/test/jdk/java/net/httpclient/quic/VariableLengthTest.java @@ -21,7 +21,6 @@ * questions. */ import jdk.internal.net.http.quic.VariableLengthEncoder; -import jtreg.SkippedException; import java.io.IOException; import java.nio.ByteBuffer; @@ -31,9 +30,9 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.assertThrows; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; +import org.opentest4j.TestAbortedException; /* * @test @@ -345,7 +344,7 @@ public class VariableLengthTest { case 2 -> ByteBuffer.allocate(capacity).putShort((short) length); case 4 -> ByteBuffer.allocate(capacity).putInt((int) length); case 8 -> ByteBuffer.allocate(capacity).putLong(length); - default -> throw new SkippedException("bad value used for capacity"); + default -> throw new TestAbortedException("bad value used for capacity"); }; } } diff --git a/test/jdk/java/net/spi/InetAddressResolverProvider/LookupPolicyMappingTest.java b/test/jdk/java/net/spi/InetAddressResolverProvider/LookupPolicyMappingTest.java index bbfa9f5555c..13ca6e50aaf 100644 --- a/test/jdk/java/net/spi/InetAddressResolverProvider/LookupPolicyMappingTest.java +++ b/test/jdk/java/net/spi/InetAddressResolverProvider/LookupPolicyMappingTest.java @@ -31,9 +31,11 @@ import static java.net.spi.InetAddressResolver.LookupPolicy.IPV4; import static java.net.spi.InetAddressResolver.LookupPolicy.IPV4_FIRST; import static java.net.spi.InetAddressResolver.LookupPolicy.IPV6; import static java.net.spi.InetAddressResolver.LookupPolicy.IPV6_FIRST; +import static jdk.test.lib.net.IPSupport.diagnoseConfigurationIssue; import jdk.test.lib.net.IPSupport; import jdk.test.lib.NetworkConfiguration; +import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -95,7 +97,7 @@ public class LookupPolicyMappingTest { // Throws SkipException if platform doesn't support required IP address types static void checkPlatformNetworkConfiguration() { - IPSupport.throwSkippedExceptionIfNonOperational(); + diagnoseConfigurationIssue().ifPresent(Assumptions::abort); IPSupport.printPlatformSupport(System.err); NetworkConfiguration.printSystemConfiguration(System.err); // If preferIPv4=true and no IPv4 - skip diff --git a/test/jdk/java/nio/channels/DatagramChannel/AfterDisconnect.java b/test/jdk/java/nio/channels/DatagramChannel/AfterDisconnect.java index 44a34ea3e55..285e98c0fc6 100644 --- a/test/jdk/java/nio/channels/DatagramChannel/AfterDisconnect.java +++ b/test/jdk/java/nio/channels/DatagramChannel/AfterDisconnect.java @@ -49,8 +49,11 @@ import java.util.HashMap; import java.util.Map; import java.util.function.Predicate; +import static jdk.test.lib.net.IPSupport.diagnoseConfigurationIssue; + import jdk.test.lib.net.IPSupport; +import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.Test; import static java.nio.charset.StandardCharsets.UTF_8; @@ -92,7 +95,8 @@ public class AfterDisconnect { @Test public void execute() throws IOException { - IPSupport.throwSkippedExceptionIfNonOperational(); + diagnoseConfigurationIssue().ifPresent(Assumptions::abort); + boolean preferIPv6 = Boolean.getBoolean("java.net.preferIPv6Addresses"); InetAddress lb = InetAddress.getLoopbackAddress(); diff --git a/test/jdk/java/nio/channels/DatagramChannel/SendReceiveMaxSize.java b/test/jdk/java/nio/channels/DatagramChannel/SendReceiveMaxSize.java index cb6e66dd5de..7d41382cf65 100644 --- a/test/jdk/java/nio/channels/DatagramChannel/SendReceiveMaxSize.java +++ b/test/jdk/java/nio/channels/DatagramChannel/SendReceiveMaxSize.java @@ -83,14 +83,14 @@ import static java.net.StandardProtocolFamily.INET; import static java.net.StandardProtocolFamily.INET6; import static java.net.StandardSocketOptions.SO_SNDBUF; import static java.net.StandardSocketOptions.SO_RCVBUF; -import static jdk.test.lib.net.IPSupport.hasIPv4; -import static jdk.test.lib.net.IPSupport.hasIPv6; -import static jdk.test.lib.net.IPSupport.preferIPv4Stack; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.api.Assumptions; + +import static jdk.test.lib.net.IPSupport.*; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -107,7 +107,7 @@ public class SendReceiveMaxSize { @BeforeAll public static void setUp() { - IPSupport.throwSkippedExceptionIfNonOperational(); + diagnoseConfigurationIssue().ifPresent(Assumptions::abort); } public static List testCases() throws IOException { diff --git a/test/jdk/java/nio/channels/etc/LocalSocketAddressType.java b/test/jdk/java/nio/channels/etc/LocalSocketAddressType.java index 60e41af6288..7439c7e436b 100644 --- a/test/jdk/java/nio/channels/etc/LocalSocketAddressType.java +++ b/test/jdk/java/nio/channels/etc/LocalSocketAddressType.java @@ -42,9 +42,9 @@ import java.util.Iterator; import java.util.stream.Stream; import static java.lang.System.out; + import static jdk.test.lib.net.IPSupport.*; -import jtreg.SkippedException; import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.params.ParameterizedTest; @@ -56,12 +56,7 @@ public class LocalSocketAddressType { @BeforeAll() public static void setup() { IPSupport.printPlatformSupport(out); - try { - throwSkippedExceptionIfNonOperational(); - } catch (SkippedException skippedException) { - // jtreg.SkippedException would cause a JUnit test to fail - Assumptions.assumeTrue(false, skippedException.getMessage()); - } + diagnoseConfigurationIssue().ifPresent(Assumptions::abort); } public static Iterator addresses() throws Exception { diff --git a/test/jdk/java/nio/channels/etc/OpenAndConnect.java b/test/jdk/java/nio/channels/etc/OpenAndConnect.java index 0e0347ebb57..ffdbebcc9a5 100644 --- a/test/jdk/java/nio/channels/etc/OpenAndConnect.java +++ b/test/jdk/java/nio/channels/etc/OpenAndConnect.java @@ -42,7 +42,6 @@ import static java.net.StandardProtocolFamily.INET; import static java.net.StandardProtocolFamily.INET6; import static jdk.test.lib.net.IPSupport.*; -import jtreg.SkippedException; import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.params.ParameterizedTest; @@ -89,12 +88,7 @@ public class OpenAndConnect { public static void setup() { NetworkConfiguration.printSystemConfiguration(out); IPSupport.printPlatformSupport(out); - try { - throwSkippedExceptionIfNonOperational(); - } catch (SkippedException skippedException) { - // jtreg.SkippedException would cause a JUnit test to fail - Assumptions.assumeTrue(false, skippedException.getMessage()); - } + diagnoseConfigurationIssue().ifPresent(Assumptions::abort); out.println("IA4LOCAL: " + IA4LOCAL); out.println("IA6LOCAL: " + IA6LOCAL); diff --git a/test/jdk/java/nio/channels/etc/ProtocolFamilies.java b/test/jdk/java/nio/channels/etc/ProtocolFamilies.java index 7f823ff35a8..2419cdd73cf 100644 --- a/test/jdk/java/nio/channels/etc/ProtocolFamilies.java +++ b/test/jdk/java/nio/channels/etc/ProtocolFamilies.java @@ -45,7 +45,6 @@ import static java.net.StandardProtocolFamily.INET; import static java.net.StandardProtocolFamily.INET6; import static jdk.test.lib.net.IPSupport.*; -import jtreg.SkippedException; import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -77,12 +76,7 @@ public class ProtocolFamilies { public static void setup() throws Exception { NetworkConfiguration.printSystemConfiguration(out); IPSupport.printPlatformSupport(out); - try { - throwSkippedExceptionIfNonOperational(); - } catch (SkippedException skippedException) { - // jtreg.SkippedException would cause a JUnit test to fail - Assumptions.assumeTrue(false, skippedException.getMessage()); - } + diagnoseConfigurationIssue().ifPresent(Assumptions::abort); ia4 = getLocalIPv4Address(); ia6 = getLocalIPv6Address(); diff --git a/test/jdk/java/text/Format/DecimalFormat/CloneTest.java b/test/jdk/java/text/Format/DecimalFormat/CloneTest.java index dabdd137f5f..1a6821777be 100644 --- a/test/jdk/java/text/Format/DecimalFormat/CloneTest.java +++ b/test/jdk/java/text/Format/DecimalFormat/CloneTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,8 +29,8 @@ * @run junit/othervm --add-opens=java.base/java.text=ALL-UNNAMED CloneTest */ -import jtreg.SkippedException; import org.junit.jupiter.api.Test; +import org.opentest4j.TestAbortedException; import java.lang.reflect.Field; import java.math.BigDecimal; @@ -78,7 +78,7 @@ public class CloneTest { digitListClass = digitList.getClass(); } catch (ReflectiveOperationException e) { - throw new SkippedException("reflective access in white-box test failed", e); + throw new TestAbortedException("reflective access in white-box test failed", e); } } @@ -91,7 +91,7 @@ public class CloneTest { assertEquals(digitListField.get(original), digitListField.get(dfClone)); } catch (ReflectiveOperationException e) { - throw new SkippedException("reflective access in white-box test failed", e); + throw new TestAbortedException("reflective access in white-box test failed", e); } } diff --git a/test/jdk/jdk/net/ExtendedSocketOption/AsynchronousSocketChannelNAPITest.java b/test/jdk/jdk/net/ExtendedSocketOption/AsynchronousSocketChannelNAPITest.java index d5994ce0add..7fc86ff9f8f 100644 --- a/test/jdk/jdk/net/ExtendedSocketOption/AsynchronousSocketChannelNAPITest.java +++ b/test/jdk/jdk/net/ExtendedSocketOption/AsynchronousSocketChannelNAPITest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @run testng/othervm -Djava.net.preferIPv4Stack=true AsynchronousSocketChannelNAPITest */ -import jdk.test.lib.net.IPSupport; import org.testng.SkipException; import org.testng.annotations.BeforeTest; import org.testng.annotations.Test; @@ -44,7 +43,9 @@ import java.net.SocketException; import java.nio.ByteBuffer; import java.nio.channels.AsynchronousServerSocketChannel; import java.nio.channels.AsynchronousSocketChannel; +import java.util.Optional; +import static jdk.test.lib.net.IPSupport.diagnoseConfigurationIssue; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertThrows; import static org.testng.Assert.assertTrue; @@ -59,7 +60,10 @@ public class AsynchronousSocketChannelNAPITest { @BeforeTest public void setup() throws IOException { - IPSupport.throwSkippedExceptionIfNonOperational(); + Optional configurationIssue = diagnoseConfigurationIssue(); + configurationIssue.map(SkipException::new).ifPresent(x -> { + throw x; + }); try (var sc = AsynchronousSocketChannel.open(); var ssc = AsynchronousServerSocketChannel.open()) { if (!sc.supportedOptions().contains(SO_INCOMING_NAPI_ID)) { diff --git a/test/jdk/jdk/net/ExtendedSocketOption/DatagramChannelNAPITest.java b/test/jdk/jdk/net/ExtendedSocketOption/DatagramChannelNAPITest.java index 24623e52cf1..d38b0c5da88 100644 --- a/test/jdk/jdk/net/ExtendedSocketOption/DatagramChannelNAPITest.java +++ b/test/jdk/jdk/net/ExtendedSocketOption/DatagramChannelNAPITest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 @@ * @run testng/othervm -Djava.net.preferIPv4Stack=true DatagramChannelNAPITest */ -import jdk.test.lib.net.IPSupport; import org.testng.SkipException; import org.testng.annotations.BeforeTest; import org.testng.annotations.Test; @@ -42,7 +41,9 @@ import java.net.InetSocketAddress; import java.net.SocketException; import java.nio.ByteBuffer; import java.nio.channels.DatagramChannel; +import java.util.Optional; +import static jdk.test.lib.net.IPSupport.diagnoseConfigurationIssue; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertThrows; import static org.testng.Assert.assertTrue; @@ -56,7 +57,10 @@ public class DatagramChannelNAPITest { @BeforeTest public void setup() throws IOException { - IPSupport.throwSkippedExceptionIfNonOperational(); + Optional configurationIssue = diagnoseConfigurationIssue(); + configurationIssue.map(SkipException::new).ifPresent(x -> { + throw x; + }); try (var dc = DatagramChannel.open()) { if (!dc.supportedOptions().contains(SO_INCOMING_NAPI_ID)) { assertThrows(UOE, () -> dc.getOption(SO_INCOMING_NAPI_ID)); diff --git a/test/jdk/jdk/net/ExtendedSocketOption/DatagramSocketNAPITest.java b/test/jdk/jdk/net/ExtendedSocketOption/DatagramSocketNAPITest.java index 446b74355b6..1ece78adec1 100644 --- a/test/jdk/jdk/net/ExtendedSocketOption/DatagramSocketNAPITest.java +++ b/test/jdk/jdk/net/ExtendedSocketOption/DatagramSocketNAPITest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * 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,12 +37,13 @@ import java.net.DatagramPacket; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.SocketException; +import java.util.Optional; -import jdk.test.lib.net.IPSupport; import org.testng.SkipException; import org.testng.annotations.BeforeTest; import org.testng.annotations.Test; +import static jdk.test.lib.net.IPSupport.diagnoseConfigurationIssue; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; import static org.testng.Assert.assertThrows; @@ -56,7 +57,10 @@ public class DatagramSocketNAPITest { @BeforeTest public void setup() throws IOException { - IPSupport.throwSkippedExceptionIfNonOperational(); + Optional configurationIssue = diagnoseConfigurationIssue(); + configurationIssue.map(SkipException::new).ifPresent(x -> { + throw x; + }); try (var ds = new DatagramSocket()) { if (!ds.supportedOptions().contains(SO_INCOMING_NAPI_ID)) { assertThrows(UOE, () -> ds.getOption(SO_INCOMING_NAPI_ID)); diff --git a/test/jdk/jdk/net/ExtendedSocketOption/SocketChannelNAPITest.java b/test/jdk/jdk/net/ExtendedSocketOption/SocketChannelNAPITest.java index 898b9725310..b1427d22db6 100644 --- a/test/jdk/jdk/net/ExtendedSocketOption/SocketChannelNAPITest.java +++ b/test/jdk/jdk/net/ExtendedSocketOption/SocketChannelNAPITest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @run testng/othervm -Djava.net.preferIPv4Stack=true SocketChannelNAPITest */ -import jdk.test.lib.net.IPSupport; import org.testng.SkipException; import org.testng.annotations.BeforeTest; import org.testng.annotations.Test; @@ -44,7 +43,9 @@ import java.net.SocketException; import java.nio.ByteBuffer; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; +import java.util.Optional; +import static jdk.test.lib.net.IPSupport.diagnoseConfigurationIssue; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertThrows; import static org.testng.Assert.assertTrue; @@ -59,7 +60,10 @@ public class SocketChannelNAPITest { @BeforeTest public void setup() throws IOException { - IPSupport.throwSkippedExceptionIfNonOperational(); + Optional configurationIssue = diagnoseConfigurationIssue(); + configurationIssue.map(SkipException::new).ifPresent(x -> { + throw x; + }); try (var s = SocketChannel.open(); var ssc = ServerSocketChannel.open()) { if (!s.supportedOptions().contains(SO_INCOMING_NAPI_ID)) { diff --git a/test/jdk/jdk/net/ExtendedSocketOption/SocketNAPITest.java b/test/jdk/jdk/net/ExtendedSocketOption/SocketNAPITest.java index 2947c6ce878..057bf7cc91d 100644 --- a/test/jdk/jdk/net/ExtendedSocketOption/SocketNAPITest.java +++ b/test/jdk/jdk/net/ExtendedSocketOption/SocketNAPITest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * 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,12 +41,13 @@ import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; import java.net.SocketException; +import java.util.Optional; -import jdk.test.lib.net.IPSupport; import org.testng.SkipException; import org.testng.annotations.BeforeTest; import org.testng.annotations.Test; +import static jdk.test.lib.net.IPSupport.diagnoseConfigurationIssue; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertThrows; import static org.testng.Assert.assertTrue; @@ -61,7 +62,10 @@ public class SocketNAPITest { @BeforeTest public void setup() throws IOException { - IPSupport.throwSkippedExceptionIfNonOperational(); + Optional configurationIssue = diagnoseConfigurationIssue(); + configurationIssue.map(SkipException::new).ifPresent(x -> { + throw x; + }); try (var s = new Socket(); var ss = new ServerSocket()) { if (!s.supportedOptions().contains(SO_INCOMING_NAPI_ID)) { From a27e7ca7565ad0e0e4acfae22ebd3f9191966edc Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Wed, 8 Apr 2026 11:43:45 +0000 Subject: [PATCH 204/359] 8381793: Clean up unused ProblemList-coh.txt Reviewed-by: dholmes --- test/jdk/ProblemList-coh.txt | 41 ------------------------------------ 1 file changed, 41 deletions(-) diff --git a/test/jdk/ProblemList-coh.txt b/test/jdk/ProblemList-coh.txt index b3bddb0c9f4..e69de29bb2d 100644 --- a/test/jdk/ProblemList-coh.txt +++ b/test/jdk/ProblemList-coh.txt @@ -1,41 +0,0 @@ -# -# Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# - -############################################################################# -# -# List of quarantined tests for testing with -XX:+UseCompactObjectHeaders -# -############################################################################# - -############################################################################# - -# Preview project specific failures go here at the end of the file. -# -# These are NOT failures that occur with the '--enable-preview' option -# specified; those go in the appropriate ProblemList-enable-preview.txt file. -# These are failures that occur WITHOUT the '--enable-preview' option -# specified AND occur because of some issue with preview project code, -# in either implementation or test code. - -############################################################################# - From 2ff1a29212f7767ff9d22050c39d573d59821dfb Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Wed, 8 Apr 2026 11:44:12 +0000 Subject: [PATCH 205/359] 8381703: G1: Racy re-read of G1CMRootRegion::num_remaining_regions causes assertion failures Reviewed-by: iwalulya, ayang --- src/hotspot/share/gc/g1/g1ConcurrentMark.cpp | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp index 4c646c82b8a..a72d5fc5cf9 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp @@ -1131,23 +1131,34 @@ bool G1ConcurrentMark::scan_root_regions(WorkerThreads* workers, bool concurrent // // Concurrent gc threads enter an STS when starting the task, so they stop, then // continue after that safepoint. - bool do_scan = !root_regions()->work_completed() && !has_root_region_scan_aborted(); + // + // Must not use G1CMRootMemRegions::work_completed() here because we need to get a + // consistent view of the value containing the number of remaining regions across the + // usages below. The safepoint/gc may already be running and modifying it + // while this code is still executing. + uint num_remaining = root_regions()->num_remaining_regions(); + bool do_scan = num_remaining > 0 && !has_root_region_scan_aborted(); if (do_scan) { // Assign one worker to each root-region but subject to the max constraint. // The constraint is also important to avoid accesses beyond the allocated per-worker // marking helper data structures. We might get passed different WorkerThreads with // different number of threads (potential worker ids) than helper data structures when // completing this work during GC. - const uint num_workers = MIN2(root_regions()->num_remaining_regions(), + const uint num_workers = MIN2(num_remaining, _max_concurrent_workers); assert(num_workers > 0, "no more remaining root regions to process"); G1CMRootRegionScanTask task(this, concurrent); log_debug(gc, ergo)("Running %s using %u workers for %u work units.", - task.name(), num_workers, root_regions()->num_remaining_regions()); + task.name(), num_workers, num_remaining); workers->run_task(&task, num_workers); } + // At the end of this method, we can re-read num_remaining() in the assert: either + // we got non-zero above and we processed all root regions (and it must be zero + // after the worker task synchronization) or it had already been zero. We also + // can't have started another concurrent cycle that could have set it to something else + // while still in the concurrent cycle (if called concurrently). assert_root_region_scan_completed_or_aborted(); return do_scan; From 28a91d0e3ab630be8893483a71b9198340677408 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20H=C3=A4ssig?= Date: Wed, 8 Apr 2026 12:00:42 +0000 Subject: [PATCH 206/359] 8381795: AArch64: Optimized build is broken after JDK-8381003 Reviewed-by: chagedorn, jsikstro, eastigeevich --- src/hotspot/os_cpu/linux_aarch64/icache_linux_aarch64.cpp | 2 +- src/hotspot/os_cpu/linux_aarch64/icache_linux_aarch64.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/os_cpu/linux_aarch64/icache_linux_aarch64.cpp b/src/hotspot/os_cpu/linux_aarch64/icache_linux_aarch64.cpp index 41cad5af325..11911a48e06 100644 --- a/src/hotspot/os_cpu/linux_aarch64/icache_linux_aarch64.cpp +++ b/src/hotspot/os_cpu/linux_aarch64/icache_linux_aarch64.cpp @@ -25,4 +25,4 @@ #include "runtime/icache.hpp" #include "utilities/globalDefinitions.hpp" -NOT_PRODUCT(THREAD_LOCAL AArch64ICacheInvalidationContext* AArch64ICacheInvalidationContext::_current_context = nullptr;) +DEBUG_ONLY(THREAD_LOCAL AArch64ICacheInvalidationContext* AArch64ICacheInvalidationContext::_current_context = nullptr;) diff --git a/src/hotspot/os_cpu/linux_aarch64/icache_linux_aarch64.hpp b/src/hotspot/os_cpu/linux_aarch64/icache_linux_aarch64.hpp index 444b3c3ebd6..5121a875701 100644 --- a/src/hotspot/os_cpu/linux_aarch64/icache_linux_aarch64.hpp +++ b/src/hotspot/os_cpu/linux_aarch64/icache_linux_aarch64.hpp @@ -82,7 +82,7 @@ class AArch64ICacheInvalidationContext : StackObj { } ~AArch64ICacheInvalidationContext() { - NOT_PRODUCT(_current_context = nullptr); + DEBUG_ONLY(_current_context = nullptr); if (!_has_modified_code || !UseSingleICacheInvalidation) { return; From cc1c427f476601d33ed13307f5a1febc0100d53e Mon Sep 17 00:00:00 2001 From: Erik Gahlin Date: Wed, 8 Apr 2026 12:19:07 +0000 Subject: [PATCH 207/359] 8380755: jdk/jfr/event/gc/heapsummary/TestHeapSummaryEventG1.java fails gcId should be increasing Reviewed-by: dholmes, mgronlun --- .../gc/heapsummary/HeapSummaryEventAllGcs.java | 4 ++-- test/lib/jdk/test/lib/jfr/Events.java | 17 ++++++++++++++++- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/test/jdk/jdk/jfr/event/gc/heapsummary/HeapSummaryEventAllGcs.java b/test/jdk/jdk/jfr/event/gc/heapsummary/HeapSummaryEventAllGcs.java index 2baf87eae31..178d796e1b0 100644 --- a/test/jdk/jdk/jfr/event/gc/heapsummary/HeapSummaryEventAllGcs.java +++ b/test/jdk/jdk/jfr/event/gc/heapsummary/HeapSummaryEventAllGcs.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ public class HeapSummaryEventAllGcs { GCHelper.callSystemGc(5, true); recording.stop(); - List allEvents = Events.fromRecording(recording); + List allEvents = Events.fromRecordingOrdered(recording); if (!checkCollectors(allEvents, expectedYoungCollector, expectedOldCollector)) { return; } diff --git a/test/lib/jdk/test/lib/jfr/Events.java b/test/lib/jdk/test/lib/jfr/Events.java index 8bbf22ca63a..03e1e39cfe3 100644 --- a/test/lib/jdk/test/lib/jfr/Events.java +++ b/test/lib/jdk/test/lib/jfr/Events.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2026, Oracle and/or its affiliates. All rights reserved. * 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.io.IOException; import java.nio.file.Path; import java.time.Duration; import java.time.Instant; +import java.util.Comparator; import java.util.List; import jdk.jfr.AnnotationElement; @@ -280,6 +281,20 @@ public class Events { return RecordingFile.readAllEvents(makeCopy(recording)); } + /** + * Creates a list of events from a recording, ordered by the end time. + * + * @param recording recording, not {@code null} + * @return a list, not null + * @throws IOException if an event set could not be created due to I/O + * errors. + */ + public static List fromRecordingOrdered(Recording recording) throws IOException { + List events = fromRecording(recording); + events.sort(Comparator.comparing(RecordedEvent::getEndTime)); + return events; + } + public static RecordingFile copyTo(Recording r) throws IOException { return new RecordingFile(makeCopy(r)); } From 988ec86dc6137d3798030a188bb9b214120a553d Mon Sep 17 00:00:00 2001 From: Serhiy Sachkov Date: Wed, 8 Apr 2026 13:02:51 +0000 Subject: [PATCH 208/359] 8381838: java/net/DatagramSocket/SendReceiveMaxSize.java fails to compile after JDK-8381008 Reviewed-by: ayang, jpai, dfuchs --- test/jdk/java/net/DatagramSocket/SendReceiveMaxSize.java | 1 + 1 file changed, 1 insertion(+) diff --git a/test/jdk/java/net/DatagramSocket/SendReceiveMaxSize.java b/test/jdk/java/net/DatagramSocket/SendReceiveMaxSize.java index 2b68af9cbf2..36eae0b5c32 100644 --- a/test/jdk/java/net/DatagramSocket/SendReceiveMaxSize.java +++ b/test/jdk/java/net/DatagramSocket/SendReceiveMaxSize.java @@ -87,6 +87,7 @@ import jdk.test.lib.RandomFactory; import jdk.test.lib.Platform; +import jdk.test.lib.net.IPSupport; import org.testng.SkipException; import org.testng.annotations.BeforeTest; import org.testng.annotations.DataProvider; From 52a54dacb82e172192d143fb44cf53c299e6b08b Mon Sep 17 00:00:00 2001 From: Daniel Fuchs Date: Wed, 8 Apr 2026 15:41:27 +0000 Subject: [PATCH 209/359] 8381616: Refactor various java/net/*Socket*/ TestNG tests to use JUnit Reviewed-by: alanb --- .../net/DatagramSocketImpl/TestCreate.java | 9 +- .../TestDefaultBehavior.java | 38 ++--- .../java/net/MulticastSocket/Constructor.java | 8 +- .../net/MulticastSocket/IPMulticastIF.java | 75 ++++----- .../net/MulticastSocket/SendPortZero.java | 49 +++--- .../MulticastSocket/SetLoopbackOption.java | 15 +- test/jdk/java/net/Socket/ConnectionReset.java | 117 +++++++------- test/jdk/java/net/Socket/UdpSocket.java | 8 +- test/jdk/java/net/SocketImpl/BadUsages.java | 144 +++++++++++------- .../net/SocketImpl/ImplSupportedOptions.java | 51 ++++--- .../SocketImpl/SocketImplCombinations.java | 123 ++++++++++----- .../net/SocketImpl/TestDefaultBehavior.java | 38 ++--- 12 files changed, 374 insertions(+), 301 deletions(-) diff --git a/test/jdk/java/net/DatagramSocketImpl/TestCreate.java b/test/jdk/java/net/DatagramSocketImpl/TestCreate.java index 81772074ae2..8d526cf0530 100644 --- a/test/jdk/java/net/DatagramSocketImpl/TestCreate.java +++ b/test/jdk/java/net/DatagramSocketImpl/TestCreate.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,10 +25,9 @@ * @test * @bug 8238231 * @summary test that DatagramSocket calls java.net.DatagramSocketImpl::create - * @run testng/othervm TestCreate + * @run junit/othervm ${test.main.class} */ -import org.testng.annotations.Test; import java.io.IOException; import java.net.DatagramPacket; @@ -44,7 +43,9 @@ import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; -import static org.testng.Assert.assertTrue; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertTrue; public class TestCreate { diff --git a/test/jdk/java/net/DatagramSocketImpl/TestDefaultBehavior.java b/test/jdk/java/net/DatagramSocketImpl/TestDefaultBehavior.java index 2e223f1820c..c4e88b6a2c0 100644 --- a/test/jdk/java/net/DatagramSocketImpl/TestDefaultBehavior.java +++ b/test/jdk/java/net/DatagramSocketImpl/TestDefaultBehavior.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,7 @@ * @test * @bug 8224477 * @summary Basic test for java.net.DatagramSocketImpl default behavior - * @run testng TestDefaultBehavior + * @run junit ${test.main.class} */ import java.io.IOException; @@ -36,11 +36,13 @@ import java.net.NetworkInterface; import java.net.SocketAddress; import java.net.SocketOption; import java.util.Set; -import org.testng.annotations.Test; import static java.lang.Boolean.*; import static java.net.StandardSocketOptions.*; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.expectThrows; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + public class TestDefaultBehavior { @@ -51,21 +53,21 @@ public class TestDefaultBehavior { public void datagramSocketImpl() { CustomDatagramSocketImpl dsi = new CustomDatagramSocketImpl(); - assertEquals(dsi.supportedOptions().size(), 0); + assertEquals(0, dsi.supportedOptions().size()); - expectThrows(NPE, () -> dsi.setOption(null, null)); - expectThrows(NPE, () -> dsi.setOption(null, 1)); - expectThrows(UOE, () -> dsi.setOption(SO_RCVBUF, 100)); - expectThrows(UOE, () -> dsi.setOption(SO_KEEPALIVE, TRUE)); - expectThrows(UOE, () -> dsi.setOption(SO_KEEPALIVE, FALSE)); - expectThrows(UOE, () -> dsi.setOption(FAKE_SOCK_OPT, TRUE)); - expectThrows(UOE, () -> dsi.setOption(FAKE_SOCK_OPT, FALSE)); - expectThrows(UOE, () -> dsi.setOption(SO_KEEPALIVE, TRUE)); + assertThrows(NPE, () -> dsi.setOption(null, null)); + assertThrows(NPE, () -> dsi.setOption(null, 1)); + assertThrows(UOE, () -> dsi.setOption(SO_RCVBUF, 100)); + assertThrows(UOE, () -> dsi.setOption(SO_KEEPALIVE, TRUE)); + assertThrows(UOE, () -> dsi.setOption(SO_KEEPALIVE, FALSE)); + assertThrows(UOE, () -> dsi.setOption(FAKE_SOCK_OPT, TRUE)); + assertThrows(UOE, () -> dsi.setOption(FAKE_SOCK_OPT, FALSE)); + assertThrows(UOE, () -> dsi.setOption(SO_KEEPALIVE, TRUE)); - expectThrows(NPE, () -> dsi.getOption(null)); - expectThrows(UOE, () -> dsi.getOption(SO_RCVBUF)); - expectThrows(UOE, () -> dsi.getOption(SO_KEEPALIVE)); - expectThrows(UOE, () -> dsi.getOption(FAKE_SOCK_OPT)); + assertThrows(NPE, () -> dsi.getOption(null)); + assertThrows(UOE, () -> dsi.getOption(SO_RCVBUF)); + assertThrows(UOE, () -> dsi.getOption(SO_KEEPALIVE)); + assertThrows(UOE, () -> dsi.getOption(FAKE_SOCK_OPT)); } static final SocketOption FAKE_SOCK_OPT = new SocketOption<>() { diff --git a/test/jdk/java/net/MulticastSocket/Constructor.java b/test/jdk/java/net/MulticastSocket/Constructor.java index 6a765cc2f04..296fe1ab105 100644 --- a/test/jdk/java/net/MulticastSocket/Constructor.java +++ b/test/jdk/java/net/MulticastSocket/Constructor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * 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,15 +24,15 @@ /* @test * @bug 8243999 * @summary Checks to ensure that Multicast constructors behave as expected - * @run testng Constructor + * @run junit ${test.main.class} */ -import org.testng.annotations.Test; import java.io.IOException; import java.net.MulticastSocket; -import static org.testng.Assert.assertTrue; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertTrue; public class Constructor { @Test diff --git a/test/jdk/java/net/MulticastSocket/IPMulticastIF.java b/test/jdk/java/net/MulticastSocket/IPMulticastIF.java index 6f6e7dd1942..3d526c9b3d3 100644 --- a/test/jdk/java/net/MulticastSocket/IPMulticastIF.java +++ b/test/jdk/java/net/MulticastSocket/IPMulticastIF.java @@ -27,44 +27,41 @@ import java.net.MulticastSocket; import java.net.NetworkInterface; import java.util.ArrayList; import java.util.List; -import java.util.Optional; import jdk.test.lib.NetworkConfiguration; -import org.testng.SkipException; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import static jdk.test.lib.net.IPSupport.diagnoseConfigurationIssue; import static java.lang.String.format; import static java.lang.System.out; import static java.net.StandardSocketOptions.IP_MULTICAST_IF; import static java.util.stream.Collectors.toList; -import static jdk.test.lib.net.IPSupport.diagnoseConfigurationIssue; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; + +import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; /** * @test * @bug 8236441 * @summary Bound MulticastSocket fails when setting outbound interface on Windows * @library /test/lib - * @run testng IPMulticastIF - * @run testng/othervm -Djava.net.preferIPv4Stack=true IPMulticastIF - * @run testng/othervm -Djava.net.preferIPv6Addresses=true IPMulticastIF - * @run testng/othervm -Djava.net.preferIPv6Addresses=true -Djava.net.preferIPv4Stack=true IPMulticastIF + * @run junit ${test.main.class} + * @run junit/othervm -Djava.net.preferIPv4Stack=true ${test.main.class} + * @run junit/othervm -Djava.net.preferIPv6Addresses=true ${test.main.class} + * @run junit/othervm -Djava.net.preferIPv6Addresses=true -Djava.net.preferIPv4Stack=true ${test.main.class} */ public class IPMulticastIF { - @BeforeTest - public void sanity() { - Optional configurationIssue = diagnoseConfigurationIssue(); - configurationIssue.map(SkipException::new).ifPresent(x -> { - throw x; - }); + @BeforeAll + public static void sanity() { + diagnoseConfigurationIssue().ifPresent(Assumptions::abort); NetworkConfiguration.printSystemConfiguration(out); } - @DataProvider(name = "scenarios") - public Object[][] positive() throws Exception { + public static Object[][] positive() throws Exception { List addrs = List.of(InetAddress.getLocalHost(), InetAddress.getLoopbackAddress()); List list = new ArrayList<>(); @@ -81,8 +78,7 @@ public class IPMulticastIF { return list.stream().toArray(Object[][]::new); } - @DataProvider(name = "interfaces") - public Object[][] interfaces() throws Exception { + public static Object[][] interfaces() throws Exception { List list = new ArrayList<>(); NetworkConfiguration nc = NetworkConfiguration.probe(); nc.multicastInterfaces(true) @@ -92,7 +88,8 @@ public class IPMulticastIF { return list.stream().toArray(Object[][]::new); } - @Test(dataProvider = "scenarios") + @ParameterizedTest + @MethodSource("positive") public void testSetGetInterfaceBound(InetSocketAddress bindAddr, NetworkInterface nif) throws Exception { @@ -100,11 +97,12 @@ public class IPMulticastIF { try (MulticastSocket ms = new MulticastSocket(bindAddr)) { ms.setNetworkInterface(nif); NetworkInterface msNetIf = ms.getNetworkInterface(); - assertEquals(msNetIf, nif); + assertEquals(nif, msNetIf); } } - @Test(dataProvider = "interfaces") + @ParameterizedTest + @MethodSource("interfaces") public void testSetGetInterfaceUnbound(NetworkInterface nif) throws Exception { @@ -112,11 +110,12 @@ public class IPMulticastIF { try (MulticastSocket ms = new MulticastSocket()) { ms.setNetworkInterface(nif); NetworkInterface msNetIf = ms.getNetworkInterface(); - assertEquals(msNetIf, nif); + assertEquals(nif, msNetIf); } } - @Test(dataProvider = "scenarios") + @ParameterizedTest + @MethodSource("positive") public void testSetGetOptionBound(InetSocketAddress bindAddr, NetworkInterface nif) throws Exception { @@ -124,11 +123,12 @@ public class IPMulticastIF { try (MulticastSocket ms = new MulticastSocket(bindAddr)) { ms.setOption(IP_MULTICAST_IF, nif); NetworkInterface msNetIf = ms.getOption(IP_MULTICAST_IF); - assertEquals(msNetIf, nif); + assertEquals(nif, msNetIf); } } - @Test(dataProvider = "interfaces") + @ParameterizedTest + @MethodSource("interfaces") public void testSetGetOptionUnbound(NetworkInterface nif) throws Exception { @@ -136,21 +136,21 @@ public class IPMulticastIF { try (MulticastSocket ms = new MulticastSocket()) { ms.setOption(IP_MULTICAST_IF, nif); NetworkInterface msNetIf = ms.getOption(IP_MULTICAST_IF); - assertEquals(msNetIf, nif); + assertEquals(nif, msNetIf); } } // -- get without set - @DataProvider(name = "bindAddresses") - public Object[][] bindAddresses() throws Exception { + public static Object[][] bindAddresses() throws Exception { return new Object[][] { { new InetSocketAddress(InetAddress.getLocalHost(), 0) }, { new InetSocketAddress(InetAddress.getLoopbackAddress(), 0) }, }; } - @Test(dataProvider = "bindAddresses") + @ParameterizedTest + @MethodSource("bindAddresses") public void testGetInterfaceBound(InetSocketAddress bindAddr) throws Exception { @@ -168,13 +168,14 @@ public class IPMulticastIF { } } - @Test(dataProvider = "bindAddresses") + @ParameterizedTest + @MethodSource("bindAddresses") public void testGetOptionBound(InetSocketAddress bindAddr) throws Exception { out.println(format("\n\n--- testGetOptionBound bindAddr=[%s]", bindAddr)); try (MulticastSocket ms = new MulticastSocket(bindAddr)) { - assertEquals(ms.getOption(IP_MULTICAST_IF), null); + assertEquals(null, ms.getOption(IP_MULTICAST_IF)); } } @@ -182,7 +183,7 @@ public class IPMulticastIF { public void testGetOptionUnbound() throws Exception { out.println("\n\n--- testGetOptionUnbound "); try (MulticastSocket ms = new MulticastSocket()) { - assertEquals(ms.getOption(IP_MULTICAST_IF), null); + assertEquals(null, ms.getOption(IP_MULTICAST_IF)); } } @@ -190,7 +191,7 @@ public class IPMulticastIF { // that represent any local address. static void assertPlaceHolder(NetworkInterface nif) { List addrs = nif.inetAddresses().collect(toList()); - assertEquals(addrs.size(), 1); + assertEquals(1, addrs.size()); assertTrue(addrs.get(0).isAnyLocalAddress()); } } diff --git a/test/jdk/java/net/MulticastSocket/SendPortZero.java b/test/jdk/java/net/MulticastSocket/SendPortZero.java index 0d8acd86c8c..ab06dfdd45d 100644 --- a/test/jdk/java/net/MulticastSocket/SendPortZero.java +++ b/test/jdk/java/net/MulticastSocket/SendPortZero.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * 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,39 +21,39 @@ * questions. */ -import org.testng.annotations.AfterTest; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import java.io.IOException; import java.net.DatagramPacket; import java.net.MulticastSocket; import java.net.InetAddress; import java.net.InetSocketAddress; -import java.net.MulticastSocket; import java.net.SocketException; -import java.nio.channels.DatagramChannel; -import static org.testng.Assert.assertThrows; +import org.junit.jupiter.api.AfterAll; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; /* * @test * @bug 8243408 * @summary Check that MulticastSocket throws expected * Exception when sending a DatagramPacket with port 0 - * @run testng/othervm SendPortZero + * @run junit/othervm ${test.main.class} */ public class SendPortZero { - private InetAddress loopbackAddr, wildcardAddr; - private MulticastSocket multicastSocket; - private DatagramPacket loopbackZeroPkt, wildcardZeroPkt, wildcardValidPkt; + private static InetAddress loopbackAddr, wildcardAddr; + private static MulticastSocket multicastSocket; + private static DatagramPacket loopbackZeroPkt, wildcardZeroPkt, wildcardValidPkt; private static final Class SE = SocketException.class; - @BeforeTest - public void setUp() throws IOException { + @BeforeAll + public static void setUp() throws IOException { multicastSocket = new MulticastSocket(); byte[] buf = "test".getBytes(); @@ -80,23 +80,26 @@ public class SendPortZero { wildcardValidPkt.setPort(multicastSocket.getLocalPort()); } - @DataProvider(name = "data") - public Object[][] variants() { + public static Object[][] testCases() throws IOException { return new Object[][]{ - { multicastSocket, loopbackZeroPkt }, - { multicastSocket, wildcardZeroPkt }, + { new MulticastSocket(), loopbackZeroPkt }, + { new MulticastSocket(), wildcardZeroPkt }, // Not currently tested. See JDK-8236807 - //{ multicastSocket, wildcardValidPkt } + //{ new MulticastSocket(), wildcardValidPkt } }; } - @Test(dataProvider = "data") + @ParameterizedTest + @MethodSource("testCases") public void testSend(MulticastSocket ms, DatagramPacket pkt) { - assertThrows(SE, () -> ms.send(pkt)); + try (ms) { + assertFalse(ms.isClosed()); + assertThrows(SE, () -> ms.send(pkt)); + } } - @AfterTest - public void tearDown() { + @AfterAll + public static void tearDown() { multicastSocket.close(); } } diff --git a/test/jdk/java/net/MulticastSocket/SetLoopbackOption.java b/test/jdk/java/net/MulticastSocket/SetLoopbackOption.java index ed831cfbdf7..8185c71345d 100644 --- a/test/jdk/java/net/MulticastSocket/SetLoopbackOption.java +++ b/test/jdk/java/net/MulticastSocket/SetLoopbackOption.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,9 +28,9 @@ * return the correct result for StandardSocketOptions.IP_MULTICAST_LOOP. * The test sets a DatagramSocketImplFactory and needs to run in /othervm * mode. - * @run testng/othervm SetLoopbackOption - * @run testng/othervm -Djava.net.preferIPv4Stack=true SetLoopbackOption - * @run testng/othervm -Djava.net.preferIPv6Addresses=true SetLoopbackOption + * @run junit/othervm ${test.main.class} + * @run junit/othervm -Djava.net.preferIPv4Stack=true ${test.main.class} + * @run junit/othervm -Djava.net.preferIPv6Addresses=true ${test.main.class} */ import java.io.FileDescriptor; @@ -52,11 +52,12 @@ import java.util.HashMap; import java.util.Map; import java.util.Set; -import org.testng.annotations.Test; -import static org.testng.Assert.*; - import static java.lang.System.out; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class SetLoopbackOption { final InetAddress loopbackAddress = InetAddress.getLoopbackAddress(); diff --git a/test/jdk/java/net/Socket/ConnectionReset.java b/test/jdk/java/net/Socket/ConnectionReset.java index 41be61ac7e1..630bd61a606 100644 --- a/test/jdk/java/net/Socket/ConnectionReset.java +++ b/test/jdk/java/net/Socket/ConnectionReset.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /** * @test - * @run testng ConnectionReset + * @run junit ${test.main.class} * @summary Test behavior of read and available when a connection is reset */ @@ -34,10 +34,13 @@ import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; -import org.testng.annotations.Test; -import static org.testng.Assert.*; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; -@Test public class ConnectionReset { static final int REPEAT_COUNT = 5; @@ -45,25 +48,23 @@ public class ConnectionReset { /** * Tests available before read when there are no bytes to read */ + @Test public void testAvailableBeforeRead1() throws IOException { - System.out.println("testAvailableBeforeRead1"); withResetConnection(null, s -> { InputStream in = s.getInputStream(); for (int i=0; i %d%n", bytesAvailable); - assertTrue(bytesAvailable == 0); - try { + System.err.format("available => %d%n", bytesAvailable); + assertEquals(0, bytesAvailable); + IOException ioe = assertThrows(IOException.class, () -> { int bytesRead = in.read(); if (bytesRead == -1) { - System.out.println("read => EOF"); + System.err.println("read => EOF"); } else { - System.out.println("read => 1 byte"); + System.err.println("read => 1 byte"); } - assertTrue(false); - } catch (IOException ioe) { - System.out.format("read => %s (expected)%n", ioe); - } + }); + System.err.format("read => %s (expected)%n", ioe); } }); } @@ -71,28 +72,25 @@ public class ConnectionReset { /** * Tests available before read when there are bytes to read */ + @Test public void testAvailableBeforeRead2() throws IOException { - System.out.println("testAvailableBeforeRead2"); byte[] data = { 1, 2, 3 }; withResetConnection(data, s -> { InputStream in = s.getInputStream(); int remaining = data.length; for (int i=0; i %d%n", bytesAvailable); + System.err.format("available => %d%n", bytesAvailable); assertTrue(bytesAvailable <= remaining); try { int bytesRead = in.read(); - if (bytesRead == -1) { - System.out.println("read => EOF"); - assertTrue(false); - } else { - System.out.println("read => 1 byte"); - assertTrue(remaining > 0); - remaining--; - } + assertNotEquals(-1, bytesRead, "EOF not expected"); + + System.err.println("read => 1 byte"); + assertTrue(remaining > 0); + remaining--; } catch (IOException ioe) { - System.out.format("read => %s%n", ioe); + System.err.format("read => %s%n", ioe); remaining = 0; } } @@ -102,25 +100,24 @@ public class ConnectionReset { /** * Tests read before available when there are no bytes to read */ + @Test public void testReadBeforeAvailable1() throws IOException { - System.out.println("testReadBeforeAvailable1"); withResetConnection(null, s -> { InputStream in = s.getInputStream(); for (int i=0; i { int bytesRead = in.read(); if (bytesRead == -1) { - System.out.println("read => EOF"); + System.err.println("read => EOF"); } else { - System.out.println("read => 1 byte"); + System.err.println("read => 1 byte"); } - assertTrue(false); - } catch (IOException ioe) { - System.out.format("read => %s (expected)%n", ioe); - } + }); + System.err.format("read => %s (expected)%n", ioe); + int bytesAvailable = in.available(); - System.out.format("available => %d%n", bytesAvailable); - assertTrue(bytesAvailable == 0); + System.err.format("available => %d%n", bytesAvailable); + assertEquals(0, bytesAvailable); } }); } @@ -128,8 +125,8 @@ public class ConnectionReset { /** * Tests read before available when there are bytes to read */ + @Test public void testReadBeforeAvailable2() throws IOException { - System.out.println("testReadBeforeAvailable2"); byte[] data = { 1, 2, 3 }; withResetConnection(data, s -> { InputStream in = s.getInputStream(); @@ -137,20 +134,17 @@ public class ConnectionReset { for (int i=0; i EOF"); - assertTrue(false); - } else { - System.out.println("read => 1 byte"); - assertTrue(remaining > 0); - remaining--; - } + assertNotEquals(-1, bytesRead, "EOF not expected"); + + System.err.println("read => 1 byte"); + assertTrue(remaining > 0); + remaining--; } catch (IOException ioe) { - System.out.format("read => %s%n", ioe); + System.err.format("read => %s%n", ioe); remaining = 0; } int bytesAvailable = in.available(); - System.out.format("available => %d%n", bytesAvailable); + System.err.format("available => %d%n", bytesAvailable); assertTrue(bytesAvailable <= remaining); } }); @@ -159,31 +153,22 @@ public class ConnectionReset { /** * Tests available and read on a socket closed after connection reset */ + @Test public void testAfterClose() throws IOException { - System.out.println("testAfterClose"); withResetConnection(null, s -> { InputStream in = s.getInputStream(); - try { - in.read(); - assertTrue(false); - } catch (IOException ioe) { - // expected - } + assertThrows(IOException.class, () -> in.read()); s.close(); - try { + IOException ioe = assertThrows(IOException.class, () -> { int bytesAvailable = in.available(); - System.out.format("available => %d%n", bytesAvailable); - assertTrue(false); - } catch (IOException ioe) { - System.out.format("available => %s (expected)%n", ioe); - } - try { + System.err.format("available => %d%n", bytesAvailable); + }); + System.err.format("available => %s (expected)%n", ioe); + ioe = assertThrows(IOException.class, () -> { int n = in.read(); - System.out.format("read => %d%n", n); - assertTrue(false); - } catch (IOException ioe) { - System.out.format("read => %s (expected)%n", ioe); - } + System.err.format("read => %d%n", n); + }); + System.err.format("read => %s (expected)%n", ioe); }); } diff --git a/test/jdk/java/net/Socket/UdpSocket.java b/test/jdk/java/net/Socket/UdpSocket.java index 7e93343cefb..47bf09d1334 100644 --- a/test/jdk/java/net/Socket/UdpSocket.java +++ b/test/jdk/java/net/Socket/UdpSocket.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * 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,13 +24,13 @@ import java.net.InetAddress; import java.net.Socket; -import org.testng.annotations.Test; -import static org.testng.Assert.fail; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.fail; /* * @test * @summary Basic test for the UDP sockets through the java.net.Socket constructors - * @run testng UdpSocket + * @run junit ${test.main.class} */ public class UdpSocket { diff --git a/test/jdk/java/net/SocketImpl/BadUsages.java b/test/jdk/java/net/SocketImpl/BadUsages.java index b5d85708dde..ca0ab6fe71e 100644 --- a/test/jdk/java/net/SocketImpl/BadUsages.java +++ b/test/jdk/java/net/SocketImpl/BadUsages.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * 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 8221481 * @summary Test the platform SocketImpl when used in unintended ways * @compile/module=java.base java/net/PlatformSocketImpl.java - * @run testng/othervm BadUsages + * @run junit/othervm ${test.main.class} */ import java.io.IOException; @@ -41,8 +41,8 @@ import java.net.StandardSocketOptions; import java.net.PlatformSocketImpl; // test helper -import org.testng.annotations.Test; -import static org.testng.Assert.*; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; /** * SocketImpl does not specify how the SocketImpl behaves when used in ways @@ -54,74 +54,80 @@ import static org.testng.Assert.*; * throws reasonable exceptions, for these scenarios. */ -@Test public class BadUsages { /** * Test create when already created. */ + @Test public void testCreate1() throws IOException { try (var impl = new PlatformSocketImpl(false)) { impl.create(true); - expectThrows(IOException.class, () -> impl.create(true)); + assertThrows(IOException.class, () -> impl.create(true)); } } /** * Test create when closed. */ + @Test public void testCreate2() throws IOException { var impl = new PlatformSocketImpl(false); impl.close(); - expectThrows(IOException.class, () -> impl.create(true)); + assertThrows(IOException.class, () -> impl.create(true)); } /** * Test create when not a stream socket. */ + @Test public void testCreate3() throws IOException { try (var impl = new PlatformSocketImpl(false)) { - expectThrows(IOException.class, () -> impl.create(false)); + assertThrows(IOException.class, () -> impl.create(false)); } } /** * Test connect when not created. */ + @Test public void testConnect1() throws IOException { try (var ss = new ServerSocket(0)) { var impl = new PlatformSocketImpl(false); var address = ss.getInetAddress(); int port = ss.getLocalPort(); - expectThrows(IOException.class, () -> impl.connect(address, port)); + assertThrows(IOException.class, () -> impl.connect(address, port)); } } /** * Test connect with unsupported address type. */ + @Test public void testConnect2() throws IOException { try (var impl = new PlatformSocketImpl(false)) { impl.create(true); var remote = new SocketAddress() { }; - expectThrows(IOException.class, () -> impl.connect(remote, 0)); + assertThrows(IOException.class, () -> impl.connect(remote, 0)); } } /** * Test connect with an unresolved address. */ + @Test public void testConnect3() throws IOException { try (var impl = new PlatformSocketImpl(false)) { impl.create(true); var remote = new InetSocketAddress("blah-blah.blah-blah", 80); - expectThrows(IOException.class, () -> impl.connect(remote, 0)); + assertThrows(IOException.class, () -> impl.connect(remote, 0)); } } /** * Test connect when already connected. */ + @Test public void testConnect4() throws IOException { try (var ss = new ServerSocket(); var impl = new PlatformSocketImpl(false)) { @@ -130,47 +136,51 @@ public class BadUsages { impl.create(true); int port = ss.getLocalPort(); impl.connect(loopback, port); - expectThrows(IOException.class, () -> impl.connect(loopback, port)); + assertThrows(IOException.class, () -> impl.connect(loopback, port)); } } /** * Test connect when closed. */ + @Test public void testConnect5() throws IOException { try (var ss = new ServerSocket(0)) { var impl = new PlatformSocketImpl(false); impl.close(); String host = ss.getInetAddress().getHostAddress(); int port = ss.getLocalPort(); - expectThrows(IOException.class, () -> impl.connect(host, port)); + assertThrows(IOException.class, () -> impl.connect(host, port)); } } /** * Test bind when not created. */ + @Test public void testBind1() throws IOException { var impl = new PlatformSocketImpl(false); var loopback = InetAddress.getLoopbackAddress(); - expectThrows(IOException.class, () -> impl.bind(loopback, 0)); + assertThrows(IOException.class, () -> impl.bind(loopback, 0)); } /** * Test bind when already bound. */ + @Test public void testBind2() throws IOException { try (var impl = new PlatformSocketImpl(false)) { impl.create(true); var loopback = InetAddress.getLoopbackAddress(); impl.bind(loopback, 0); - expectThrows(IOException.class, () -> impl.bind(loopback, 0)); + assertThrows(IOException.class, () -> impl.bind(loopback, 0)); } } /** * Test bind when connected. */ + @Test public void testBind3() throws IOException { try (var ss = new ServerSocket(); var impl = new PlatformSocketImpl(false)) { @@ -178,94 +188,103 @@ public class BadUsages { ss.bind(new InetSocketAddress(loopback, 0)); impl.create(true); impl.connect(ss.getLocalSocketAddress(), 0); - expectThrows(IOException.class, () -> impl.bind(loopback, 0)); + assertThrows(IOException.class, () -> impl.bind(loopback, 0)); } } /** * Test bind when closed. */ + @Test public void testBind4() throws IOException { var impl = new PlatformSocketImpl(false); impl.close(); var loopback = InetAddress.getLoopbackAddress(); - expectThrows(IOException.class, () -> impl.bind(loopback, 0)); + assertThrows(IOException.class, () -> impl.bind(loopback, 0)); } /** * Test listen when not created. */ + @Test public void testListen1() { var impl = new PlatformSocketImpl(false); - expectThrows(IOException.class, () -> impl.listen(16)); + assertThrows(IOException.class, () -> impl.listen(16)); } /** * Test listen when not bound. */ + @Test public void testListen2() throws IOException { try (var impl = new PlatformSocketImpl(false)) { impl.create(true); - expectThrows(IOException.class, () -> impl.listen(16)); + assertThrows(IOException.class, () -> impl.listen(16)); } } /** * Test listen when closed. */ + @Test public void testListen3() throws IOException { var impl = new PlatformSocketImpl(false); impl.close(); - expectThrows(IOException.class, () -> impl.listen(16)); + assertThrows(IOException.class, () -> impl.listen(16)); } /** * Test accept when not created. */ + @Test public void testAccept1() throws IOException { var impl = new PlatformSocketImpl(true); var si = new PlatformSocketImpl(false); - expectThrows(IOException.class, () -> impl.accept(si)); + assertThrows(IOException.class, () -> impl.accept(si)); } /** * Test accept when not bound. */ + @Test public void testAccept2() throws IOException { try (var impl = new PlatformSocketImpl(true)) { impl.create(true); var si = new PlatformSocketImpl(false); - expectThrows(IOException.class, () -> impl.accept(si)); + assertThrows(IOException.class, () -> impl.accept(si)); } } /** * Test accept when closed. */ + @Test public void testAccept4() throws IOException { var impl = new PlatformSocketImpl(true); impl.close(); var si = new PlatformSocketImpl(false); - expectThrows(IOException.class, () -> impl.accept(si)); + assertThrows(IOException.class, () -> impl.accept(si)); } /** * Test accept with SocketImpl that is already created. */ + @Test public void testAccept5() throws IOException { try (var impl = new PlatformSocketImpl(true); var si = new PlatformSocketImpl(false)) { impl.create(true); impl.bind(InetAddress.getLoopbackAddress(), 0); si.create(true); - expectThrows(IOException.class, () -> impl.accept(si)); + assertThrows(IOException.class, () -> impl.accept(si)); } } /** * Test accept with SocketImpl that is closed. */ + @Test public void testAccept6() throws IOException { try (var impl = new PlatformSocketImpl(true); var si = new PlatformSocketImpl(false)) { @@ -273,65 +292,71 @@ public class BadUsages { impl.bind(InetAddress.getLoopbackAddress(), 0); si.create(true); si.close(); - expectThrows(IOException.class, () -> impl.accept(si)); + assertThrows(IOException.class, () -> impl.accept(si)); } } /** * Test available when not created. */ + @Test public void testAvailable1() throws IOException { var impl = new PlatformSocketImpl(false); - expectThrows(IOException.class, () -> impl.available()); + assertThrows(IOException.class, () -> impl.available()); } /** * Test available when created but not connected. */ + @Test public void testAvailable2() throws IOException { try (var impl = new PlatformSocketImpl(false)) { impl.create(true); - expectThrows(IOException.class, () -> impl.available()); + assertThrows(IOException.class, () -> impl.available()); } } /** * Test available when closed. */ + @Test public void testAvailable3() throws IOException { var impl = new PlatformSocketImpl(false); impl.close(); - expectThrows(IOException.class, () -> impl.available()); + assertThrows(IOException.class, () -> impl.available()); } /** * Test setOption when not created. */ + @Test public void testSetOption1() throws IOException { var impl = new PlatformSocketImpl(false); - expectThrows(IOException.class, + assertThrows(IOException.class, () -> impl.setOption(StandardSocketOptions.SO_REUSEADDR, true)); // legacy - expectThrows(SocketException.class, + assertThrows(SocketException.class, () -> impl.setOption(SocketOptions.SO_REUSEADDR, true)); } /** * Test setOption when closed. */ + @Test public void testSetOption2() throws IOException { var impl = new PlatformSocketImpl(false); impl.close(); - expectThrows(IOException.class, + assertThrows(IOException.class, () -> impl.setOption(StandardSocketOptions.SO_REUSEADDR, true)); // legacy - expectThrows(SocketException.class, + assertThrows(SocketException.class, () -> impl.setOption(SocketOptions.SO_REUSEADDR, true)); } /** * Test setOption with unsupported option. */ + @Test public void testSetOption3() throws IOException { try (var impl = new PlatformSocketImpl(false)) { impl.create(true); @@ -339,25 +364,26 @@ public class BadUsages { @Override public String name() { return "birthday"; } @Override public Class type() { return String.class; } }; - expectThrows(UnsupportedOperationException.class, () -> impl.setOption(opt, "")); + assertThrows(UnsupportedOperationException.class, () -> impl.setOption(opt, "")); // legacy - expectThrows(SocketException.class, () -> impl.setOption(-1, "")); + assertThrows(SocketException.class, () -> impl.setOption(-1, "")); } } /** * Test setOption(int, Object) with invalid values. */ + @Test public void testSetOption4() throws IOException { try (var impl = new PlatformSocketImpl(false)) { impl.create(true); - expectThrows(SocketException.class, + assertThrows(SocketException.class, () -> impl.setOption(SocketOptions.SO_REUSEADDR, -1)); - expectThrows(SocketException.class, + assertThrows(SocketException.class, () -> impl.setOption(SocketOptions.SO_TIMEOUT, -1)); - expectThrows(SocketException.class, + assertThrows(SocketException.class, () -> impl.setOption(SocketOptions.SO_SNDBUF, -1)); - expectThrows(SocketException.class, + assertThrows(SocketException.class, () -> impl.setOption(SocketOptions.SO_RCVBUF, -1)); } } @@ -365,29 +391,32 @@ public class BadUsages { /** * Test getOption when not created. */ + @Test public void testGetOption1() throws IOException { var impl = new PlatformSocketImpl(false); - expectThrows(IOException.class, + assertThrows(IOException.class, () -> impl.getOption(StandardSocketOptions.SO_REUSEADDR)); - expectThrows(SocketException.class, + assertThrows(SocketException.class, () -> impl.getOption(-1)); } /** * Test getOption when closed. */ + @Test public void testGetOption2() throws IOException { var impl = new PlatformSocketImpl(false); impl.close(); - expectThrows(IOException.class, + assertThrows(IOException.class, () -> impl.getOption(StandardSocketOptions.SO_REUSEADDR)); - expectThrows(SocketException.class, + assertThrows(SocketException.class, () -> impl.getOption(SocketOptions.SO_REUSEADDR)); } /** * Test getOption with unsupported option. */ + @Test public void testGetOption3() throws IOException { try (var impl = new PlatformSocketImpl(false)) { impl.create(true); @@ -395,89 +424,98 @@ public class BadUsages { @Override public String name() { return "birthday"; } @Override public Class type() { return String.class; } }; - expectThrows(UnsupportedOperationException.class, () -> impl.getOption(opt)); - expectThrows(SocketException.class, () -> impl.getOption(-1)); + assertThrows(UnsupportedOperationException.class, () -> impl.getOption(opt)); + assertThrows(SocketException.class, () -> impl.getOption(-1)); } } /** * Test shutdownInput when not created. */ + @Test public void testShutdownInput1() throws IOException { var impl = new PlatformSocketImpl(false); - expectThrows(IOException.class, () -> impl.shutdownInput()); + assertThrows(IOException.class, () -> impl.shutdownInput()); } /** * Test shutdownInput when not connected. */ + @Test public void testShutdownInput2() throws IOException { try (var impl = new PlatformSocketImpl(false)) { impl.create(true); - expectThrows(IOException.class, () -> impl.shutdownInput()); + assertThrows(IOException.class, () -> impl.shutdownInput()); } } /** * Test shutdownInput when closed. */ + @Test public void testShutdownInput3() throws IOException { var impl = new PlatformSocketImpl(false); impl.close(); - expectThrows(IOException.class, () -> impl.shutdownInput()); + assertThrows(IOException.class, () -> impl.shutdownInput()); } /** * Test shutdownOutput when not created. */ + @Test public void testShutdownOutput1() throws IOException { var impl = new PlatformSocketImpl(false); - expectThrows(IOException.class, () -> impl.shutdownOutput()); + assertThrows(IOException.class, () -> impl.shutdownOutput()); } /** * Test shutdownOutput when not connected. */ + @Test public void testShutdownOutput2() throws IOException { try (var impl = new PlatformSocketImpl(false)) { impl.create(true); - expectThrows(IOException.class, () -> impl.shutdownOutput()); + assertThrows(IOException.class, () -> impl.shutdownOutput()); } } /** * Test shutdownOutput when closed. */ + @Test public void testShutdownOutput3() throws IOException { var impl = new PlatformSocketImpl(false); impl.close(); - expectThrows(IOException.class, () -> impl.shutdownOutput()); + assertThrows(IOException.class, () -> impl.shutdownOutput()); } /** * Test sendUrgentData when not created. */ + @Test public void testSendUrgentData1() throws IOException { var impl = new PlatformSocketImpl(false); - expectThrows(IOException.class, () -> impl.sendUrgentData(0)); + assertThrows(IOException.class, () -> impl.sendUrgentData(0)); } /** * Test sendUrgentData when not connected. */ + @Test public void testSendUrgentData2() throws IOException { try (var impl = new PlatformSocketImpl(false)) { impl.create(true); - expectThrows(IOException.class, () -> impl.sendUrgentData(0)); + assertThrows(IOException.class, () -> impl.sendUrgentData(0)); } } /** * Test sendUrgentData when closed. */ + @Test public void testSendUrgentData3() throws IOException { var impl = new PlatformSocketImpl(false); impl.close(); - expectThrows(IOException.class, () -> impl.sendUrgentData(0)); + assertThrows(IOException.class, () -> impl.sendUrgentData(0)); } } diff --git a/test/jdk/java/net/SocketImpl/ImplSupportedOptions.java b/test/jdk/java/net/SocketImpl/ImplSupportedOptions.java index 51d523dce82..422f292bd97 100644 --- a/test/jdk/java/net/SocketImpl/ImplSupportedOptions.java +++ b/test/jdk/java/net/SocketImpl/ImplSupportedOptions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,7 @@ * @test * @bug 8213418 * @summary Ensure correct impl supported socket options - * @run testng ImplSupportedOptions + * @run junit ${test.main.class} */ import java.io.IOException; @@ -40,9 +40,10 @@ import java.net.SocketImpl; import java.net.SocketOption; import java.net.StandardSocketOptions; import java.util.Set; -import org.testng.annotations.Test; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; public class ImplSupportedOptions { @@ -52,29 +53,29 @@ public class ImplSupportedOptions { Set standardOptions = s.supportedOptions(); assertTrue(standardOptions.contains(StandardSocketOptions.SO_LINGER), "Expected SO_LINGER, in:" + standardOptions); - assertEquals(standardOptions, s.supportedOptions()); - assertEquals(standardOptions, s.supportedOptions()); + assertEquals(s.supportedOptions(), standardOptions); + assertEquals(s.supportedOptions(), standardOptions); s = new DummySocket(); Set dummyOptions = s.supportedOptions(); - assertEquals(dummyOptions.size(), 1); + assertEquals(1, dummyOptions.size()); assertTrue(dummyOptions.contains(DummySocketImpl.SOCKET_OPT)); - assertEquals(dummyOptions, s.supportedOptions()); - assertEquals(dummyOptions, s.supportedOptions()); + assertEquals(s.supportedOptions(), dummyOptions); + assertEquals(s.supportedOptions(), dummyOptions); s = new Socket(); standardOptions = s.supportedOptions(); assertTrue(standardOptions.contains(StandardSocketOptions.SO_LINGER), "Expected SO_LINGER, in:" + standardOptions); - assertEquals(standardOptions, s.supportedOptions()); - assertEquals(standardOptions, s.supportedOptions()); + assertEquals(s.supportedOptions(), standardOptions); + assertEquals(s.supportedOptions(), standardOptions); s = new DummySocket(); dummyOptions = s.supportedOptions(); - assertEquals(dummyOptions.size(), 1); + assertEquals(1, dummyOptions.size()); assertTrue(dummyOptions.contains(DummySocketImpl.SOCKET_OPT)); - assertEquals(dummyOptions, s.supportedOptions()); - assertEquals(dummyOptions, s.supportedOptions()); + assertEquals(s.supportedOptions(), dummyOptions); + assertEquals(s.supportedOptions(), dummyOptions); } @Test @@ -83,29 +84,29 @@ public class ImplSupportedOptions { Set standardOptions = s.supportedOptions(); assertTrue(standardOptions.contains(StandardSocketOptions.SO_REUSEADDR), "Expected SO_REUSEADDR, in:" + standardOptions); - assertEquals(standardOptions, s.supportedOptions()); - assertEquals(standardOptions, s.supportedOptions()); + assertEquals(s.supportedOptions(), standardOptions); + assertEquals(s.supportedOptions(), standardOptions); s = new DummyServerSocket(); Set dummyOptions = s.supportedOptions(); - assertEquals(dummyOptions.size(), 1); + assertEquals(1, dummyOptions.size()); assertTrue(dummyOptions.contains(DummySocketImpl.SOCKET_OPT)); - assertEquals(dummyOptions, s.supportedOptions()); - assertEquals(dummyOptions, s.supportedOptions()); + assertEquals(s.supportedOptions(), dummyOptions); + assertEquals(s.supportedOptions(), dummyOptions); s = new ServerSocket(); standardOptions = s.supportedOptions(); assertTrue(standardOptions.contains(StandardSocketOptions.SO_REUSEADDR), "Expected SO_REUSEADDR, in:" + standardOptions); - assertEquals(standardOptions, s.supportedOptions()); - assertEquals(standardOptions, s.supportedOptions()); + assertEquals(s.supportedOptions(), standardOptions); + assertEquals(s.supportedOptions(), standardOptions); s = new DummyServerSocket(); dummyOptions = s.supportedOptions(); - assertEquals(dummyOptions.size(), 1); + assertEquals(1, dummyOptions.size()); assertTrue(dummyOptions.contains(DummySocketImpl.SOCKET_OPT)); - assertEquals(dummyOptions, s.supportedOptions()); - assertEquals(dummyOptions, s.supportedOptions()); + assertEquals(s.supportedOptions(), dummyOptions); + assertEquals(s.supportedOptions(), dummyOptions); } static class DummySocket extends Socket { diff --git a/test/jdk/java/net/SocketImpl/SocketImplCombinations.java b/test/jdk/java/net/SocketImpl/SocketImplCombinations.java index 8fe8600bbb3..3a7968db909 100644 --- a/test/jdk/java/net/SocketImpl/SocketImplCombinations.java +++ b/test/jdk/java/net/SocketImpl/SocketImplCombinations.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,7 @@ * @test * @bug 8220493 * @modules java.base/java.net:+open java.base/sun.nio.ch:+open - * @run testng/othervm SocketImplCombinations + * @run junit/othervm ${test.main.class} * @summary Test Socket and ServerSocket with combinations of SocketImpls */ @@ -46,15 +46,22 @@ import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.util.function.BiConsumer; -import org.testng.annotations.Test; -import static org.testng.Assert.*; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; -@Test public class SocketImplCombinations { /** * Test creating an unconnected Socket, it should be created with a platform SocketImpl. */ + @Test public void testNewSocket1() throws IOException { try (Socket s = new Socket()) { SocketImpl si = getSocketImpl(s); @@ -67,6 +74,7 @@ public class SocketImplCombinations { /** * Test creating a connected Socket, it should be created with a platform SocketImpl. */ + @Test public void testNewSocket2() throws IOException { try (ServerSocket ss = boundServerSocket()) { try (Socket s = new Socket(ss.getInetAddress(), ss.getLocalPort())) { @@ -82,6 +90,7 @@ public class SocketImplCombinations { * Test creating a Socket for a DIRECT connection, it should be created with a * platform SocketImpl. */ + @Test public void testNewSocket3() throws IOException { try (Socket s = new Socket(Proxy.NO_PROXY)) { SocketImpl si = getSocketImpl(s); @@ -93,6 +102,7 @@ public class SocketImplCombinations { * Test creating a Socket for a SOCKS connection, it should be created with a * SOCKS SocketImpl. */ + @Test public void testNewSocket4() throws IOException { var address = new InetSocketAddress("127.0.0.1", 1080); var socksProxy = new Proxy(Proxy.Type.SOCKS, address); @@ -105,9 +115,10 @@ public class SocketImplCombinations { } /** - * Test creating a Socket for a HTTP proxy connection, it should be created with - * a HTTP proxy SocketImpl. + * Test creating a Socket for an HTTP proxy connection, it should be created with + * an HTTP proxy SocketImpl. */ + @Test public void testNewSocket5() throws IOException { var address = new InetSocketAddress("127.0.0.1", 8080); var httpProxy = new Proxy(Proxy.Type.HTTP, address); @@ -123,10 +134,11 @@ public class SocketImplCombinations { * Test creating a Socket no SocketImpl. A platform SocketImpl should be * created lazily. */ + @Test public void testNewSocket6() throws IOException { Socket s = new Socket((SocketImpl) null) { }; try (s) { - assertTrue(getSocketImpl(s) == null); + assertNull(getSocketImpl(s)); s.bind(loopbackSocketAddress()); // force SocketImpl to be created SocketImpl si = getSocketImpl(s); assertTrue(isSocksSocketImpl(si)); @@ -138,22 +150,24 @@ public class SocketImplCombinations { /** * Test creating a Socket with a custom SocketImpl. */ + @Test public void testNewSocket7() throws IOException { Socket s = new Socket(new CustomSocketImpl(false)) { }; try (s) { SocketImpl si = getSocketImpl(s); - assertTrue(si instanceof CustomSocketImpl); + assertInstanceOf(CustomSocketImpl.class, si); } } /** * Test creating a Socket when there is a SocketImplFactory set. */ + @Test public void testNewSocket8() throws IOException { setSocketSocketImplFactory(() -> new CustomSocketImpl(false)); try (Socket s = new Socket()) { SocketImpl si = getSocketImpl(s); - assertTrue(si instanceof CustomSocketImpl); + assertInstanceOf(CustomSocketImpl.class, si); } finally { setSocketSocketImplFactory(null); } @@ -163,11 +177,12 @@ public class SocketImplCombinations { * Test creating a Socket for a DIRECT connection when there is a * SocketImplFactory set. */ + @Test public void testNewSocket9() throws IOException { setSocketSocketImplFactory(() -> new CustomSocketImpl(false)); try (Socket s = new Socket(Proxy.NO_PROXY)) { SocketImpl si = getSocketImpl(s); - assertTrue(si instanceof CustomSocketImpl); + assertInstanceOf(CustomSocketImpl.class, si); } finally { setSocketSocketImplFactory(null); } @@ -177,6 +192,7 @@ public class SocketImplCombinations { * Test creating a Socket for a SOCKS connection when there is a * SocketImplFactory set. */ + @Test public void testNewSocket10() throws IOException { var address = new InetSocketAddress("127.0.0.1", 1080); var socksProxy = new Proxy(Proxy.Type.SOCKS, address); @@ -192,9 +208,10 @@ public class SocketImplCombinations { } /** - * Test creating a Socket for a HTTP proxy connection when there is a + * Test creating a Socket for an HTTP proxy connection when there is a * SocketImplFactory set. */ + @Test public void testNewSocket11() throws IOException { var address = new InetSocketAddress("127.0.0.1", 8080); var httpProxy = new Proxy(Proxy.Type.HTTP, address); @@ -212,14 +229,15 @@ public class SocketImplCombinations { /** * Test creating a Socket no SocketImpl when there is a SocketImplFactory set. */ + @Test public void testNewSocket12() throws IOException { setSocketSocketImplFactory(() -> new CustomSocketImpl(false)); try { Socket s = new Socket((SocketImpl) null) { }; try (s) { - assertTrue(getSocketImpl(s) == null); + assertNull(getSocketImpl(s)); s.bind(loopbackSocketAddress()); // force SocketImpl to be created - assertTrue(getSocketImpl(s) instanceof CustomSocketImpl); + assertInstanceOf(CustomSocketImpl.class, getSocketImpl(s)); } } finally { setSocketSocketImplFactory(null); @@ -230,6 +248,7 @@ public class SocketImplCombinations { * Test creating an unbound ServerSocket, it should be created with a platform * SocketImpl. */ + @Test public void testNewServerSocket1() throws IOException { try (ServerSocket ss = new ServerSocket()) { SocketImpl si = getSocketImpl(ss); @@ -241,6 +260,7 @@ public class SocketImplCombinations { * Test creating a bound ServerSocket, it should be created with a platform * SocketImpl. */ + @Test public void testNewServerSocket2() throws IOException { try (ServerSocket ss = new ServerSocket(0)) { SocketImpl si = getSocketImpl(ss); @@ -251,22 +271,24 @@ public class SocketImplCombinations { /** * Test creating a ServerSocket with a custom SocketImpl. */ + @Test public void testNewServerSocket3() throws IOException { ServerSocket ss = new ServerSocket(new CustomSocketImpl(true)) { }; try (ss) { SocketImpl si = getSocketImpl(ss); - assertTrue(si instanceof CustomSocketImpl); + assertInstanceOf(CustomSocketImpl.class, si); } } /** * Test creating an unbound ServerSocket when there is a SocketImplFactory set. */ + @Test public void testNewServerSocket4() throws IOException { setServerSocketImplFactory(() -> new CustomSocketImpl(true)); try (ServerSocket ss = new ServerSocket()) { SocketImpl si = getSocketImpl(ss); - assertTrue(si instanceof CustomSocketImpl); + assertInstanceOf(CustomSocketImpl.class, si); } finally { setServerSocketImplFactory(null); } @@ -275,11 +297,12 @@ public class SocketImplCombinations { /** * Test creating a bound ServerSocket when there is a SocketImplFactory set. */ + @Test public void testNewServerSocket5() throws IOException { setServerSocketImplFactory(() -> new CustomSocketImpl(true)); try (ServerSocket ss = new ServerSocket(0)) { SocketImpl si = getSocketImpl(ss); - assertTrue(si instanceof CustomSocketImpl); + assertInstanceOf(CustomSocketImpl.class, si); } finally { setServerSocketImplFactory(null); } @@ -289,13 +312,14 @@ public class SocketImplCombinations { * Test ServerSocket.accept. The ServerSocket uses a platform SocketImpl, * the Socket to accept is created with no SocketImpl. */ + @Test public void testServerSocketAccept1() throws IOException { var socket = new Socket((SocketImpl) null) { }; - assertTrue(getSocketImpl(socket) == null); + assertNull(getSocketImpl(socket)); serverSocketAccept(socket, (ss, s) -> { assertTrue(isPlatformSocketImpl(getSocketImpl(ss))); - assertTrue(s == socket); + assertSame(socket, s); SocketImpl si = getSocketImpl(s); assertTrue(isPlatformSocketImpl(si)); checkFields(si); @@ -307,13 +331,14 @@ public class SocketImplCombinations { * the Socket to accept is created with no SocketImpl, and there is a custom * client SocketImplFactory set. */ + @Test public void testServerSocketAccept2() throws IOException { var socket = new Socket((SocketImpl) null) { }; - assertTrue(getSocketImpl(socket) == null); + assertNull(getSocketImpl(socket)); serverSocketAccept(socket, () -> new CustomSocketImpl(false), (ss, s) -> { assertTrue(isPlatformSocketImpl(getSocketImpl(ss))); - assertTrue(s == socket); + assertSame(socket, s); SocketImpl si = getSocketImpl(s); assertTrue(isPlatformSocketImpl(si)); checkFields(si); @@ -325,6 +350,7 @@ public class SocketImplCombinations { * the Socket to accept is created with a SocketImpl that delegates to a * platform SocketImpl. */ + @Test public void testServerSocketAccept3() throws IOException { var socket = new Socket(); SocketImpl si = getSocketImpl(socket); @@ -334,7 +360,7 @@ public class SocketImplCombinations { serverSocketAccept(socket, (ss, s) -> { assertTrue(isPlatformSocketImpl(getSocketImpl(ss))); - assertTrue(s == socket); + assertSame(socket, s); SocketImpl psi = getSocketImpl(socket); assertTrue(isPlatformSocketImpl(psi)); checkFields(psi); @@ -345,26 +371,28 @@ public class SocketImplCombinations { * Test ServerSocket.accept. The ServerSocket uses a platform SocketImpl, * the Socket to accept is created with a custom SocketImpl. */ + @Test public void testServerSocketAccept4a() throws IOException { SocketImpl clientImpl = new CustomSocketImpl(false); Socket socket = new Socket(clientImpl) { }; - assertTrue(getSocketImpl(socket) == clientImpl); + assertSame(clientImpl, getSocketImpl(socket)); try (ServerSocket ss = serverSocketToAccept(socket)) { - expectThrows(IOException.class, ss::accept); + assertThrows(IOException.class, ss::accept); } finally { socket.close(); } } + @Test public void testServerSocketAccept4b() throws IOException { SocketImpl clientImpl = new CustomSocketImpl(false); Socket socket = new Socket(clientImpl) { }; - assertTrue(getSocketImpl(socket) == clientImpl); + assertSame(clientImpl, getSocketImpl(socket)); setSocketSocketImplFactory(() -> new CustomSocketImpl(false)); try (ServerSocket ss = serverSocketToAccept(socket)) { - expectThrows(IOException.class, ss::accept); + assertThrows(IOException.class, ss::accept); } finally { setSocketSocketImplFactory(null); socket.close(); @@ -375,42 +403,46 @@ public class SocketImplCombinations { * Test ServerSocket.accept. The ServerSocket uses a custom SocketImpl, * the Socket to accept is created no SocketImpl. */ + @Test public void testServerSocketAccept5a() throws IOException { SocketImpl serverImpl = new CustomSocketImpl(true); try (ServerSocket ss = new ServerSocket(serverImpl) { }) { ss.bind(loopbackSocketAddress()); - expectThrows(IOException.class, ss::accept); + assertThrows(IOException.class, ss::accept); } } + @Test public void testServerSocketAccept5b() throws IOException { var socket = new Socket((SocketImpl) null) { }; - assertTrue(getSocketImpl(socket) == null); + assertNull(getSocketImpl(socket)); SocketImpl serverImpl = new CustomSocketImpl(true); try (ServerSocket ss = serverSocketToAccept(serverImpl, socket)) { - expectThrows(IOException.class, ss::accept); + assertThrows(IOException.class, ss::accept); } finally { socket.close(); } } + @Test public void testServerSocketAccept5c() throws IOException { setServerSocketImplFactory(() -> new CustomSocketImpl(true)); try (ServerSocket ss = new ServerSocket(0)) { - expectThrows(IOException.class, ss::accept); + assertThrows(IOException.class, ss::accept); } finally { setServerSocketImplFactory(null); } } + @Test public void testServerSocketAccept5d() throws IOException { var socket = new Socket((SocketImpl) null) { }; - assertTrue(getSocketImpl(socket) == null); + assertNull(getSocketImpl(socket)); setServerSocketImplFactory(() -> new CustomSocketImpl(true)); try (ServerSocket ss = serverSocketToAccept(socket)) { - expectThrows(IOException.class, ss::accept); + assertThrows(IOException.class, ss::accept); } finally { setServerSocketImplFactory(null); socket.close(); @@ -422,16 +454,17 @@ public class SocketImplCombinations { * the Socket to accept is created with no SocketImpl, and there is a custom * client SocketImplFactory set. */ + @Test public void testServerSocketAccept6() throws Exception { var socket = new Socket((SocketImpl) null) { }; - assertTrue(getSocketImpl(socket) == null); + assertNull(getSocketImpl(socket)); SocketImpl serverImpl = new CustomSocketImpl(true); SocketImplFactory clientFactory = () -> new CustomSocketImpl(false); serverSocketAccept(serverImpl, socket, clientFactory, (ss, s) -> { - assertTrue(getSocketImpl(ss) == serverImpl); + assertSame(serverImpl, getSocketImpl(ss)); SocketImpl si = getSocketImpl(s); - assertTrue(si instanceof CustomSocketImpl); + assertInstanceOf(CustomSocketImpl.class, si); checkFields(si); }); } @@ -441,6 +474,7 @@ public class SocketImplCombinations { * the Socket to accept is created with a SocketImpl that delegates to a * platform SocketImpl. */ + @Test public void testServerSocketAccept7a() throws IOException { var socket = new Socket(); SocketImpl si = getSocketImpl(socket); @@ -450,12 +484,13 @@ public class SocketImplCombinations { SocketImpl serverImpl = new CustomSocketImpl(true); try (ServerSocket ss = serverSocketToAccept(serverImpl, socket)) { - expectThrows(IOException.class, ss::accept); + assertThrows(IOException.class, ss::accept); } finally { socket.close(); } } + @Test public void testServerSocketAccept7b() throws IOException { var socket = new Socket(); SocketImpl si = getSocketImpl(socket); @@ -465,7 +500,7 @@ public class SocketImplCombinations { setServerSocketImplFactory(() -> new CustomSocketImpl(true)); try (ServerSocket ss = serverSocketToAccept(socket)) { - expectThrows(IOException.class, ss::accept); + assertThrows(IOException.class, ss::accept); } finally { setServerSocketImplFactory(null); socket.close(); @@ -476,16 +511,17 @@ public class SocketImplCombinations { * Test ServerSocket.accept. The ServerSocket uses a custom SocketImpl, * the Socket to accept is created with a custom SocketImpl. */ + @Test public void testServerSocketAccept8() throws Exception { SocketImpl clientImpl = new CustomSocketImpl(false); Socket socket = new Socket(clientImpl) { }; - assertTrue(getSocketImpl(socket) == clientImpl); + assertSame(clientImpl, getSocketImpl(socket)); SocketImpl serverImpl = new CustomSocketImpl(true); SocketImplFactory clientFactory = () -> new CustomSocketImpl(false); serverSocketAccept(serverImpl, socket, clientFactory, (ss, s) -> { - assertTrue(getSocketImpl(ss) == serverImpl); - assertTrue(getSocketImpl(s) == clientImpl); + assertSame(serverImpl, getSocketImpl(ss)); + assertSame(clientImpl, getSocketImpl(s)); checkFields(clientImpl); }); } @@ -751,11 +787,14 @@ public class SocketImplCombinations { InetAddress address = get(si, "address"); int port = get(si, "port"); int localport = get(si, "localport"); - assertTrue(fd.valid() && address != null && port != 0 && localport != 0); + assertTrue(fd.valid()); + assertNotNull(address); + assertNotEquals(0, port); + assertNotEquals(0, localport); } /** - * Custom SocketImpl that is layed on a SocketChannel or ServerSocketChannel + * Custom SocketImpl that is layered on a SocketChannel or ServerSocketChannel */ static class CustomSocketImpl extends SocketImpl { private final boolean server; diff --git a/test/jdk/java/net/SocketImpl/TestDefaultBehavior.java b/test/jdk/java/net/SocketImpl/TestDefaultBehavior.java index 6ee01a56a1e..c08d652270d 100644 --- a/test/jdk/java/net/SocketImpl/TestDefaultBehavior.java +++ b/test/jdk/java/net/SocketImpl/TestDefaultBehavior.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,7 @@ * @test * @bug 8224477 * @summary Basic test for java.net.SocketImpl default behavior - * @run testng TestDefaultBehavior + * @run junit ${test.main.class} */ import java.io.IOException; @@ -36,11 +36,13 @@ import java.net.SocketAddress; import java.net.SocketImpl; import java.net.SocketOption; import java.util.Set; -import org.testng.annotations.Test; import static java.lang.Boolean.*; import static java.net.StandardSocketOptions.*; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.expectThrows; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.Test; public class TestDefaultBehavior { @@ -51,21 +53,21 @@ public class TestDefaultBehavior { public void socketImpl() { CustomSocketImpl csi = new CustomSocketImpl(); - assertEquals(csi.supportedOptions().size(), 0); + assertEquals(0, csi.supportedOptions().size()); - expectThrows(NPE, () -> csi.setOption(null, null)); - expectThrows(NPE, () -> csi.setOption(null, 1)); - expectThrows(UOE, () -> csi.setOption(SO_RCVBUF, 100)); - expectThrows(UOE, () -> csi.setOption(SO_KEEPALIVE, TRUE)); - expectThrows(UOE, () -> csi.setOption(SO_KEEPALIVE, FALSE)); - expectThrows(UOE, () -> csi.setOption(FAKE_SOCK_OPT, TRUE)); - expectThrows(UOE, () -> csi.setOption(FAKE_SOCK_OPT, FALSE)); - expectThrows(UOE, () -> csi.setOption(SO_KEEPALIVE, TRUE)); + assertThrows(NPE, () -> csi.setOption(null, null)); + assertThrows(NPE, () -> csi.setOption(null, 1)); + assertThrows(UOE, () -> csi.setOption(SO_RCVBUF, 100)); + assertThrows(UOE, () -> csi.setOption(SO_KEEPALIVE, TRUE)); + assertThrows(UOE, () -> csi.setOption(SO_KEEPALIVE, FALSE)); + assertThrows(UOE, () -> csi.setOption(FAKE_SOCK_OPT, TRUE)); + assertThrows(UOE, () -> csi.setOption(FAKE_SOCK_OPT, FALSE)); + assertThrows(UOE, () -> csi.setOption(SO_KEEPALIVE, TRUE)); - expectThrows(NPE, () -> csi.getOption(null)); - expectThrows(UOE, () -> csi.getOption(SO_RCVBUF)); - expectThrows(UOE, () -> csi.getOption(SO_KEEPALIVE)); - expectThrows(UOE, () -> csi.getOption(FAKE_SOCK_OPT)); + assertThrows(NPE, () -> csi.getOption(null)); + assertThrows(UOE, () -> csi.getOption(SO_RCVBUF)); + assertThrows(UOE, () -> csi.getOption(SO_KEEPALIVE)); + assertThrows(UOE, () -> csi.getOption(FAKE_SOCK_OPT)); } static final SocketOption FAKE_SOCK_OPT = new SocketOption<>() { From 34686923aaf9695aefe4ec23a0dae6b11ef2ad46 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Wed, 8 Apr 2026 15:44:39 +0000 Subject: [PATCH 210/359] 8372617: Save and restore stubgen stubs when using an AOT code cache Reviewed-by: kvn, asmehra --- .../cpu/aarch64/macroAssembler_aarch64.cpp | 7 +- src/hotspot/cpu/aarch64/runtime_aarch64.cpp | 2 +- .../cpu/aarch64/stubDeclarations_aarch64.hpp | 50 +- .../cpu/aarch64/stubGenerator_aarch64.cpp | 1720 +++++++++++++---- .../cpu/aarch64/stubRoutines_aarch64.cpp | 36 + .../cpu/aarch64/stubRoutines_aarch64.hpp | 5 + src/hotspot/cpu/arm/stubGenerator_arm.cpp | 6 +- src/hotspot/cpu/arm/stubRoutines_arm.cpp | 6 + src/hotspot/cpu/ppc/stubGenerator_ppc.cpp | 6 +- src/hotspot/cpu/ppc/stubRoutines_ppc_64.cpp | 6 + src/hotspot/cpu/riscv/stubGenerator_riscv.cpp | 6 +- src/hotspot/cpu/riscv/stubRoutines_riscv.cpp | 6 + src/hotspot/cpu/s390/stubGenerator_s390.cpp | 6 +- src/hotspot/cpu/s390/stubRoutines_s390.cpp | 6 + src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp | 20 + src/hotspot/cpu/x86/c1_LIRAssembler_x86.hpp | 3 + .../cpu/x86/gc/z/zBarrierSetAssembler_x86.cpp | 74 +- .../cpu/x86/gc/z/zBarrierSetAssembler_x86.hpp | 6 +- src/hotspot/cpu/x86/macroAssembler_x86.cpp | 29 +- .../cpu/x86/macroAssembler_x86_sha.cpp | 34 +- src/hotspot/cpu/x86/stubDeclarations_x86.hpp | 9 + src/hotspot/cpu/x86/stubGenerator_x86_64.cpp | 957 +++++++-- src/hotspot/cpu/x86/stubGenerator_x86_64.hpp | 31 +- .../cpu/x86/stubGenerator_x86_64_adler.cpp | 20 +- .../cpu/x86/stubGenerator_x86_64_aes.cpp | 178 +- .../x86/stubGenerator_x86_64_arraycopy.cpp | 633 +++++- .../cpu/x86/stubGenerator_x86_64_cbrt.cpp | 35 +- .../cpu/x86/stubGenerator_x86_64_chacha.cpp | 38 +- .../x86/stubGenerator_x86_64_constants.cpp | 26 + .../cpu/x86/stubGenerator_x86_64_cos.cpp | 11 +- .../x86/stubGenerator_x86_64_dilithium.cpp | 83 +- .../cpu/x86/stubGenerator_x86_64_exp.cpp | 32 +- .../cpu/x86/stubGenerator_x86_64_fmod.cpp | 25 +- .../cpu/x86/stubGenerator_x86_64_ghash.cpp | 40 +- .../cpu/x86/stubGenerator_x86_64_kyber.cpp | 118 +- .../cpu/x86/stubGenerator_x86_64_log.cpp | 44 +- .../cpu/x86/stubGenerator_x86_64_poly1305.cpp | 25 +- .../x86/stubGenerator_x86_64_poly_mont.cpp | 43 +- .../cpu/x86/stubGenerator_x86_64_pow.cpp | 41 +- .../cpu/x86/stubGenerator_x86_64_sha3.cpp | 36 +- .../cpu/x86/stubGenerator_x86_64_sin.cpp | 19 +- .../cpu/x86/stubGenerator_x86_64_sinh.cpp | 33 +- .../cpu/x86/stubGenerator_x86_64_tan.cpp | 34 +- .../cpu/x86/stubGenerator_x86_64_tanh.cpp | 33 +- src/hotspot/cpu/x86/stubRoutines_x86.cpp | 47 + src/hotspot/cpu/x86/stubRoutines_x86.hpp | 2 + src/hotspot/cpu/zero/stubGenerator_zero.cpp | 6 +- src/hotspot/cpu/zero/stubRoutines_zero.cpp | 6 + src/hotspot/share/asm/codeBuffer.cpp | 2 +- src/hotspot/share/c1/c1_Runtime1.cpp | 6 +- src/hotspot/share/code/aotCodeCache.cpp | 1329 ++++++++++--- src/hotspot/share/code/aotCodeCache.hpp | 227 ++- .../share/gc/z/zBarrierSetAssembler.hpp | 3 + src/hotspot/share/opto/runtime.cpp | 4 +- src/hotspot/share/prims/downcallLinker.hpp | 2 +- src/hotspot/share/runtime/init.cpp | 15 +- src/hotspot/share/runtime/sharedRuntime.cpp | 5 + .../share/runtime/stubCodeGenerator.cpp | 136 +- .../share/runtime/stubCodeGenerator.hpp | 72 +- .../share/runtime/stubDeclarations.hpp | 6 + src/hotspot/share/runtime/stubInfo.cpp | 9 + src/hotspot/share/runtime/stubInfo.hpp | 5 + src/hotspot/share/runtime/stubRoutines.cpp | 91 +- src/hotspot/share/runtime/stubRoutines.hpp | 8 + .../cds/appcds/aotCode/AOTCodeFlags.java | 98 +- 65 files changed, 5582 insertions(+), 1075 deletions(-) diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp index b5e15402941..7fa2e8086ad 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp @@ -3454,7 +3454,7 @@ void MacroAssembler::subw(Register Rd, Register Rn, RegisterOrConstant decrement void MacroAssembler::reinit_heapbase() { if (UseCompressedOops) { - if (Universe::is_fully_initialized()) { + if (Universe::is_fully_initialized() && !AOTCodeCache::is_on_for_dump()) { mov(rheapbase, CompressedOops::base()); } else { lea(rheapbase, ExternalAddress(CompressedOops::base_addr())); @@ -5128,7 +5128,8 @@ void MacroAssembler::cmp_klass(Register obj, Register klass, Register tmp) { if (CompressedKlassPointers::base() == nullptr) { cmp(klass, tmp, LSL, CompressedKlassPointers::shift()); return; - } else if (((uint64_t)CompressedKlassPointers::base() & 0xffffffff) == 0 + } else if (!AOTCodeCache::is_on_for_dump() && + ((uint64_t)CompressedKlassPointers::base() & 0xffffffff) == 0 && CompressedKlassPointers::shift() == 0) { // Only the bottom 32 bits matter cmpw(klass, tmp); @@ -5371,7 +5372,7 @@ void MacroAssembler::encode_klass_not_null_for_aot(Register dst, Register src) { } void MacroAssembler::encode_klass_not_null(Register dst, Register src) { - if (AOTCodeCache::is_on_for_dump()) { + if (CompressedKlassPointers::base() != nullptr && AOTCodeCache::is_on_for_dump()) { encode_klass_not_null_for_aot(dst, src); return; } diff --git a/src/hotspot/cpu/aarch64/runtime_aarch64.cpp b/src/hotspot/cpu/aarch64/runtime_aarch64.cpp index e36aa21b567..638e57b03fe 100644 --- a/src/hotspot/cpu/aarch64/runtime_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/runtime_aarch64.cpp @@ -290,7 +290,7 @@ ExceptionBlob* OptoRuntime::generate_exception_blob() { assert(SimpleRuntimeFrame::framesize % 4 == 0, "sp not 16-byte aligned"); const char* name = OptoRuntime::stub_name(StubId::c2_exception_id); - CodeBlob* blob = AOTCodeCache::load_code_blob(AOTCodeEntry::C2Blob, (uint)BlobId::c2_exception_id, name); + CodeBlob* blob = AOTCodeCache::load_code_blob(AOTCodeEntry::C2Blob, BlobId::c2_exception_id); if (blob != nullptr) { return blob->as_exception_blob(); } diff --git a/src/hotspot/cpu/aarch64/stubDeclarations_aarch64.hpp b/src/hotspot/cpu/aarch64/stubDeclarations_aarch64.hpp index 695534604b8..9dac6a39b82 100644 --- a/src/hotspot/cpu/aarch64/stubDeclarations_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/stubDeclarations_aarch64.hpp @@ -84,8 +84,7 @@ do_stub(compiler, count_positives) \ do_arch_entry(aarch64, compiler, count_positives, count_positives, \ count_positives) \ - do_stub(compiler, count_positives_long) \ - do_arch_entry(aarch64, compiler, count_positives_long, \ + do_arch_entry(aarch64, compiler, count_positives, \ count_positives_long, count_positives_long) \ do_stub(compiler, compare_long_string_LL) \ do_arch_entry(aarch64, compiler, compare_long_string_LL, \ @@ -108,8 +107,9 @@ do_stub(compiler, string_indexof_linear_ul) \ do_arch_entry(aarch64, compiler, string_indexof_linear_ul, \ string_indexof_linear_ul, string_indexof_linear_ul) \ - /* this uses the entry for ghash_processBlocks */ \ - do_stub(compiler, ghash_processBlocks_wide) \ + do_stub(compiler, ghash_processBlocks_small) \ + do_arch_entry(aarch64, compiler, ghash_processBlocks_small, \ + ghash_processBlocks_small, ghash_processBlocks_small) \ #define STUBGEN_FINAL_BLOBS_ARCH_DO(do_stub, \ @@ -139,9 +139,49 @@ do_stub(final, spin_wait) \ do_arch_entry_init(aarch64, final, spin_wait, spin_wait, \ spin_wait, empty_spin_wait) \ - /* stub only -- entries are not stored in StubRoutines::aarch64 */ \ /* n.b. these are not the same as the generic atomic stubs */ \ do_stub(final, atomic_entry_points) \ + do_arch_entry(aarch64, final, atomic_entry_points, \ + atomic_fetch_add_4_impl, atomic_fetch_add_4_impl) \ + do_arch_entry(aarch64, final, atomic_entry_points, \ + atomic_fetch_add_8_impl, atomic_fetch_add_8_impl) \ + do_arch_entry(aarch64, final, atomic_entry_points, \ + atomic_fetch_add_4_relaxed_impl, \ + atomic_fetch_add_4_relaxed_impl) \ + do_arch_entry(aarch64, final, atomic_entry_points, \ + atomic_fetch_add_8_relaxed_impl, \ + atomic_fetch_add_8_relaxed_impl) \ + do_arch_entry(aarch64, final, atomic_entry_points, \ + atomic_xchg_4_impl, atomic_xchg_4_impl) \ + do_arch_entry(aarch64, final, atomic_entry_points, \ + atomic_xchg_8_impl, atomic_xchg_8_impl) \ + do_arch_entry(aarch64, final, atomic_entry_points, \ + atomic_cmpxchg_1_impl, atomic_cmpxchg_1_impl) \ + do_arch_entry(aarch64, final, atomic_entry_points, \ + atomic_cmpxchg_4_impl, atomic_cmpxchg_4_impl) \ + do_arch_entry(aarch64, final, atomic_entry_points, \ + atomic_cmpxchg_8_impl, atomic_cmpxchg_8_impl) \ + do_arch_entry(aarch64, final, atomic_entry_points, \ + atomic_cmpxchg_1_relaxed_impl, \ + atomic_cmpxchg_1_relaxed_impl) \ + do_arch_entry(aarch64, final, atomic_entry_points, \ + atomic_cmpxchg_4_relaxed_impl, \ + atomic_cmpxchg_4_relaxed_impl) \ + do_arch_entry(aarch64, final, atomic_entry_points, \ + atomic_cmpxchg_8_relaxed_impl, \ + atomic_cmpxchg_8_relaxed_impl) \ + do_arch_entry(aarch64, final, atomic_entry_points, \ + atomic_cmpxchg_4_release_impl, \ + atomic_cmpxchg_4_release_impl) \ + do_arch_entry(aarch64, final, atomic_entry_points, \ + atomic_cmpxchg_8_release_impl, \ + atomic_cmpxchg_8_release_impl) \ + do_arch_entry(aarch64, final, atomic_entry_points, \ + atomic_cmpxchg_4_seq_cst_impl, \ + atomic_cmpxchg_4_seq_cst_impl) \ + do_arch_entry(aarch64, final, atomic_entry_points, \ + atomic_cmpxchg_8_seq_cst_impl, \ + atomic_cmpxchg_8_seq_cst_impl) \ #endif // CPU_AARCH64_STUBDECLARATIONS_HPP diff --git a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp index 21a1124a8ec..32fd8afb268 100644 --- a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp @@ -79,6 +79,166 @@ #define BIND(label) bind(label); BLOCK_COMMENT(#label ":") +// Constant data definitions + +static const uint32_t _sha256_round_consts[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, +}; + +static const uint64_t _sha512_round_consts[80] = { + 0x428A2F98D728AE22L, 0x7137449123EF65CDL, 0xB5C0FBCFEC4D3B2FL, + 0xE9B5DBA58189DBBCL, 0x3956C25BF348B538L, 0x59F111F1B605D019L, + 0x923F82A4AF194F9BL, 0xAB1C5ED5DA6D8118L, 0xD807AA98A3030242L, + 0x12835B0145706FBEL, 0x243185BE4EE4B28CL, 0x550C7DC3D5FFB4E2L, + 0x72BE5D74F27B896FL, 0x80DEB1FE3B1696B1L, 0x9BDC06A725C71235L, + 0xC19BF174CF692694L, 0xE49B69C19EF14AD2L, 0xEFBE4786384F25E3L, + 0x0FC19DC68B8CD5B5L, 0x240CA1CC77AC9C65L, 0x2DE92C6F592B0275L, + 0x4A7484AA6EA6E483L, 0x5CB0A9DCBD41FBD4L, 0x76F988DA831153B5L, + 0x983E5152EE66DFABL, 0xA831C66D2DB43210L, 0xB00327C898FB213FL, + 0xBF597FC7BEEF0EE4L, 0xC6E00BF33DA88FC2L, 0xD5A79147930AA725L, + 0x06CA6351E003826FL, 0x142929670A0E6E70L, 0x27B70A8546D22FFCL, + 0x2E1B21385C26C926L, 0x4D2C6DFC5AC42AEDL, 0x53380D139D95B3DFL, + 0x650A73548BAF63DEL, 0x766A0ABB3C77B2A8L, 0x81C2C92E47EDAEE6L, + 0x92722C851482353BL, 0xA2BFE8A14CF10364L, 0xA81A664BBC423001L, + 0xC24B8B70D0F89791L, 0xC76C51A30654BE30L, 0xD192E819D6EF5218L, + 0xD69906245565A910L, 0xF40E35855771202AL, 0x106AA07032BBD1B8L, + 0x19A4C116B8D2D0C8L, 0x1E376C085141AB53L, 0x2748774CDF8EEB99L, + 0x34B0BCB5E19B48A8L, 0x391C0CB3C5C95A63L, 0x4ED8AA4AE3418ACBL, + 0x5B9CCA4F7763E373L, 0x682E6FF3D6B2B8A3L, 0x748F82EE5DEFB2FCL, + 0x78A5636F43172F60L, 0x84C87814A1F0AB72L, 0x8CC702081A6439ECL, + 0x90BEFFFA23631E28L, 0xA4506CEBDE82BDE9L, 0xBEF9A3F7B2C67915L, + 0xC67178F2E372532BL, 0xCA273ECEEA26619CL, 0xD186B8C721C0C207L, + 0xEADA7DD6CDE0EB1EL, 0xF57D4F7FEE6ED178L, 0x06F067AA72176FBAL, + 0x0A637DC5A2C898A6L, 0x113F9804BEF90DAEL, 0x1B710B35131C471BL, + 0x28DB77F523047D84L, 0x32CAAB7B40C72493L, 0x3C9EBE0A15C9BEBCL, + 0x431D67C49C100D4CL, 0x4CC5D4BECB3E42B6L, 0x597F299CFC657E2AL, + 0x5FCB6FAB3AD6FAECL, 0x6C44198C4A475817L +}; + +static const uint64_t _sha3_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 +}; + +static const uint64_t _double_keccak_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 +}; + +static const char _encodeBlock_toBase64[64] = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' +}; + +static const char _encodeBlock_toBase64URL[64] = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_' +}; + +// Non-SIMD lookup tables are mostly dumped from fromBase64 array used in java.util.Base64, +// except the trailing character '=' is also treated illegal value in this intrinsic. That +// is java.util.Base64.fromBase64['='] = -2, while fromBase(URL)64ForNoSIMD['='] = 255 here. +static const uint8_t _decodeBlock_fromBase64ForNoSIMD[256] = { + 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, + 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, + 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 62u, 255u, 255u, 255u, 63u, + 52u, 53u, 54u, 55u, 56u, 57u, 58u, 59u, 60u, 61u, 255u, 255u, 255u, 255u, 255u, 255u, + 255u, 0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 9u, 10u, 11u, 12u, 13u, 14u, + 15u, 16u, 17u, 18u, 19u, 20u, 21u, 22u, 23u, 24u, 25u, 255u, 255u, 255u, 255u, 255u, + 255u, 26u, 27u, 28u, 29u, 30u, 31u, 32u, 33u, 34u, 35u, 36u, 37u, 38u, 39u, 40u, + 41u, 42u, 43u, 44u, 45u, 46u, 47u, 48u, 49u, 50u, 51u, 255u, 255u, 255u, 255u, 255u, + 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, + 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, + 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, + 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, + 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, + 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, + 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, + 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, +}; + +static const uint8_t _decodeBlock_fromBase64URLForNoSIMD[256] = { + 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, + 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, + 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 62u, 255u, 255u, + 52u, 53u, 54u, 55u, 56u, 57u, 58u, 59u, 60u, 61u, 255u, 255u, 255u, 255u, 255u, 255u, + 255u, 0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 9u, 10u, 11u, 12u, 13u, 14u, + 15u, 16u, 17u, 18u, 19u, 20u, 21u, 22u, 23u, 24u, 25u, 255u, 255u, 255u, 255u, 63u, + 255u, 26u, 27u, 28u, 29u, 30u, 31u, 32u, 33u, 34u, 35u, 36u, 37u, 38u, 39u, 40u, + 41u, 42u, 43u, 44u, 45u, 46u, 47u, 48u, 49u, 50u, 51u, 255u, 255u, 255u, 255u, 255u, + 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, + 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, + 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, + 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, + 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, + 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, + 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, + 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, +}; + +// A legal value of base64 code is in range [0, 127]. We need two lookups +// with tbl/tbx and combine them to get the decode data. The 1st table vector +// lookup use tbl, out of range indices are set to 0 in destination. The 2nd +// table vector lookup use tbx, out of range indices are unchanged in +// destination. Input [64..126] is mapped to index [65, 127] in second lookup. +// The value of index 64 is set to 0, so that we know that we already get the +// decoded data with the 1st lookup. +static const uint8_t _decodeBlock_fromBase64ForSIMD[128] = { + 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, + 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, + 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 62u, 255u, 255u, 255u, 63u, + 52u, 53u, 54u, 55u, 56u, 57u, 58u, 59u, 60u, 61u, 255u, 255u, 255u, 255u, 255u, 255u, + 0u, 255u, 0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 9u, 10u, 11u, 12u, 13u, + 14u, 15u, 16u, 17u, 18u, 19u, 20u, 21u, 22u, 23u, 24u, 25u, 255u, 255u, 255u, 255u, + 255u, 255u, 26u, 27u, 28u, 29u, 30u, 31u, 32u, 33u, 34u, 35u, 36u, 37u, 38u, 39u, + 40u, 41u, 42u, 43u, 44u, 45u, 46u, 47u, 48u, 49u, 50u, 51u, 255u, 255u, 255u, 255u, +}; + +static const uint8_t _decodeBlock_fromBase64URLForSIMD[128] = { + 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, + 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, + 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 62u, 255u, 255u, + 52u, 53u, 54u, 55u, 56u, 57u, 58u, 59u, 60u, 61u, 255u, 255u, 255u, 255u, 255u, 255u, + 0u, 255u, 0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 9u, 10u, 11u, 12u, 13u, + 14u, 15u, 16u, 17u, 18u, 19u, 20u, 21u, 22u, 23u, 24u, 25u, 255u, 255u, 255u, 255u, + 63u, 255u, 26u, 27u, 28u, 29u, 30u, 31u, 32u, 33u, 34u, 35u, 36u, 37u, 38u, 39u, + 40u, 41u, 42u, 43u, 44u, 45u, 46u, 47u, 48u, 49u, 50u, 51u, 255u, 255u, 255u, 255u, +}; + + // Stub Code definitions class StubGenerator: public StubCodeGenerator { @@ -203,8 +363,17 @@ class StubGenerator: public StubCodeGenerator { "adjust this code"); StubId stub_id = StubId::stubgen_call_stub_id; + GrowableArray
entries; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 2, "sanity check"); + address start = load_archive_data(stub_id, &entries); + if (start != nullptr) { + assert(entries.length() == 1, "expected 1 extra entry"); + return_address = entries.at(0); + return start; + } StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); const Address sp_after_call (rfp, sp_after_call_off * wordSize); @@ -323,6 +492,7 @@ class StubGenerator: public StubCodeGenerator { // save current address for use by exception handling code return_address = __ pc(); + entries.append(return_address); // store result depending on type (everything that is not // T_OBJECT, T_LONG, T_FLOAT or T_DOUBLE is treated as T_INT) @@ -406,6 +576,9 @@ class StubGenerator: public StubCodeGenerator { __ strd(j_farg0, Address(j_rarg2, 0)); __ br(Assembler::AL, exit); + // record the stub entry and end plus the auxiliary entry + store_archive_data(stub_id, start, __ pc(), &entries); + return start; } @@ -423,8 +596,14 @@ class StubGenerator: public StubCodeGenerator { address generate_catch_exception() { StubId stub_id = StubId::stubgen_catch_exception_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); // same as in generate_call_stub(): const Address sp_after_call(rfp, sp_after_call_off * wordSize); @@ -450,7 +629,9 @@ class StubGenerator: public StubCodeGenerator { __ verify_oop(r0); __ str(r0, Address(rthread, Thread::pending_exception_offset())); - __ mov(rscratch1, (address)__FILE__); + // special case -- add file name string to AOT address table + address file = (address)AOTCodeCache::add_C_string(__FILE__); + __ lea(rscratch1, ExternalAddress(file)); __ str(rscratch1, Address(rthread, Thread::exception_file_offset())); __ movw(rscratch1, (int)__LINE__); __ strw(rscratch1, Address(rthread, Thread::exception_line_offset())); @@ -458,7 +639,10 @@ class StubGenerator: public StubCodeGenerator { // complete return to VM assert(StubRoutines::_call_stub_return_address != nullptr, "_call_stub_return_address must have been generated before"); - __ b(StubRoutines::_call_stub_return_address); + __ b(RuntimeAddress(StubRoutines::_call_stub_return_address)); + + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); return start; } @@ -479,8 +663,14 @@ class StubGenerator: public StubCodeGenerator { address generate_forward_exception() { StubId stub_id = StubId::stubgen_forward_exception_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); // Upon entry, LR points to the return address returning into // Java (interpreted or compiled) code; i.e., the return address @@ -551,6 +741,9 @@ class StubGenerator: public StubCodeGenerator { __ verify_oop(r0); __ br(r19); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -569,8 +762,14 @@ class StubGenerator: public StubCodeGenerator { // [tos + 5]: saved rscratch1 address generate_verify_oop() { StubId stub_id = StubId::stubgen_verify_oop_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); Label exit, error; @@ -613,14 +812,23 @@ class StubGenerator: public StubCodeGenerator { __ blr(rscratch1); __ hlt(0); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } // Generate indices for iota vector. address generate_iota_indices(StubId stub_id) { + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); // B __ emit_data64(0x0706050403020100, relocInfo::none); __ emit_data64(0x0F0E0D0C0B0A0908, relocInfo::none); @@ -639,6 +847,10 @@ class StubGenerator: public StubCodeGenerator { // D - FP __ emit_data64(0x0000000000000000, relocInfo::none); // 0.0d __ emit_data64(0x3FF0000000000000, relocInfo::none); // 1.0d + + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -656,15 +868,21 @@ class StubGenerator: public StubCodeGenerator { // r11 < MacroAssembler::zero_words_block_size. address generate_zero_blocks() { + StubId stub_id = StubId::stubgen_zero_blocks_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); + StubCodeMark mark(this, stub_id); Label done; Label base_aligned; Register base = r10, cnt = r11; - __ align(CodeEntryAlignment); - StubId stub_id = StubId::stubgen_zero_blocks_id; - StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); if (UseBlockZeroing) { int zva_length = VM_Version::zva_length(); @@ -707,6 +925,9 @@ class StubGenerator: public StubCodeGenerator { __ ret(lr); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -803,6 +1024,12 @@ class StubGenerator: public StubCodeGenerator { // s and d are adjusted to point to the remaining words to copy // address generate_copy_longs(StubId stub_id, DecoratorSet decorators, Register s, Register d, Register count) { + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } BasicType type; copy_direction direction; @@ -854,7 +1081,7 @@ class StubGenerator: public StubCodeGenerator { StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); Label unaligned_copy_long; if (AvoidUnalignedAccesses) { @@ -1154,6 +1381,9 @@ class StubGenerator: public StubCodeGenerator { __ ret(lr); } + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -1445,19 +1675,25 @@ class StubGenerator: public StubCodeGenerator { } if (direction == copy_forwards) { if (type != T_OBJECT) { - __ bl(StubRoutines::aarch64::copy_byte_f()); + __ lea(rscratch1, RuntimeAddress(StubRoutines::aarch64::copy_byte_f())); + __ blr(rscratch1); } else if ((decorators & IS_DEST_UNINITIALIZED) != 0) { - __ bl(StubRoutines::aarch64::copy_oop_uninit_f()); + __ lea(rscratch1, RuntimeAddress(StubRoutines::aarch64::copy_oop_uninit_f())); + __ blr(rscratch1); } else { - __ bl(StubRoutines::aarch64::copy_oop_f()); + __ lea(rscratch1, RuntimeAddress(StubRoutines::aarch64::copy_oop_f())); + __ blr(rscratch1); } } else { if (type != T_OBJECT) { - __ bl(StubRoutines::aarch64::copy_byte_b()); + __ lea(rscratch1, RuntimeAddress(StubRoutines::aarch64::copy_byte_b())); + __ blr(rscratch1); } else if ((decorators & IS_DEST_UNINITIALIZED) != 0) { - __ bl(StubRoutines::aarch64::copy_oop_uninit_b()); + __ lea(rscratch1, RuntimeAddress(StubRoutines::aarch64::copy_oop_uninit_b())); + __ blr(rscratch1); } else { - __ bl(StubRoutines::aarch64::copy_oop_b()); + __ lea(rscratch1, RuntimeAddress(StubRoutines::aarch64::copy_oop_b())); + __ blr(rscratch1); } } @@ -1508,8 +1744,8 @@ class StubGenerator: public StubCodeGenerator { // stub_id - is used to name the stub and identify all details of // how to perform the copy. // - // entry - is assigned to the stub's post push entry point unless - // it is null + // nopush_entry - is assigned to the stub's post push entry point + // unless it is null // // Inputs: // c_rarg0 - source array address @@ -1525,8 +1761,6 @@ class StubGenerator: public StubCodeGenerator { // copy method // address generate_disjoint_copy(StubId stub_id, address *nopush_entry) { - Register s = c_rarg0, d = c_rarg1, count = c_rarg2; - RegSet saved_reg = RegSet::of(s, d, count); int size; bool aligned; bool is_oop; @@ -1607,17 +1841,45 @@ class StubGenerator: public StubCodeGenerator { ShouldNotReachHere(); break; } + // all stubs provide a 2nd entry which omits the frame push for + // use when bailing out from a conjoint copy. However we may also + // need some extra addressses for memory access protection. + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 2, "sanity check"); + assert(nopush_entry != nullptr, "all disjoint copy stubs export a nopush entry"); + + bool add_extras = !is_oop && (!aligned || sizeof(jlong) == size); + int extra_count = ((add_extras ? 1 : 0) * UnsafeMemoryAccess::COLUMN_COUNT); + GrowableArray
entries; + GrowableArray
extras; + GrowableArray
*extras_ptr = (extra_count > 0 ? &extras : nullptr); + address start = load_archive_data(stub_id, &entries, extras_ptr); + if (start != nullptr) { + assert(entries.length() == entry_count - 1, + "unexpected entries count %d", entries.length()); + *nopush_entry = entries.at(0); + assert(extras.length() == extra_count, + "unexpected extra count %d", extras.length()); + if (add_extras) { + // register one handler at offset 0 + register_unsafe_access_handlers(extras, 0, 1); + } + return start; + } + + Register s = c_rarg0, d = c_rarg1, count = c_rarg2; + RegSet saved_reg = RegSet::of(s, d, count); __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); __ enter(); - if (nopush_entry != nullptr) { - *nopush_entry = __ pc(); - // caller can pass a 64-bit byte count here (from Unsafe.copyMemory) - BLOCK_COMMENT("Entry:"); - } + *nopush_entry = __ pc(); + entries.append(*nopush_entry); + + // caller can pass a 64-bit byte count here (from Unsafe.copyMemory) + BLOCK_COMMENT("Post-Push Entry:"); DecoratorSet decorators = IN_HEAP | IS_ARRAY | ARRAYCOPY_DISJOINT; if (dest_uninitialized) { @@ -1636,8 +1898,7 @@ class StubGenerator: public StubCodeGenerator { } { // UnsafeMemoryAccess page error: continue after unsafe access - bool add_entry = !is_oop && (!aligned || sizeof(jlong) == size); - UnsafeMemoryAccessMark umam(this, add_entry, true); + UnsafeMemoryAccessMark umam(this, add_extras, true); copy_memory(decorators, is_oop ? T_OBJECT : T_BYTE, aligned, s, d, count, size); } @@ -1652,6 +1913,20 @@ class StubGenerator: public StubCodeGenerator { __ leave(); __ mov(r0, zr); // return 0 __ ret(lr); + + address end = __ pc(); + + if (add_extras) { + // retrieve the registered handler addresses + retrieve_unsafe_access_handlers(start, end, extras); + assert(extras.length() == extra_count + , "incorrect handlers count %d", extras.length()); + } + + // record the stub entry and end plus the no_push entry and any + // extra handler addresses + store_archive_data(stub_id, start, end, &entries, extras_ptr); + return start; } @@ -1663,8 +1938,8 @@ class StubGenerator: public StubCodeGenerator { // corresponding disjoint copy routine which can be // jumped to if the ranges do not actually overlap // - // entry - is assigned to the stub's post push entry point unless - // it is null + // nopush_entry - is assigned to the stub's post push entry point + // unless it is null // // // Inputs: @@ -1681,8 +1956,6 @@ class StubGenerator: public StubCodeGenerator { // used by some other conjoint copy method // address generate_conjoint_copy(StubId stub_id, address nooverlap_target, address *nopush_entry) { - Register s = c_rarg0, d = c_rarg1, count = c_rarg2; - RegSet saved_regs = RegSet::of(s, d, count); int size; bool aligned; bool is_oop; @@ -1762,15 +2035,47 @@ class StubGenerator: public StubCodeGenerator { default: ShouldNotReachHere(); } + // only some conjoint stubs generate a 2nd entry + int entry_count = StubInfo::entry_count(stub_id); + int expected_entry_count = (nopush_entry == nullptr ? 1 : 2); + assert(entry_count == expected_entry_count, + "expected entry count %d does not match declared entry count %d for stub %s", + expected_entry_count, entry_count, StubInfo::name(stub_id)); + // We need to protect memory accesses in certain cases + bool add_extras = !is_oop && (!aligned || sizeof(jlong) == size); + int extra_count = ((add_extras ? 1 : 0) * UnsafeMemoryAccess::COLUMN_COUNT); + GrowableArray
entries; + GrowableArray
extras; + GrowableArray
*entries_ptr = (nopush_entry != nullptr ? &entries : nullptr); + GrowableArray
*extras_ptr = (extra_count > 0 ? &extras : nullptr); + address start = load_archive_data(stub_id, entries_ptr, extras_ptr); + if (start != nullptr) { + assert(entries.length() == expected_entry_count - 1, + "unexpected entries count %d", entries.length()); + assert(extras.length() == extra_count, + "unexpected extra count %d", extras.length()); + if (nopush_entry != nullptr) { + *nopush_entry = entries.at(0); + } + if (add_extras) { + // register one handler at offset 0 + register_unsafe_access_handlers(extras, 0, 1); + } + return start; + } + + Register s = c_rarg0, d = c_rarg1, count = c_rarg2; + RegSet saved_regs = RegSet::of(s, d, count); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); __ enter(); if (nopush_entry != nullptr) { *nopush_entry = __ pc(); + entries.append(*nopush_entry); // caller can pass a 64-bit byte count here (from Unsafe.copyMemory) - BLOCK_COMMENT("Entry:"); + BLOCK_COMMENT("Post-Push Entry:"); } // use fwd copy when (d-s) above_equal (count*size) @@ -1798,8 +2103,7 @@ class StubGenerator: public StubCodeGenerator { } { // UnsafeMemoryAccess page error: continue after unsafe access - bool add_entry = !is_oop && (!aligned || sizeof(jlong) == size); - UnsafeMemoryAccessMark umam(this, add_entry, true); + UnsafeMemoryAccessMark umam(this, add_extras, true); copy_memory(decorators, is_oop ? T_OBJECT : T_BYTE, aligned, s, d, count, -size); } if (is_oop) { @@ -1811,6 +2115,23 @@ class StubGenerator: public StubCodeGenerator { __ leave(); __ mov(r0, zr); // return 0 __ ret(lr); + + assert(entries.length() == expected_entry_count - 1, + "unexpected entries count %d", entries.length()); + + address end = __ pc(); + + if (add_extras) { + // retrieve the registered handler addresses + retrieve_unsafe_access_handlers(start, end, extras); + assert(extras.length() == extra_count, + "incorrect handlers count %d", extras.length()); + } + + // record the stub entry and end plus any no_push entry and/or + // extra handler addresses + store_archive_data(stub_id, start, end, entries_ptr, extras_ptr); + return start; } @@ -1864,6 +2185,27 @@ class StubGenerator: public StubCodeGenerator { ShouldNotReachHere(); } + // The normal stub provides a 2nd entry which omits the frame push + // for use when bailing out from a disjoint copy. + // Only some conjoint stubs generate a 2nd entry + int entry_count = StubInfo::entry_count(stub_id); + int expected_entry_count = (nopush_entry == nullptr ? 1 : 2); + GrowableArray
entries; + GrowableArray
*entries_ptr = (expected_entry_count == 1 ? nullptr : &entries); + assert(entry_count == expected_entry_count, + "expected entry count %d does not match declared entry count %d for stub %s", + expected_entry_count, entry_count, StubInfo::name(stub_id)); + address start = load_archive_data(stub_id, entries_ptr); + if (start != nullptr) { + assert(entries.length() + 1 == expected_entry_count, + "expected entry count %d does not match return entry count %d for stub %s", + expected_entry_count, entries.length() + 1, StubInfo::name(stub_id)); + if (nopush_entry != nullptr) { + *nopush_entry = entries.at(0); + } + return start; + } + Label L_load_element, L_store_element, L_do_card_marks, L_done, L_done_pop; // Input registers (after setup_arg_regs) @@ -1896,7 +2238,7 @@ class StubGenerator: public StubCodeGenerator { __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); __ enter(); // required for proper stackwalking of RuntimeStub frame @@ -1913,6 +2255,7 @@ class StubGenerator: public StubCodeGenerator { // Caller of this entry point must set up the argument registers. if (nopush_entry != nullptr) { *nopush_entry = __ pc(); + entries.append(*nopush_entry); BLOCK_COMMENT("Entry:"); } @@ -2010,6 +2353,8 @@ class StubGenerator: public StubCodeGenerator { __ leave(); __ ret(lr); + // record the stub entry and end plus any no_push entry + store_archive_data(stub_id, start, __ pc() , entries_ptr); return start; } @@ -2072,13 +2417,18 @@ class StubGenerator: public StubCodeGenerator { address int_copy_entry, address long_copy_entry) { StubId stub_id = StubId::stubgen_unsafe_arraycopy_id; - + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } Label L_long_aligned, L_int_aligned, L_short_aligned; Register s = c_rarg0, d = c_rarg1, count = c_rarg2; __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); __ enter(); // required for proper stackwalking of RuntimeStub frame // bump this on entry, not on exit: @@ -2104,6 +2454,9 @@ class StubGenerator: public StubCodeGenerator { __ lsr(count, count, LogBytesPerLong); // size => long_count __ b(RuntimeAddress(long_copy_entry)); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -2125,7 +2478,12 @@ class StubGenerator: public StubCodeGenerator { address int_copy_entry, address oop_copy_entry, address long_copy_entry, address checkcast_copy_entry) { StubId stub_id = StubId::stubgen_generic_arraycopy_id; - + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } Label L_failed, L_objArray; Label L_copy_bytes, L_copy_shorts, L_copy_ints, L_copy_longs; @@ -2144,7 +2502,7 @@ class StubGenerator: public StubCodeGenerator { StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); __ enter(); // required for proper stackwalking of RuntimeStub frame @@ -2383,6 +2741,9 @@ class StubGenerator: public StubCodeGenerator { __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(lr); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -2427,10 +2788,15 @@ class StubGenerator: public StubCodeGenerator { default: ShouldNotReachHere(); }; - + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); BLOCK_COMMENT("Entry:"); @@ -2563,15 +2929,32 @@ class StubGenerator: public StubCodeGenerator { __ bind(L_exit2); __ leave(); __ ret(lr); + + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } address generate_unsafecopy_common_error_exit() { - address start_pc = __ pc(); + StubId stub_id = StubId::stubgen_unsafecopy_common_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); + StubCodeMark mark(this, stub_id); + start = __ pc(); __ leave(); __ mov(r0, 0); __ ret(lr); - return start_pc; + + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + + return start; } // @@ -2589,13 +2972,28 @@ class StubGenerator: public StubCodeGenerator { // c_rarg2 - byte value // address generate_unsafe_setmemory() { + StubId stub_id = StubId::stubgen_unsafe_setmemory_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + // we expect one set of extra unsafememory access handler entries + GrowableArray
extras; + int extra_count = 1 * UnsafeMemoryAccess::COLUMN_COUNT; + address start = load_archive_data(stub_id, nullptr, &extras); + if (start != nullptr) { + assert(extras.length() == extra_count, + "unexpected extra entry count %d", extras.length()); + register_unsafe_access_handlers(extras, 0, 1); + return start; + } + __ align(CodeEntryAlignment); - StubCodeMark mark(this, StubId::stubgen_unsafe_setmemory_id); - address start = __ pc(); + StubCodeMark mark(this, stub_id); + start = __ pc(); Register dest = c_rarg0, count = c_rarg1, value = c_rarg2; Label tail; + { UnsafeMemoryAccessMark umam(this, true, false); __ enter(); // required for proper stackwalking of RuntimeStub frame @@ -2679,6 +3077,17 @@ class StubGenerator: public StubCodeGenerator { __ bind(finished); __ leave(); __ ret(lr); + // have to exit the block and destroy the UnsafeMemoryAccessMark + // in order to retrieve the handler end address + } + + // install saved handler addresses in extras + address end = __ pc(); + retrieve_unsafe_access_handlers(start, end, extras); + assert(extras.length() == extra_count, + "incorrect handlers count %d", extras.length()); + // record the stub entry and end plus the extras + store_archive_data(stub_id, start, end, nullptr, &extras); return start; } @@ -2686,33 +3095,45 @@ class StubGenerator: public StubCodeGenerator { address generate_data_cache_writeback() { const Register line = c_rarg0; // address of line to write back - __ align(CodeEntryAlignment); - StubId stub_id = StubId::stubgen_data_cache_writeback_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); __ enter(); __ cache_wb(Address(line, 0)); __ leave(); __ ret(lr); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } address generate_data_cache_writeback_sync() { - const Register is_pre = c_rarg0; // pre or post sync - - __ align(CodeEntryAlignment); - StubId stub_id = StubId::stubgen_data_cache_writeback_sync_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + const Register is_pre = c_rarg0; // pre or post sync + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); // pre wbsync is a no-op // post wbsync translates to an sfence Label skip; - address start = __ pc(); + start = __ pc(); __ enter(); __ cbnz(is_pre, skip); __ cache_wbsync(false); @@ -2720,6 +3141,9 @@ class StubGenerator: public StubCodeGenerator { __ leave(); __ ret(lr); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -2882,8 +3306,15 @@ class StubGenerator: public StubCodeGenerator { // c_rarg2 - sessionKe (key) in little endian int array // address generate_aescrypt_encryptBlock() { - __ align(CodeEntryAlignment); + assert(UseAES, "need AES cryptographic extension support"); StubId stub_id = StubId::stubgen_aescrypt_encryptBlock_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); const Register from = c_rarg0; // source array address @@ -2891,7 +3322,7 @@ class StubGenerator: public StubCodeGenerator { const Register key = c_rarg2; // key array address const Register keylen = rscratch1; - address start = __ pc(); + start = __ pc(); __ enter(); __ ldrw(keylen, Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT))); @@ -2904,6 +3335,9 @@ class StubGenerator: public StubCodeGenerator { __ leave(); __ ret(lr); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -2916,8 +3350,14 @@ class StubGenerator: public StubCodeGenerator { // address generate_aescrypt_decryptBlock() { assert(UseAES, "need AES cryptographic extension support"); - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_aescrypt_decryptBlock_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); Label L_doLast; @@ -2926,7 +3366,7 @@ class StubGenerator: public StubCodeGenerator { const Register key = c_rarg2; // key array address const Register keylen = rscratch1; - address start = __ pc(); + start = __ pc(); __ enter(); // required for proper stackwalking of RuntimeStub frame __ ldrw(keylen, Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT))); @@ -2938,6 +3378,9 @@ class StubGenerator: public StubCodeGenerator { __ leave(); __ ret(lr); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -2955,8 +3398,14 @@ class StubGenerator: public StubCodeGenerator { // address generate_cipherBlockChaining_encryptAESCrypt() { assert(UseAES, "need AES cryptographic extension support"); - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_cipherBlockChaining_encryptAESCrypt_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); Label L_loadkeys_44, L_loadkeys_52, L_aes_loop, L_rounds_44, L_rounds_52; @@ -2969,7 +3418,7 @@ class StubGenerator: public StubCodeGenerator { const Register len_reg = c_rarg4; // src len (must be multiple of blocksize 16) const Register keylen = rscratch1; - address start = __ pc(); + start = __ pc(); __ enter(); @@ -3043,6 +3492,9 @@ class StubGenerator: public StubCodeGenerator { __ leave(); __ ret(lr); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -3060,8 +3512,14 @@ class StubGenerator: public StubCodeGenerator { // address generate_cipherBlockChaining_decryptAESCrypt() { assert(UseAES, "need AES cryptographic extension support"); - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_cipherBlockChaining_decryptAESCrypt_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); Label L_loadkeys_44, L_loadkeys_52, L_aes_loop, L_rounds_44, L_rounds_52; @@ -3074,7 +3532,7 @@ class StubGenerator: public StubCodeGenerator { const Register len_reg = c_rarg4; // src len (must be multiple of blocksize 16) const Register keylen = rscratch1; - address start = __ pc(); + start = __ pc(); __ enter(); @@ -3152,6 +3610,9 @@ class StubGenerator: public StubCodeGenerator { __ leave(); __ ret(lr); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -3188,6 +3649,13 @@ class StubGenerator: public StubCodeGenerator { // r0 - input length // address generate_counterMode_AESCrypt() { + StubId stub_id = StubId::stubgen_counterMode_AESCrypt_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } const Register in = c_rarg0; const Register out = c_rarg1; const Register key = c_rarg2; @@ -3248,9 +3716,8 @@ class StubGenerator: public StubCodeGenerator { // Wide bulk encryption of whole blocks. __ align(CodeEntryAlignment); - StubId stub_id = StubId::stubgen_counterMode_AESCrypt_id; StubCodeMark mark(this, stub_id); - const address start = __ pc(); + start = __ pc(); __ enter(); Label DONE, CTR_large_block, large_block_return; @@ -3435,6 +3902,9 @@ class StubGenerator: public StubCodeGenerator { __ strw(used, Address(used_ptr)); __ b(large_block_return); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -3451,11 +3921,16 @@ class StubGenerator: public StubCodeGenerator { // return - number of processed bytes address generate_galoisCounterMode_AESCrypt() { Label ghash_polynomial; // local data generated after code - - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_galoisCounterMode_AESCrypt_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); __ enter(); const Register in = c_rarg0; @@ -3567,6 +4042,9 @@ class StubGenerator: public StubCodeGenerator { // 128-bit vector __ emit_int64(0x87); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -3685,10 +4163,16 @@ class StubGenerator: public StubCodeGenerator { default: ShouldNotReachHere(); } + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); Register buf = c_rarg0; Register state = c_rarg1; @@ -3815,6 +4299,9 @@ class StubGenerator: public StubCodeGenerator { __ ret(lr); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -3838,11 +4325,16 @@ class StubGenerator: public StubCodeGenerator { default: ShouldNotReachHere(); } - + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); Register buf = c_rarg0; Register state = c_rarg1; @@ -3919,6 +4411,9 @@ class StubGenerator: public StubCodeGenerator { __ emit_int32(0x8f1bbcdc); __ emit_int32(0xca62c1d6); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -3943,30 +4438,15 @@ class StubGenerator: public StubCodeGenerator { default: ShouldNotReachHere(); } - - static const uint32_t round_consts[64] = { - 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, - 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, - 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, - 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, - 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, - 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, - 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, - 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, - 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, - 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, - 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, - 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, - 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, - 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, - 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, - 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, - }; - + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } __ align(CodeEntryAlignment); - StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); Register buf = c_rarg0; Register state = c_rarg1; @@ -3987,7 +4467,7 @@ class StubGenerator: public StubCodeGenerator { // t1 == v7 // load 16 keys to v16..v31 - __ lea(rscratch1, ExternalAddress((address)round_consts)); + __ lea(rscratch1, ExternalAddress((address)_sha256_round_consts)); __ ld1(v16, v17, v18, v19, __ T4S, __ post(rscratch1, 64)); __ ld1(v20, v21, v22, v23, __ T4S, __ post(rscratch1, 64)); __ ld1(v24, v25, v26, v27, __ T4S, __ post(rscratch1, 64)); @@ -4048,6 +4528,9 @@ class StubGenerator: public StubCodeGenerator { __ ret(lr); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -4099,41 +4582,15 @@ class StubGenerator: public StubCodeGenerator { default: ShouldNotReachHere(); } - - static const uint64_t round_consts[80] = { - 0x428A2F98D728AE22L, 0x7137449123EF65CDL, 0xB5C0FBCFEC4D3B2FL, - 0xE9B5DBA58189DBBCL, 0x3956C25BF348B538L, 0x59F111F1B605D019L, - 0x923F82A4AF194F9BL, 0xAB1C5ED5DA6D8118L, 0xD807AA98A3030242L, - 0x12835B0145706FBEL, 0x243185BE4EE4B28CL, 0x550C7DC3D5FFB4E2L, - 0x72BE5D74F27B896FL, 0x80DEB1FE3B1696B1L, 0x9BDC06A725C71235L, - 0xC19BF174CF692694L, 0xE49B69C19EF14AD2L, 0xEFBE4786384F25E3L, - 0x0FC19DC68B8CD5B5L, 0x240CA1CC77AC9C65L, 0x2DE92C6F592B0275L, - 0x4A7484AA6EA6E483L, 0x5CB0A9DCBD41FBD4L, 0x76F988DA831153B5L, - 0x983E5152EE66DFABL, 0xA831C66D2DB43210L, 0xB00327C898FB213FL, - 0xBF597FC7BEEF0EE4L, 0xC6E00BF33DA88FC2L, 0xD5A79147930AA725L, - 0x06CA6351E003826FL, 0x142929670A0E6E70L, 0x27B70A8546D22FFCL, - 0x2E1B21385C26C926L, 0x4D2C6DFC5AC42AEDL, 0x53380D139D95B3DFL, - 0x650A73548BAF63DEL, 0x766A0ABB3C77B2A8L, 0x81C2C92E47EDAEE6L, - 0x92722C851482353BL, 0xA2BFE8A14CF10364L, 0xA81A664BBC423001L, - 0xC24B8B70D0F89791L, 0xC76C51A30654BE30L, 0xD192E819D6EF5218L, - 0xD69906245565A910L, 0xF40E35855771202AL, 0x106AA07032BBD1B8L, - 0x19A4C116B8D2D0C8L, 0x1E376C085141AB53L, 0x2748774CDF8EEB99L, - 0x34B0BCB5E19B48A8L, 0x391C0CB3C5C95A63L, 0x4ED8AA4AE3418ACBL, - 0x5B9CCA4F7763E373L, 0x682E6FF3D6B2B8A3L, 0x748F82EE5DEFB2FCL, - 0x78A5636F43172F60L, 0x84C87814A1F0AB72L, 0x8CC702081A6439ECL, - 0x90BEFFFA23631E28L, 0xA4506CEBDE82BDE9L, 0xBEF9A3F7B2C67915L, - 0xC67178F2E372532BL, 0xCA273ECEEA26619CL, 0xD186B8C721C0C207L, - 0xEADA7DD6CDE0EB1EL, 0xF57D4F7FEE6ED178L, 0x06F067AA72176FBAL, - 0x0A637DC5A2C898A6L, 0x113F9804BEF90DAEL, 0x1B710B35131C471BL, - 0x28DB77F523047D84L, 0x32CAAB7B40C72493L, 0x3C9EBE0A15C9BEBCL, - 0x431D67C49C100D4CL, 0x4CC5D4BECB3E42B6L, 0x597F299CFC657E2AL, - 0x5FCB6FAB3AD6FAECL, 0x6C44198C4A475817L - }; - + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } __ align(CodeEntryAlignment); - StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); Register buf = c_rarg0; Register state = c_rarg1; @@ -4151,7 +4608,7 @@ class StubGenerator: public StubCodeGenerator { __ ld1(v8, v9, v10, v11, __ T2D, state); // load first 4 round constants - __ lea(rscratch1, ExternalAddress((address)round_consts)); + __ lea(rscratch1, ExternalAddress((address)_sha512_round_consts)); __ ld1(v20, v21, v22, v23, __ T2D, __ post(rscratch1, 64)); __ BIND(sha512_loop); @@ -4236,6 +4693,9 @@ class StubGenerator: public StubCodeGenerator { __ ret(lr); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -4349,22 +4809,15 @@ class StubGenerator: public StubCodeGenerator { default: ShouldNotReachHere(); } - - 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 - }; - + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } __ align(CodeEntryAlignment); - StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); Register buf = c_rarg0; Register state = c_rarg1; @@ -4396,7 +4849,7 @@ class StubGenerator: public StubCodeGenerator { __ movw(rscratch2, 24); // load round_constants base - __ lea(rscratch1, ExternalAddress((address) round_consts)); + __ lea(rscratch1, ExternalAddress((address) _sha3_round_consts)); // load input __ ld1(v25, v26, v27, v28, __ T8B, __ post(buf, 32)); @@ -4488,6 +4941,9 @@ class StubGenerator: public StubCodeGenerator { __ ret(lr); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -4495,22 +4951,18 @@ class StubGenerator: public StubCodeGenerator { // 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 - }; - + StubId stub_id = StubId::stubgen_double_keccak_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } // Implements the double_keccak() method of the // sun.secyrity.provider.SHA3Parallel class __ align(CodeEntryAlignment); - StubCodeMark mark(this, "StubRoutines", "double_keccak"); - address start = __ pc(); + StubCodeMark mark(this, stub_id); + start = __ pc(); __ enter(); Register state0 = c_rarg0; @@ -4546,7 +4998,7 @@ class StubGenerator: public StubCodeGenerator { __ movw(rscratch2, 24); // load round_constants base - __ lea(rscratch1, ExternalAddress((address) round_consts)); + __ lea(rscratch1, ExternalAddress((address) _double_keccak_round_consts)); __ BIND(rounds24_loop); __ subw(rscratch2, rscratch2, 1); @@ -4578,6 +5030,9 @@ class StubGenerator: public StubCodeGenerator { __ mov(r0, zr); // return 0 __ ret(lr); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -4611,11 +5066,17 @@ class StubGenerator: public StubCodeGenerator { // vectors write their first lane back to the keystream buffer, followed // by the second lane from all vectors and so on. address generate_chacha20Block_blockpar() { + StubId stub_id = StubId::stubgen_chacha20Block_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } Label L_twoRounds, L_cc20_const; __ align(CodeEntryAlignment); - StubId stub_id = StubId::stubgen_chacha20Block_id; StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); __ enter(); int i, j; @@ -4770,6 +5231,9 @@ class StubGenerator: public StubCodeGenerator { __ emit_int64(0x0605040702010003UL); __ emit_int64(0x0E0D0C0F0A09080BUL); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -5258,11 +5722,16 @@ class StubGenerator: public StubCodeGenerator { // coeffs (short[256]) = c_rarg0 // ntt_zetas (short[256]) = c_rarg1 address generate_kyberNtt() { - - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_kyberNtt_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); __ enter(); const Register coeffs = c_rarg0; @@ -5486,6 +5955,9 @@ class StubGenerator: public StubCodeGenerator { __ mov(r0, zr); // return 0 __ ret(lr); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -5496,11 +5968,16 @@ class StubGenerator: public StubCodeGenerator { // coeffs (short[256]) = c_rarg0 // ntt_zetas (short[256]) = c_rarg1 address generate_kyberInverseNtt() { - - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_kyberInverseNtt_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); __ enter(); const Register coeffs = c_rarg0; @@ -5770,6 +6247,9 @@ class StubGenerator: public StubCodeGenerator { __ mov(r0, zr); // return 0 __ ret(lr); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -5783,11 +6263,16 @@ class StubGenerator: public StubCodeGenerator { // nttb (short[256]) = c_rarg2 // zetas (short[128]) = c_rarg3 address generate_kyberNttMult() { - - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_kyberNttMult_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); __ enter(); const Register result = c_rarg0; @@ -5889,6 +6374,9 @@ class StubGenerator: public StubCodeGenerator { __ mov(r0, zr); // return 0 __ ret(lr); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -5900,11 +6388,16 @@ class StubGenerator: public StubCodeGenerator { // a (short[256]) = c_rarg1 // b (short[256]) = c_rarg2 address generate_kyberAddPoly_2() { - - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_kyberAddPoly_2_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); __ enter(); const Register result = c_rarg0; @@ -5973,6 +6466,9 @@ class StubGenerator: public StubCodeGenerator { __ mov(r0, zr); // return 0 __ ret(lr); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -5985,11 +6481,16 @@ class StubGenerator: public StubCodeGenerator { // b (short[256]) = c_rarg2 // c (short[256]) = c_rarg3 address generate_kyberAddPoly_3() { - - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_kyberAddPoly_3_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); __ enter(); const Register result = c_rarg0; @@ -6072,6 +6573,9 @@ class StubGenerator: public StubCodeGenerator { __ mov(r0, zr); // return 0 __ ret(lr); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -6092,12 +6596,18 @@ class StubGenerator: public StubCodeGenerator { // parsed (short[]) = c_rarg2 // parsedLength = c_rarg3 address generate_kyber12To16() { + StubId stub_id = StubId::stubgen_kyber12To16_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } Label L_F00, L_loop; __ align(CodeEntryAlignment); - StubId stub_id = StubId::stubgen_kyber12To16_id; StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); __ enter(); const Register condensed = c_rarg0; @@ -6225,6 +6735,9 @@ class StubGenerator: public StubCodeGenerator { __ emit_int64(0x0f000f000f000f00); __ emit_int64(0x0f000f000f000f00); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -6234,11 +6747,16 @@ class StubGenerator: public StubCodeGenerator { // // coeffs (short[256]) = c_rarg0 address generate_kyberBarrettReduce() { - - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_kyberBarrettReduce_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); __ enter(); const Register coeffs = c_rarg0; @@ -6318,6 +6836,9 @@ class StubGenerator: public StubCodeGenerator { __ mov(r0, zr); // return 0 __ ret(lr); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -6481,11 +7002,16 @@ class StubGenerator: public StubCodeGenerator { // coeffs (int[256]) = c_rarg0 // zetas (int[256]) = c_rarg1 address generate_dilithiumAlmostNtt() { - - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_dilithiumAlmostNtt_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); __ enter(); const Register coeffs = c_rarg0; @@ -6596,6 +7122,9 @@ class StubGenerator: public StubCodeGenerator { __ mov(r0, zr); // return 0 __ ret(lr); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -6688,11 +7217,16 @@ class StubGenerator: public StubCodeGenerator { // coeffs (int[256]) = c_rarg0 // zetas (int[256]) = c_rarg1 address generate_dilithiumAlmostInverseNtt() { - - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_dilithiumAlmostInverseNtt_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); __ enter(); const Register coeffs = c_rarg0; @@ -6788,6 +7322,9 @@ class StubGenerator: public StubCodeGenerator { __ mov(r0, zr); // return 0 __ ret(lr); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -6801,11 +7338,16 @@ class StubGenerator: public StubCodeGenerator { // poly1 (int[256]) = c_rarg1 // poly2 (int[256]) = c_rarg2 address generate_dilithiumNttMult() { - - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_dilithiumNttMult_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); __ enter(); Label L_loop; @@ -6854,6 +7396,9 @@ class StubGenerator: public StubCodeGenerator { __ mov(r0, zr); // return 0 __ ret(lr); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -6865,11 +7410,16 @@ class StubGenerator: public StubCodeGenerator { // coeffs (int[256]) = c_rarg0 // constant (int) = c_rarg1 address generate_dilithiumMontMulByConstant() { - - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_dilithiumMontMulByConstant_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); __ enter(); Label L_loop; @@ -6915,6 +7465,9 @@ class StubGenerator: public StubCodeGenerator { __ mov(r0, zr); // return 0 __ ret(lr); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -6929,11 +7482,16 @@ class StubGenerator: public StubCodeGenerator { // twoGamma2 (int) = c_rarg3 // multiplier (int) = c_rarg4 address generate_dilithiumDecomposePoly() { - - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_dilithiumDecomposePoly_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); Label L_loop; const Register input = c_rarg0; @@ -7073,6 +7631,9 @@ class StubGenerator: public StubCodeGenerator { __ mov(r0, zr); // return 0 __ ret(lr); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -7212,21 +7773,15 @@ class StubGenerator: public StubCodeGenerator { default: ShouldNotReachHere(); } - - 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 - }; - + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); Register buf = c_rarg0; Register state = c_rarg1; @@ -7378,7 +7933,7 @@ class StubGenerator: public StubCodeGenerator { __ fmovs(v1, 1.0); // exact representation __ str(buf, Address(sp, 16)); - __ lea(tmp3, ExternalAddress((address) round_consts)); + __ lea(tmp3, ExternalAddress((address) _sha3_round_consts)); __ BIND(loop_body); keccak_round_gpr(can_use_fp, can_use_r18, tmp3, @@ -7433,6 +7988,9 @@ class StubGenerator: public StubCodeGenerator { __ ret(lr); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -7449,12 +8007,17 @@ class StubGenerator: public StubCodeGenerator { */ address generate_updateBytesCRC32() { assert(UseCRC32Intrinsics, "what are we doing here?"); - - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_updateBytesCRC32_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); const Register crc = c_rarg0; // crc const Register buf = c_rarg1; // source java byte array address @@ -7474,6 +8037,9 @@ class StubGenerator: public StubCodeGenerator { __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(lr); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -7491,12 +8057,17 @@ class StubGenerator: public StubCodeGenerator { */ address generate_updateBytesCRC32C() { assert(UseCRC32CIntrinsics, "what are we doing here?"); - - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_updateBytesCRC32C_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); const Register crc = c_rarg0; // crc const Register buf = c_rarg1; // source java byte array address @@ -7516,6 +8087,9 @@ class StubGenerator: public StubCodeGenerator { __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(lr); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -7531,10 +8105,16 @@ class StubGenerator: public StubCodeGenerator { * c_rarg0 - int adler result */ address generate_updateBytesAdler32() { - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_updateBytesAdler32_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); Label L_simple_by1_loop, L_nmax, L_nmax_loop, L_by16, L_by16_loop, L_by1_loop, L_do_mod, L_combine, L_by1; @@ -7702,6 +8282,9 @@ class StubGenerator: public StubCodeGenerator { __ ret(lr); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -7753,11 +8336,17 @@ class StubGenerator: public StubCodeGenerator { * c_rarg4 - z address */ address generate_multiplyToLen() { - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_multiplyToLen_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); const Register x = r0; const Register xlen = r1; const Register y = r2; @@ -7779,6 +8368,9 @@ class StubGenerator: public StubCodeGenerator { __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(lr); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -7786,10 +8378,16 @@ class StubGenerator: public StubCodeGenerator { // squareToLen algorithm for sizes 1..127 described in java code works // faster than multiply_to_len on some CPUs and slower on others, but // multiply_to_len shows a bit better overall results - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_squareToLen_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); const Register x = r0; const Register xlen = r1; @@ -7816,15 +8414,25 @@ class StubGenerator: public StubCodeGenerator { __ pop(spilled_regs, sp); __ leave(); __ ret(lr); + + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } address generate_mulAdd() { - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_mulAdd_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); const Register out = r0; const Register in = r1; @@ -7838,6 +8446,9 @@ class StubGenerator: public StubCodeGenerator { __ leave(); __ ret(lr); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -7851,10 +8462,16 @@ class StubGenerator: public StubCodeGenerator { // c_rarg4 - numIter // address generate_bigIntegerRightShift() { - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_bigIntegerRightShiftWorker_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); Label ShiftSIMDLoop, ShiftTwoLoop, ShiftThree, ShiftTwo, ShiftOne, Exit; @@ -7961,6 +8578,9 @@ class StubGenerator: public StubCodeGenerator { __ BIND(Exit); __ ret(lr); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -7974,10 +8594,16 @@ class StubGenerator: public StubCodeGenerator { // c_rarg4 - numIter // address generate_bigIntegerLeftShift() { - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_bigIntegerLeftShiftWorker_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); Label ShiftSIMDLoop, ShiftTwoLoop, ShiftThree, ShiftTwo, ShiftOne, Exit; @@ -8072,10 +8698,25 @@ class StubGenerator: public StubCodeGenerator { __ BIND(Exit); __ ret(lr); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } address generate_count_positives(address &count_positives_long) { + StubId stub_id = StubId::stubgen_count_positives_id; + GrowableArray
entries; + int entry_count = StubInfo::entry_count(stub_id); + // We have an extra entry for count_positives_long. + assert(entry_count == 2, "sanity check"); + address start = load_archive_data(stub_id, &entries); + if (start != nullptr) { + assert(entries.length() == 1, + "unexpected extra entry count %d", entries.length()); + count_positives_long = entries.at(0); + return start; + } const u1 large_loop_size = 64; const uint64_t UPPER_BIT_MASK=0x8080808080808080; int dcache_line = VM_Version::dcache_line_size(); @@ -8083,8 +8724,6 @@ class StubGenerator: public StubCodeGenerator { Register ary1 = r1, len = r2, result = r0; __ align(CodeEntryAlignment); - - StubId stub_id = StubId::stubgen_count_positives_id; StubCodeMark mark(this, stub_id); address entry = __ pc(); @@ -8127,6 +8766,7 @@ class StubGenerator: public StubCodeGenerator { const RegSet spilled_regs = RegSet::range(tmp1, tmp5) + tmp6; count_positives_long = __ pc(); // 2nd entry point + entries.append(count_positives_long); __ enter(); @@ -8241,6 +8881,9 @@ class StubGenerator: public StubCodeGenerator { __ sub(result, result, len); __ ret(lr); + // record the stub entry and end plus the extra entry + store_archive_data(stub_id, entry, __ pc(), &entries); + return entry; } @@ -8331,6 +8974,13 @@ class StubGenerator: public StubCodeGenerator { // r3-r5 are reserved temporary registers // Clobbers: v0-v7 when UseSIMDForArrayEquals, rscratch1, rscratch2 address generate_large_array_equals() { + StubId stub_id = StubId::stubgen_large_array_equals_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } Register a1 = r1, a2 = r2, result = r0, cnt1 = r10, tmp1 = rscratch1, tmp2 = rscratch2, tmp3 = r3, tmp4 = r4, tmp5 = r5, tmp6 = r11, tmp7 = r12, tmp8 = r13; @@ -8346,7 +8996,6 @@ class StubGenerator: public StubCodeGenerator { __ align(CodeEntryAlignment); - StubId stub_id = StubId::stubgen_large_array_equals_id; StubCodeMark mark(this, stub_id); address entry = __ pc(); @@ -8421,6 +9070,10 @@ class StubGenerator: public StubCodeGenerator { __ bind(NOT_EQUAL_NO_POP); __ leave(); __ ret(lr); + + // record the stub entry and end + store_archive_data(stub_id, entry, __ pc()); + return entry; } @@ -8429,6 +9082,33 @@ class StubGenerator: public StubCodeGenerator { // cnt = r2 - elements count // Clobbers: v0-v13, rscratch1, rscratch2 address generate_large_arrays_hashcode(BasicType eltype) { + StubId stub_id; + switch (eltype) { + case T_BOOLEAN: + stub_id = StubId::stubgen_large_arrays_hashcode_boolean_id; + break; + case T_BYTE: + stub_id = StubId::stubgen_large_arrays_hashcode_byte_id; + break; + case T_CHAR: + stub_id = StubId::stubgen_large_arrays_hashcode_char_id; + break; + case T_SHORT: + stub_id = StubId::stubgen_large_arrays_hashcode_short_id; + break; + case T_INT: + stub_id = StubId::stubgen_large_arrays_hashcode_int_id; + break; + default: + stub_id = StubId::NO_STUBID; + ShouldNotReachHere(); + }; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } const Register result = r0, ary = r1, cnt = r2; const FloatRegister vdata0 = v3, vdata1 = v2, vdata2 = v1, vdata3 = v0; const FloatRegister vmul0 = v4, vmul1 = v5, vmul2 = v6, vmul3 = v7; @@ -8472,28 +9152,6 @@ class StubGenerator: public StubCodeGenerator { __ align(CodeEntryAlignment); - StubId stub_id; - switch (eltype) { - case T_BOOLEAN: - stub_id = StubId::stubgen_large_arrays_hashcode_boolean_id; - break; - case T_BYTE: - stub_id = StubId::stubgen_large_arrays_hashcode_byte_id; - break; - case T_CHAR: - stub_id = StubId::stubgen_large_arrays_hashcode_char_id; - break; - case T_SHORT: - stub_id = StubId::stubgen_large_arrays_hashcode_short_id; - break; - case T_INT: - stub_id = StubId::stubgen_large_arrays_hashcode_int_id; - break; - default: - stub_id = StubId::NO_STUBID; - ShouldNotReachHere(); - }; - StubCodeMark mark(this, stub_id); address entry = __ pc(); @@ -8728,19 +9386,32 @@ class StubGenerator: public StubCodeGenerator { __ leave(); __ ret(lr); + // record the stub entry and end + store_archive_data(stub_id, entry, __ pc()); + return entry; } address generate_dsin_dcos(bool isCos) { - __ align(CodeEntryAlignment); StubId stub_id = (isCos ? StubId::stubgen_dcos_id : StubId::stubgen_dsin_id); + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); __ generate_dsin_dcos(isCos, (address)StubRoutines::aarch64::_npio2_hw, (address)StubRoutines::aarch64::_two_over_pi, (address)StubRoutines::aarch64::_pio2, (address)StubRoutines::aarch64::_dsin_coef, (address)StubRoutines::aarch64::_dcos_coef); + + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -8784,8 +9455,14 @@ class StubGenerator: public StubCodeGenerator { // r10 = tmp1 // r11 = tmp2 address generate_compare_long_string_different_encoding(bool isLU) { - __ align(CodeEntryAlignment); StubId stub_id = (isLU ? StubId::stubgen_compare_long_string_LU_id : StubId::stubgen_compare_long_string_UL_id); + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); address entry = __ pc(); Label SMALL_LOOP, TAIL, TAIL_LOAD_16, LOAD_LAST, DIFF1, DIFF2, @@ -8887,20 +9564,34 @@ class StubGenerator: public StubCodeGenerator { __ subw(result, tmp1, rscratch1); __ bind(DONE); __ ret(lr); - return entry; + + // record the stub entry and end + store_archive_data(stub_id, entry, __ pc()); + + return entry; } // r0 = input (float16) // v0 = result (float) // v1 = temporary float register address generate_float16ToFloat() { - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_hf2f_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); address entry = __ pc(); BLOCK_COMMENT("Entry:"); __ flt16_to_flt(v0, r0, v1); __ ret(lr); + + // record the stub entry and end + store_archive_data(stub_id, entry, __ pc()); + return entry; } @@ -8908,24 +9599,40 @@ class StubGenerator: public StubCodeGenerator { // r0 = result (float16) // v1 = temporary float register address generate_floatToFloat16() { - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_f2hf_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); address entry = __ pc(); BLOCK_COMMENT("Entry:"); __ flt_to_flt16(r0, v0, v1); __ ret(lr); + + // record the stub entry and end + store_archive_data(stub_id, entry, __ pc()); + return entry; } address generate_method_entry_barrier() { - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_method_entry_barrier_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); Label deoptimize_label; - address start = __ pc(); + start = __ pc(); BarrierSetAssembler* bs_asm = BarrierSet::barrier_set()->barrier_set_assembler(); @@ -8974,6 +9681,9 @@ class StubGenerator: public StubCodeGenerator { __ mov(sp, rscratch1); __ br(rscratch2); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -8985,8 +9695,14 @@ class StubGenerator: public StubCodeGenerator { // r10 = tmp1 // r11 = tmp2 address generate_compare_long_string_same_encoding(bool isLL) { - __ align(CodeEntryAlignment); StubId stub_id = (isLL ? StubId::stubgen_compare_long_string_LL_id : StubId::stubgen_compare_long_string_UU_id); + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); address entry = __ pc(); Register result = r0, str1 = r1, cnt1 = r2, str2 = r3, cnt2 = r4, @@ -9094,6 +9810,10 @@ class StubGenerator: public StubCodeGenerator { __ bind(LENGTH_DIFF); __ ret(lr); + + // record the stub entry and end + store_archive_data(stub_id, entry, __ pc()); + return entry; } @@ -9125,8 +9845,14 @@ class StubGenerator: public StubCodeGenerator { case UU: stub_id = StubId::stubgen_compare_long_string_UU_id; break; default: ShouldNotReachHere(); } - + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } __ align(CodeEntryAlignment); + StubCodeMark mark(this, stub_id); address entry = __ pc(); Register result = r0, str1 = r1, cnt1 = r2, str2 = r3, cnt2 = r4, tmp1 = r10, tmp2 = r11; @@ -9161,8 +9887,6 @@ class StubGenerator: public StubCodeGenerator { ShouldNotReachHere(); \ } - StubCodeMark mark(this, stub_id); - __ mov(idx, 0); __ sve_whilelt(pgtmp1, mode == LL ? __ B : __ H, idx, cnt); @@ -9206,6 +9930,10 @@ class StubGenerator: public StubCodeGenerator { __ bind(DONE); __ ret(lr); #undef LOAD_PAIR + + // record the stub entry and end + store_archive_data(stub_id, entry, __ pc()); + return entry; } @@ -9267,6 +9995,12 @@ class StubGenerator: public StubCodeGenerator { stub_id = StubId::stubgen_string_indexof_linear_uu_id; } } + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); address entry = __ pc(); @@ -9535,6 +10269,10 @@ class StubGenerator: public StubCodeGenerator { __ BIND(DONE); __ pop(spilled_regs, sp); __ ret(lr); + + // record the stub entry and end + store_archive_data(stub_id, entry, __ pc()); + return entry; } @@ -9565,8 +10303,14 @@ class StubGenerator: public StubCodeGenerator { // v1 = loaded 8 bytes // Clobbers: r0, r1, r3, rscratch1, rflags, v0-v6 address generate_large_byte_array_inflate() { - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_large_byte_array_inflate_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); address entry = __ pc(); Label LOOP, LOOP_START, LOOP_PRFM, LOOP_PRFM_START, DONE; @@ -9605,6 +10349,10 @@ class StubGenerator: public StubCodeGenerator { __ br(__ GE, LOOP); __ bind(DONE); __ ret(lr); + + // record the stub entry and end + store_archive_data(stub_id, entry, __ pc()); + return entry; } @@ -9620,7 +10368,7 @@ class StubGenerator: public StubCodeGenerator { * Output: * Updated state at c_rarg0 */ - address generate_ghash_processBlocks() { + address generate_ghash_processBlocks_small() { // Bafflingly, GCM uses little-endian for the byte order, but // big-endian for the bit order. For example, the polynomial 1 is // represented as the 16-byte string 80 00 00 00 | 12 bytes of 00. @@ -9632,11 +10380,17 @@ class StubGenerator: public StubCodeGenerator { // that) and keep the data in little-endian bit order through the // calculation, bit-reversing the inputs and outputs. - StubId stub_id = StubId::stubgen_ghash_processBlocks_id; + StubId stub_id = StubId::stubgen_ghash_processBlocks_small_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); Label polynomial; // local data generated at end of stub - __ align(CodeEntryAlignment); - address start = __ pc(); + start = __ pc(); Register state = c_rarg0; Register subkeyH = c_rarg1; @@ -9696,17 +10450,24 @@ class StubGenerator: public StubCodeGenerator { // 128-bit vector __ emit_int64(0x87); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } - address generate_ghash_processBlocks_wide() { - address small = generate_ghash_processBlocks(); - - StubId stub_id = StubId::stubgen_ghash_processBlocks_wide_id; - StubCodeMark mark(this, stub_id); + address generate_ghash_processBlocks(address small) { + StubId stub_id = StubId::stubgen_ghash_processBlocks_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } Label polynomial; // local data generated after stub __ align(CodeEntryAlignment); - address start = __ pc(); + StubCodeMark mark(this, stub_id); + start = __ pc(); Register state = c_rarg0; Register subkeyH = c_rarg1; @@ -9748,8 +10509,10 @@ class StubGenerator: public StubCodeGenerator { // 128-bit vector __ emit_int64(0x87); - return start; + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } void generate_base64_encode_simdround(Register src, Register dst, @@ -9800,26 +10563,16 @@ class StubGenerator: public StubCodeGenerator { */ address generate_base64_encodeBlock() { - static const char toBase64[64] = { - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', - 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', - 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', - 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' - }; - - static const char toBase64URL[64] = { - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', - 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', - 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', - 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_' - }; - - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_base64_encodeBlock_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); Register src = c_rarg0; // source array Register soff = c_rarg1; // source start offset @@ -9839,9 +10592,9 @@ class StubGenerator: public StubCodeGenerator { __ sub(length, send, soff); // load the codec base address - __ lea(codec, ExternalAddress((address) toBase64)); + __ lea(codec, ExternalAddress((address) _encodeBlock_toBase64)); __ cbz(isURL, ProcessData); - __ lea(codec, ExternalAddress((address) toBase64URL)); + __ lea(codec, ExternalAddress((address) _encodeBlock_toBase64URL)); __ BIND(ProcessData); @@ -9894,6 +10647,9 @@ class StubGenerator: public StubCodeGenerator { __ BIND(Exit); __ ret(lr); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -10015,80 +10771,16 @@ class StubGenerator: public StubCodeGenerator { // on http://0x80.pl/articles/base64-simd-neon.html#encoding-quadwords, in section // titled "Base64 decoding". - // Non-SIMD lookup tables are mostly dumped from fromBase64 array used in java.util.Base64, - // except the trailing character '=' is also treated illegal value in this intrinsic. That - // is java.util.Base64.fromBase64['='] = -2, while fromBase(URL)64ForNoSIMD['='] = 255 here. - static const uint8_t fromBase64ForNoSIMD[256] = { - 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, - 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, - 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 62u, 255u, 255u, 255u, 63u, - 52u, 53u, 54u, 55u, 56u, 57u, 58u, 59u, 60u, 61u, 255u, 255u, 255u, 255u, 255u, 255u, - 255u, 0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 9u, 10u, 11u, 12u, 13u, 14u, - 15u, 16u, 17u, 18u, 19u, 20u, 21u, 22u, 23u, 24u, 25u, 255u, 255u, 255u, 255u, 255u, - 255u, 26u, 27u, 28u, 29u, 30u, 31u, 32u, 33u, 34u, 35u, 36u, 37u, 38u, 39u, 40u, - 41u, 42u, 43u, 44u, 45u, 46u, 47u, 48u, 49u, 50u, 51u, 255u, 255u, 255u, 255u, 255u, - 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, - 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, - 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, - 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, - 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, - 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, - 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, - 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, - }; - - static const uint8_t fromBase64URLForNoSIMD[256] = { - 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, - 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, - 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 62u, 255u, 255u, - 52u, 53u, 54u, 55u, 56u, 57u, 58u, 59u, 60u, 61u, 255u, 255u, 255u, 255u, 255u, 255u, - 255u, 0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 9u, 10u, 11u, 12u, 13u, 14u, - 15u, 16u, 17u, 18u, 19u, 20u, 21u, 22u, 23u, 24u, 25u, 255u, 255u, 255u, 255u, 63u, - 255u, 26u, 27u, 28u, 29u, 30u, 31u, 32u, 33u, 34u, 35u, 36u, 37u, 38u, 39u, 40u, - 41u, 42u, 43u, 44u, 45u, 46u, 47u, 48u, 49u, 50u, 51u, 255u, 255u, 255u, 255u, 255u, - 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, - 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, - 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, - 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, - 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, - 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, - 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, - 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, - }; - - // A legal value of base64 code is in range [0, 127]. We need two lookups - // with tbl/tbx and combine them to get the decode data. The 1st table vector - // lookup use tbl, out of range indices are set to 0 in destination. The 2nd - // table vector lookup use tbx, out of range indices are unchanged in - // destination. Input [64..126] is mapped to index [65, 127] in second lookup. - // The value of index 64 is set to 0, so that we know that we already get the - // decoded data with the 1st lookup. - static const uint8_t fromBase64ForSIMD[128] = { - 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, - 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, - 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 62u, 255u, 255u, 255u, 63u, - 52u, 53u, 54u, 55u, 56u, 57u, 58u, 59u, 60u, 61u, 255u, 255u, 255u, 255u, 255u, 255u, - 0u, 255u, 0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 9u, 10u, 11u, 12u, 13u, - 14u, 15u, 16u, 17u, 18u, 19u, 20u, 21u, 22u, 23u, 24u, 25u, 255u, 255u, 255u, 255u, - 255u, 255u, 26u, 27u, 28u, 29u, 30u, 31u, 32u, 33u, 34u, 35u, 36u, 37u, 38u, 39u, - 40u, 41u, 42u, 43u, 44u, 45u, 46u, 47u, 48u, 49u, 50u, 51u, 255u, 255u, 255u, 255u, - }; - - static const uint8_t fromBase64URLForSIMD[128] = { - 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, - 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, - 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 62u, 255u, 255u, - 52u, 53u, 54u, 55u, 56u, 57u, 58u, 59u, 60u, 61u, 255u, 255u, 255u, 255u, 255u, 255u, - 0u, 255u, 0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 9u, 10u, 11u, 12u, 13u, - 14u, 15u, 16u, 17u, 18u, 19u, 20u, 21u, 22u, 23u, 24u, 25u, 255u, 255u, 255u, 255u, - 63u, 255u, 26u, 27u, 28u, 29u, 30u, 31u, 32u, 33u, 34u, 35u, 36u, 37u, 38u, 39u, - 40u, 41u, 42u, 43u, 44u, 45u, 46u, 47u, 48u, 49u, 50u, 51u, 255u, 255u, 255u, 255u, - }; - - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_base64_decodeBlock_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); Register src = c_rarg0; // source array Register soff = c_rarg1; // source start offset @@ -10115,9 +10807,9 @@ class StubGenerator: public StubCodeGenerator { __ sub(length, send, soff); __ bfm(length, zr, 0, 1); - __ lea(nosimd_codec, ExternalAddress((address) fromBase64ForNoSIMD)); + __ lea(nosimd_codec, ExternalAddress((address) _decodeBlock_fromBase64ForNoSIMD)); __ cbz(isURL, ProcessData); - __ lea(nosimd_codec, ExternalAddress((address) fromBase64URLForNoSIMD)); + __ lea(nosimd_codec, ExternalAddress((address) _decodeBlock_fromBase64URLForNoSIMD)); __ BIND(ProcessData); __ mov(rscratch1, length); @@ -10162,9 +10854,9 @@ class StubGenerator: public StubCodeGenerator { __ cbzw(rscratch1, Exit); __ sub(length, length, 80); - __ lea(simd_codec, ExternalAddress((address) fromBase64ForSIMD)); + __ lea(simd_codec, ExternalAddress((address) _decodeBlock_fromBase64ForSIMD)); __ cbz(isURL, SIMDEnter); - __ lea(simd_codec, ExternalAddress((address) fromBase64URLForSIMD)); + __ lea(simd_codec, ExternalAddress((address) _decodeBlock_fromBase64URLForSIMD)); __ BIND(SIMDEnter); __ ld1(v0, v1, v2, v3, __ T16B, __ post(simd_codec, 64)); @@ -10197,24 +10889,50 @@ class StubGenerator: public StubCodeGenerator { __ leave(); __ ret(lr); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } // Support for spin waits. address generate_spin_wait() { - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_spin_wait_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); __ spin_wait(); __ ret(lr); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } void generate_lookup_secondary_supers_table_stub() { StubId stub_id = StubId::stubgen_lookup_secondary_supers_table_id; + GrowableArray
entries; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == Klass::SECONDARY_SUPERS_TABLE_SIZE, "sanity check"); + address start = load_archive_data(stub_id, &entries); + if (start != nullptr) { + assert(entries.length() == Klass::SECONDARY_SUPERS_TABLE_SIZE - 1, + "unexpected extra entry count %d", entries.length()); + StubRoutines::_lookup_secondary_supers_table_stubs[0] = start; + for (int slot = 1; slot < Klass::SECONDARY_SUPERS_TABLE_SIZE; slot++) { + StubRoutines::_lookup_secondary_supers_table_stubs[slot] = entries.at(slot - 1); + } + return; + } + StubCodeMark mark(this, stub_id); const Register @@ -10229,7 +10947,13 @@ class StubGenerator: public StubCodeGenerator { vtemp = v0; for (int slot = 0; slot < Klass::SECONDARY_SUPERS_TABLE_SIZE; slot++) { - StubRoutines::_lookup_secondary_supers_table_stubs[slot] = __ pc(); + address next_entry = __ pc(); + StubRoutines::_lookup_secondary_supers_table_stubs[slot] = next_entry; + if (slot == 0) { + start = next_entry; + } else { + entries.append(next_entry); + } Label L_success; __ enter(); __ lookup_secondary_supers_table_const(r_sub_klass, r_super_klass, @@ -10239,14 +10963,21 @@ class StubGenerator: public StubCodeGenerator { __ leave(); __ ret(lr); } + // record the stub entry and end plus all the auxiliary entries + store_archive_data(stub_id, start, __ pc(), &entries); } // Slow path implementation for UseSecondarySupersTable. address generate_lookup_secondary_supers_table_slow_path_stub() { StubId stub_id = StubId::stubgen_lookup_secondary_supers_table_slow_path_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } StubCodeMark mark(this, stub_id); - - address start = __ pc(); + start = __ pc(); const Register r_super_klass = r0, // argument r_array_base = r1, // argument @@ -10258,6 +10989,9 @@ class StubGenerator: public StubCodeGenerator { __ lookup_secondary_supers_table_slow_path(r_super_klass, r_array_base, r_array_index, r_bitmap, temp1, result); __ ret(lr); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -10397,14 +11131,43 @@ class StubGenerator: public StubCodeGenerator { if (! UseLSE) { return; } - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_atomic_entry_points_id; - StubCodeMark mark(this, stub_id); - address first_entry = __ pc(); + GrowableArray
entries; + int entry_count = StubInfo::entry_count(stub_id); + address start = load_archive_data(stub_id, &entries); + if (start != nullptr) { + assert(entries.length() == entry_count - 1, + "unexpected extra entry count %d", entries.length()); + aarch64_atomic_fetch_add_4_impl = (aarch64_atomic_stub_t)start; + int idx = 0; + aarch64_atomic_fetch_add_8_impl = (aarch64_atomic_stub_t)entries.at(idx++); + aarch64_atomic_fetch_add_4_relaxed_impl = (aarch64_atomic_stub_t)entries.at(idx++); + aarch64_atomic_fetch_add_8_relaxed_impl = (aarch64_atomic_stub_t)entries.at(idx++); + aarch64_atomic_xchg_4_impl = (aarch64_atomic_stub_t)entries.at(idx++); + aarch64_atomic_xchg_8_impl = (aarch64_atomic_stub_t)entries.at(idx++); + aarch64_atomic_cmpxchg_1_impl = (aarch64_atomic_stub_t)entries.at(idx++); + aarch64_atomic_cmpxchg_4_impl = (aarch64_atomic_stub_t)entries.at(idx++); + aarch64_atomic_cmpxchg_8_impl = (aarch64_atomic_stub_t)entries.at(idx++); + aarch64_atomic_cmpxchg_1_relaxed_impl = (aarch64_atomic_stub_t)entries.at(idx++); + aarch64_atomic_cmpxchg_4_relaxed_impl = (aarch64_atomic_stub_t)entries.at(idx++); + aarch64_atomic_cmpxchg_8_relaxed_impl = (aarch64_atomic_stub_t)entries.at(idx++); + aarch64_atomic_cmpxchg_4_release_impl = (aarch64_atomic_stub_t)entries.at(idx++); + aarch64_atomic_cmpxchg_8_release_impl = (aarch64_atomic_stub_t)entries.at(idx++); + aarch64_atomic_cmpxchg_4_seq_cst_impl = (aarch64_atomic_stub_t)entries.at(idx++); + aarch64_atomic_cmpxchg_8_seq_cst_impl = (aarch64_atomic_stub_t)entries.at(idx++); + assert(idx == entries.length(), "sanity!"); + return; + } + __ align(CodeEntryAlignment); + StubCodeMark mark(this, stub_id); + start = __ pc(); + address end; + { // ADD, memory_order_conservative AtomicStubMark mark_fetch_add_4(_masm, &aarch64_atomic_fetch_add_4_impl); gen_ldadd_entry(Assembler::word, memory_order_conservative); + AtomicStubMark mark_fetch_add_8(_masm, &aarch64_atomic_fetch_add_8_impl); gen_ldadd_entry(Assembler::xword, memory_order_conservative); @@ -10412,6 +11175,7 @@ class StubGenerator: public StubCodeGenerator { AtomicStubMark mark_fetch_add_4_relaxed (_masm, &aarch64_atomic_fetch_add_4_relaxed_impl); gen_ldadd_entry(MacroAssembler::word, memory_order_relaxed); + AtomicStubMark mark_fetch_add_8_relaxed (_masm, &aarch64_atomic_fetch_add_8_relaxed_impl); gen_ldadd_entry(MacroAssembler::xword, memory_order_relaxed); @@ -10419,14 +11183,17 @@ class StubGenerator: public StubCodeGenerator { // XCHG, memory_order_conservative AtomicStubMark mark_xchg_4(_masm, &aarch64_atomic_xchg_4_impl); gen_swpal_entry(Assembler::word); - AtomicStubMark mark_xchg_8_impl(_masm, &aarch64_atomic_xchg_8_impl); + + AtomicStubMark mark_xchg_8(_masm, &aarch64_atomic_xchg_8_impl); gen_swpal_entry(Assembler::xword); // CAS, memory_order_conservative AtomicStubMark mark_cmpxchg_1(_masm, &aarch64_atomic_cmpxchg_1_impl); gen_cas_entry(MacroAssembler::byte, memory_order_conservative); + AtomicStubMark mark_cmpxchg_4(_masm, &aarch64_atomic_cmpxchg_4_impl); gen_cas_entry(MacroAssembler::word, memory_order_conservative); + AtomicStubMark mark_cmpxchg_8(_masm, &aarch64_atomic_cmpxchg_8_impl); gen_cas_entry(MacroAssembler::xword, memory_order_conservative); @@ -10434,9 +11201,11 @@ class StubGenerator: public StubCodeGenerator { AtomicStubMark mark_cmpxchg_1_relaxed (_masm, &aarch64_atomic_cmpxchg_1_relaxed_impl); gen_cas_entry(MacroAssembler::byte, memory_order_relaxed); + AtomicStubMark mark_cmpxchg_4_relaxed (_masm, &aarch64_atomic_cmpxchg_4_relaxed_impl); gen_cas_entry(MacroAssembler::word, memory_order_relaxed); + AtomicStubMark mark_cmpxchg_8_relaxed (_masm, &aarch64_atomic_cmpxchg_8_relaxed_impl); gen_cas_entry(MacroAssembler::xword, memory_order_relaxed); @@ -10444,6 +11213,7 @@ class StubGenerator: public StubCodeGenerator { AtomicStubMark mark_cmpxchg_4_release (_masm, &aarch64_atomic_cmpxchg_4_release_impl); gen_cas_entry(MacroAssembler::word, memory_order_release); + AtomicStubMark mark_cmpxchg_8_release (_masm, &aarch64_atomic_cmpxchg_8_release_impl); gen_cas_entry(MacroAssembler::xword, memory_order_release); @@ -10451,11 +11221,41 @@ class StubGenerator: public StubCodeGenerator { AtomicStubMark mark_cmpxchg_4_seq_cst (_masm, &aarch64_atomic_cmpxchg_4_seq_cst_impl); gen_cas_entry(MacroAssembler::word, memory_order_seq_cst); + AtomicStubMark mark_cmpxchg_8_seq_cst (_masm, &aarch64_atomic_cmpxchg_8_seq_cst_impl); gen_cas_entry(MacroAssembler::xword, memory_order_seq_cst); - ICache::invalidate_range(first_entry, __ pc() - first_entry); + end = __ pc(); + + ICache::invalidate_range(start, end - start); + // exit block to force update of AtomicStubMark targets + } + + assert(start == (address)aarch64_atomic_fetch_add_4_impl, + "atomic stub should be at start of buffer"); + // record the stub start and end plus all the entries saved by the + // AtomicStubMark destructor + entries.append((address)aarch64_atomic_fetch_add_8_impl); + entries.append((address)aarch64_atomic_fetch_add_4_relaxed_impl); + entries.append((address)aarch64_atomic_fetch_add_8_relaxed_impl); + entries.append((address)aarch64_atomic_xchg_4_impl); + entries.append((address)aarch64_atomic_xchg_8_impl); + entries.append((address)aarch64_atomic_cmpxchg_1_impl); + entries.append((address)aarch64_atomic_cmpxchg_4_impl); + entries.append((address)aarch64_atomic_cmpxchg_8_impl); + entries.append((address)aarch64_atomic_cmpxchg_1_relaxed_impl); + entries.append((address)aarch64_atomic_cmpxchg_4_relaxed_impl); + entries.append((address)aarch64_atomic_cmpxchg_8_relaxed_impl); + entries.append((address)aarch64_atomic_cmpxchg_4_release_impl); + entries.append((address)aarch64_atomic_cmpxchg_8_release_impl); + entries.append((address)aarch64_atomic_cmpxchg_4_seq_cst_impl); + entries.append((address)aarch64_atomic_cmpxchg_8_seq_cst_impl); + + assert(entries.length() == entry_count - 1, + "unexpected extra entry count %d", entries.length()); + + store_archive_data(stub_id, start, end, &entries); } #endif // LINUX @@ -10559,9 +11359,19 @@ class StubGenerator: public StubCodeGenerator { if (!Continuations::enabled()) return nullptr; StubId stub_id = StubId::stubgen_cont_thaw_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); generate_cont_thaw(Continuation::thaw_top); + + // record the stub start and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -10570,11 +11380,20 @@ class StubGenerator: public StubCodeGenerator { // TODO: will probably need multiple return barriers depending on return type StubId stub_id = StubId::stubgen_cont_returnBarrier_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); generate_cont_thaw(Continuation::thaw_return_barrier); + // record the stub start and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -10582,19 +11401,34 @@ class StubGenerator: public StubCodeGenerator { if (!Continuations::enabled()) return nullptr; StubId stub_id = StubId::stubgen_cont_returnBarrierExc_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); generate_cont_thaw(Continuation::thaw_return_barrier_exception); + // record the stub start and end + store_archive_data(stub_id, start, __ pc()); + return start; } address generate_cont_preempt_stub() { if (!Continuations::enabled()) return nullptr; StubId stub_id = StubId::stubgen_cont_preempt_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); __ reset_last_Java_frame(true); @@ -10619,6 +11453,9 @@ class StubGenerator: public StubCodeGenerator { __ ldr(rscratch1, Address(rscratch1)); __ br(rscratch1); + // record the stub start and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -10674,10 +11511,16 @@ class StubGenerator: public StubCodeGenerator { // computation. address generate_poly1305_processBlocks() { - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_poly1305_processBlocks_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); Label here; __ enter(); RegSet callee_saved = RegSet::range(r19, r28); @@ -10785,14 +11628,23 @@ class StubGenerator: public StubCodeGenerator { __ leave(); __ ret(lr); + // record the stub start and end + store_archive_data(stub_id, start, __ pc()); + return start; } // exception handler for upcall stubs address generate_upcall_stub_exception_handler() { StubId stub_id = StubId::stubgen_upcall_stub_exception_handler_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); // Native caller has no idea how to handle exceptions, // so we just crash here. Up to callee to catch exceptions. @@ -10801,6 +11653,9 @@ class StubGenerator: public StubCodeGenerator { __ blr(rscratch1); __ should_not_reach_here(); + // record the stub start and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -10809,8 +11664,14 @@ class StubGenerator: public StubCodeGenerator { // rmethod = result address generate_upcall_stub_load_target() { StubId stub_id = StubId::stubgen_upcall_stub_load_target_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); __ resolve_global_jobject(j_rarg0, rscratch1, rscratch2); // Load target method from receiver @@ -10824,6 +11685,9 @@ class StubGenerator: public StubCodeGenerator { __ ret(lr); + // record the stub start and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -11223,8 +12087,6 @@ class StubGenerator: public StubCodeGenerator { */ address generate_multiply() { Label argh, nothing; - bind(argh); - stop("MontgomeryMultiply total_allocation must be <= 8192"); align(CodeEntryAlignment); address entry = pc(); @@ -11331,6 +12193,10 @@ class StubGenerator: public StubCodeGenerator { bind(nothing); ret(lr); + // handler for error case + bind(argh); + stop("MontgomeryMultiply total_allocation must be <= 8192"); + return entry; } // In C, approximately: @@ -11434,8 +12300,6 @@ class StubGenerator: public StubCodeGenerator { */ address generate_square() { Label argh; - bind(argh); - stop("MontgomeryMultiply total_allocation must be <= 8192"); align(CodeEntryAlignment); address entry = pc(); @@ -11544,6 +12408,10 @@ class StubGenerator: public StubCodeGenerator { leave(); ret(lr); + // handler for error case + bind(argh); + stop("MontgomeryMultiply total_allocation must be <= 8192"); + return entry; } // In C, approximately: @@ -11798,18 +12666,32 @@ class StubGenerator: public StubCodeGenerator { if (UseMontgomeryMultiplyIntrinsic) { StubId stub_id = StubId::stubgen_montgomeryMultiply_id; - StubCodeMark mark(this, stub_id); - MontgomeryMultiplyGenerator g(_masm, /*squaring*/false); - StubRoutines::_montgomeryMultiply = g.generate_multiply(); + address start = load_archive_data(stub_id); + if (start == nullptr) { + // we have to generate it + StubCodeMark mark(this, stub_id); + MontgomeryMultiplyGenerator g(_masm, /*squaring*/false); + start = g.generate_multiply(); + // record the stub start and end + store_archive_data(stub_id, start, _masm->pc()); + } + StubRoutines::_montgomeryMultiply = start; } if (UseMontgomerySquareIntrinsic) { StubId stub_id = StubId::stubgen_montgomerySquare_id; - StubCodeMark mark(this, stub_id); - MontgomeryMultiplyGenerator g(_masm, /*squaring*/true); - // We use generate_multiply() rather than generate_square() - // because it's faster for the sizes of modulus we care about. - StubRoutines::_montgomerySquare = g.generate_multiply(); + address start = load_archive_data(stub_id); + if (start == nullptr) { + // we have to generate it + StubCodeMark mark(this, stub_id); + MontgomeryMultiplyGenerator g(_masm, /*squaring*/true); + // We use generate_multiply() rather than generate_square() + // because it's faster for the sizes of modulus we care about. + start = g.generate_multiply(); + // record the stub start and end + store_archive_data(stub_id, start, _masm->pc()); + } + StubRoutines::_montgomerySquare = start; } #endif // COMPILER2 @@ -11854,7 +12736,8 @@ class StubGenerator: public StubCodeGenerator { } if (UseGHASHIntrinsics) { // StubRoutines::_ghash_processBlocks = generate_ghash_processBlocks(); - StubRoutines::_ghash_processBlocks = generate_ghash_processBlocks_wide(); + StubRoutines::aarch64::_ghash_processBlocks_small = generate_ghash_processBlocks_small(); + StubRoutines::_ghash_processBlocks = generate_ghash_processBlocks(StubRoutines::aarch64::_ghash_processBlocks_small); } if (UseAESIntrinsics && UseGHASHIntrinsics) { StubRoutines::_galoisCounterMode_AESCrypt = generate_galoisCounterMode_AESCrypt(); @@ -11898,7 +12781,7 @@ class StubGenerator: public StubCodeGenerator { } public: - StubGenerator(CodeBuffer* code, BlobId blob_id) : StubCodeGenerator(code, blob_id) { + StubGenerator(CodeBuffer* code, BlobId blob_id, AOTStubData* stub_data) : StubCodeGenerator(code, blob_id, stub_data) { switch(blob_id) { case BlobId::stubgen_preuniverse_id: generate_preuniverse_stubs(); @@ -11920,12 +12803,35 @@ class StubGenerator: public StubCodeGenerator { break; }; } + +#if INCLUDE_CDS + static void init_AOTAddressTable(GrowableArray
& external_addresses) { + // external data defined in this file +#define ADD(addr) external_addresses.append((address)addr); + ADD(_sha256_round_consts); + ADD(_sha512_round_consts); + ADD(_sha3_round_consts); + ADD(_double_keccak_round_consts); + ADD(_encodeBlock_toBase64); + ADD(_encodeBlock_toBase64URL); + ADD(_decodeBlock_fromBase64ForNoSIMD); + ADD(_decodeBlock_fromBase64URLForNoSIMD); + ADD(_decodeBlock_fromBase64ForSIMD); + ADD(_decodeBlock_fromBase64URLForSIMD); +#undef ADD + } +#endif // INCLUDE_CDS }; // end class declaration -void StubGenerator_generate(CodeBuffer* code, BlobId blob_id) { - StubGenerator g(code, blob_id); +void StubGenerator_generate(CodeBuffer* code, BlobId blob_id, AOTStubData* stub_data) { + StubGenerator g(code, blob_id, stub_data); } +#if INCLUDE_CDS +void StubGenerator_init_AOTAddressTable(GrowableArray
& addresses) { + StubGenerator::init_AOTAddressTable(addresses); +} +#endif // INCLUDE_CDS #if defined (LINUX) diff --git a/src/hotspot/cpu/aarch64/stubRoutines_aarch64.cpp b/src/hotspot/cpu/aarch64/stubRoutines_aarch64.cpp index 88993818b47..35ec22b0897 100644 --- a/src/hotspot/cpu/aarch64/stubRoutines_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/stubRoutines_aarch64.cpp @@ -413,3 +413,39 @@ ATTRIBUTE_ALIGNED(64) jdouble StubRoutines::aarch64::_pio2[] = { 2.73370053816464559624e-44, // 0x36E3822280000000 2.16741683877804819444e-51, // 0x3569F31D00000000 }; + +#if INCLUDE_CDS +extern void StubGenerator_init_AOTAddressTable(GrowableArray
& addresses); + +void StubRoutines::init_AOTAddressTable() { + ResourceMark rm; + GrowableArray
external_addresses; + // publish static addresses referred to by aarch64 generator + // n.b. we have to use use an extern call here because class + // StubGenerator, which provides the static method that knows how to + // add the relevant addresses, is declared in a source file rather + // than in a separately includeable header. + StubGenerator_init_AOTAddressTable(external_addresses); + // publish external data addresses defined in nested aarch64 class + StubRoutines::aarch64::init_AOTAddressTable(external_addresses); + AOTCodeCache::publish_external_addresses(external_addresses); +} + + +#define ADD(addr) external_addresses.append((address)addr); + +void StubRoutines::aarch64::init_AOTAddressTable(GrowableArray
& external_addresses) { + ADD(_kyberConsts); + ADD(_dilithiumConsts); + // this is added in generic code + // ADD(_crc_table); + ADD(_adler_table); + ADD(_npio2_hw); + ADD(_dsin_coef); + ADD(_dcos_coef); + ADD(_two_over_pi); + ADD(_pio2); +} + +#undef ADD +#endif // INCLUDE_CDS diff --git a/src/hotspot/cpu/aarch64/stubRoutines_aarch64.hpp b/src/hotspot/cpu/aarch64/stubRoutines_aarch64.hpp index c35371e1083..f77192a3741 100644 --- a/src/hotspot/cpu/aarch64/stubRoutines_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/stubRoutines_aarch64.hpp @@ -110,6 +110,11 @@ private: _completed = true; } +#if INCLUDE_CDS + static void init_AOTAddressTable(GrowableArray
& external_addresses); +#endif // INCLUDE_CDS + + private: static uint16_t _kyberConsts[]; static uint32_t _dilithiumConsts[]; diff --git a/src/hotspot/cpu/arm/stubGenerator_arm.cpp b/src/hotspot/cpu/arm/stubGenerator_arm.cpp index a36ad3a0c47..a705b15eff5 100644 --- a/src/hotspot/cpu/arm/stubGenerator_arm.cpp +++ b/src/hotspot/cpu/arm/stubGenerator_arm.cpp @@ -3211,7 +3211,7 @@ class StubGenerator: public StubCodeGenerator { } public: - StubGenerator(CodeBuffer* code, BlobId blob_id) : StubCodeGenerator(code, blob_id) { + StubGenerator(CodeBuffer* code, BlobId blob_id, AOTStubData* stub_data) : StubCodeGenerator(code, blob_id, stub_data) { switch(blob_id) { case BlobId::stubgen_preuniverse_id: generate_preuniverse_stubs(); @@ -3235,8 +3235,8 @@ class StubGenerator: public StubCodeGenerator { } }; // end class declaration -void StubGenerator_generate(CodeBuffer* code, BlobId blob_id) { - StubGenerator g(code, blob_id); +void StubGenerator_generate(CodeBuffer* code, BlobId blob_id, AOTStubData* stub_data) { + StubGenerator g(code, blob_id, stub_data); } // implementation of internal development flag diff --git a/src/hotspot/cpu/arm/stubRoutines_arm.cpp b/src/hotspot/cpu/arm/stubRoutines_arm.cpp index a4f2b5e1bd9..3ed747ea11a 100644 --- a/src/hotspot/cpu/arm/stubRoutines_arm.cpp +++ b/src/hotspot/cpu/arm/stubRoutines_arm.cpp @@ -39,3 +39,9 @@ STUBGEN_ARCH_ENTRIES_DO(DEFINE_ARCH_ENTRY, DEFINE_ARCH_ENTRY_INIT) address StubRoutines::crc_table_addr() { ShouldNotCallThis(); return nullptr; } address StubRoutines::crc32c_table_addr() { ShouldNotCallThis(); return nullptr; } + +#if INCLUDE_CDS +// nothing to do for arm +void StubRoutines::init_AOTAddressTable() { +} +#endif // INCLUDE_CDS diff --git a/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp b/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp index e48778a8b9f..f528587a8bb 100644 --- a/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp +++ b/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp @@ -5095,7 +5095,7 @@ void generate_lookup_secondary_supers_table_stub() { } public: - StubGenerator(CodeBuffer* code, BlobId blob_id) : StubCodeGenerator(code, blob_id) { + StubGenerator(CodeBuffer* code, BlobId blob_id, AOTStubData *stub_data) : StubCodeGenerator(code, blob_id, stub_data) { switch(blob_id) { case BlobId::stubgen_preuniverse_id: generate_preuniverse_stubs(); @@ -5119,7 +5119,7 @@ void generate_lookup_secondary_supers_table_stub() { } }; -void StubGenerator_generate(CodeBuffer* code, BlobId blob_id) { - StubGenerator g(code, blob_id); +void StubGenerator_generate(CodeBuffer* code, BlobId blob_id, AOTStubData *stub_data) { + StubGenerator g(code, blob_id, stub_data); } diff --git a/src/hotspot/cpu/ppc/stubRoutines_ppc_64.cpp b/src/hotspot/cpu/ppc/stubRoutines_ppc_64.cpp index 914c5a17a19..3b7ee66348a 100644 --- a/src/hotspot/cpu/ppc/stubRoutines_ppc_64.cpp +++ b/src/hotspot/cpu/ppc/stubRoutines_ppc_64.cpp @@ -183,3 +183,9 @@ address StubRoutines::ppc::generate_crc_constants(juint reverse_poly) { return consts; } + +#if INCLUDE_CDS +// nothing to do for ppc +void StubRoutines::init_AOTAddressTable() { +} +#endif // INCLUDE_CDS diff --git a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp index 964c6d98e9c..4656b5c0d41 100644 --- a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp @@ -7348,7 +7348,7 @@ static const int64_t right_3_bits = right_n_bits(3); } public: - StubGenerator(CodeBuffer* code, BlobId blob_id) : StubCodeGenerator(code, blob_id) { + StubGenerator(CodeBuffer* code, BlobId blob_id, AOTStubData* stub_data) : StubCodeGenerator(code, blob_id, stub_data) { switch(blob_id) { case BlobId::stubgen_preuniverse_id: generate_preuniverse_stubs(); @@ -7372,6 +7372,6 @@ static const int64_t right_3_bits = right_n_bits(3); } }; // end class declaration -void StubGenerator_generate(CodeBuffer* code, BlobId blob_id) { - StubGenerator g(code, blob_id); +void StubGenerator_generate(CodeBuffer* code, BlobId blob_id, AOTStubData* stub_data) { + StubGenerator g(code, blob_id, stub_data); } diff --git a/src/hotspot/cpu/riscv/stubRoutines_riscv.cpp b/src/hotspot/cpu/riscv/stubRoutines_riscv.cpp index 2aac95d71fa..51e31aa3672 100644 --- a/src/hotspot/cpu/riscv/stubRoutines_riscv.cpp +++ b/src/hotspot/cpu/riscv/stubRoutines_riscv.cpp @@ -501,3 +501,9 @@ ATTRIBUTE_ALIGNED(4096) juint StubRoutines::riscv::_crc_table[] = 0x751997d0UL, 0x00000001UL, 0xccaa009eUL, 0x00000000UL, }; + +#if INCLUDE_CDS +// nothing to do for riscv +void StubRoutines::init_AOTAddressTable() { +} +#endif // INCLUDE_CDS diff --git a/src/hotspot/cpu/s390/stubGenerator_s390.cpp b/src/hotspot/cpu/s390/stubGenerator_s390.cpp index 2aa365be999..3f16312eb48 100644 --- a/src/hotspot/cpu/s390/stubGenerator_s390.cpp +++ b/src/hotspot/cpu/s390/stubGenerator_s390.cpp @@ -3422,7 +3422,7 @@ class StubGenerator: public StubCodeGenerator { } public: - StubGenerator(CodeBuffer* code, BlobId blob_id) : StubCodeGenerator(code, blob_id) { + StubGenerator(CodeBuffer* code, BlobId blob_id, AOTStubData* stub_data) : StubCodeGenerator(code, blob_id, stub_data) { switch(blob_id) { case BlobId::stubgen_preuniverse_id: generate_preuniverse_stubs(); @@ -3479,6 +3479,6 @@ class StubGenerator: public StubCodeGenerator { }; -void StubGenerator_generate(CodeBuffer* code, BlobId blob_id) { - StubGenerator g(code, blob_id); +void StubGenerator_generate(CodeBuffer* code, BlobId blob_id, AOTStubData* stub_data) { + StubGenerator g(code, blob_id, stub_data); } diff --git a/src/hotspot/cpu/s390/stubRoutines_s390.cpp b/src/hotspot/cpu/s390/stubRoutines_s390.cpp index 6feb20f9604..3db4995338d 100644 --- a/src/hotspot/cpu/s390/stubRoutines_s390.cpp +++ b/src/hotspot/cpu/s390/stubRoutines_s390.cpp @@ -736,3 +736,9 @@ juint StubRoutines::zarch::_crc32c_table[CRC32_TABLES][CRC32_COLUMN_SIZE] = { } #endif }; + +#if INCLUDE_CDS +// nothing to do for s390 +void StubRoutines::init_AOTAddressTable() { +} +#endif // INCLUDE_CDS diff --git a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp index 1242078e11d..29925e71aaf 100644 --- a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp @@ -71,6 +71,17 @@ static jlong *double_signmask_pool = double_quadword(&fp_signmask_pool[2*2], static jlong *float_signflip_pool = double_quadword(&fp_signmask_pool[3*2], (jlong)UCONST64(0x8000000080000000), (jlong)UCONST64(0x8000000080000000)); static jlong *double_signflip_pool = double_quadword(&fp_signmask_pool[4*2], (jlong)UCONST64(0x8000000000000000), (jlong)UCONST64(0x8000000000000000)); +#if INCLUDE_CDS +// publish external addresses defined in this file +void LIR_Assembler::init_AOTAddressTable(GrowableArray
& external_addresses) { +#define ADD(addr) external_addresses.append((address)addr); + ADD(float_signmask_pool); + ADD(double_signmask_pool); + ADD(float_signflip_pool); + ADD(double_signflip_pool); +#undef ADD +} +#endif // INCLUDE_CDS NEEDS_CLEANUP // remove this definitions ? const Register SYNC_header = rax; // synchronization header @@ -519,6 +530,15 @@ void LIR_Assembler::const2reg(LIR_Opr src, LIR_Opr dest, LIR_PatchCode patch_cod } case T_LONG: { +#if INCLUDE_CDS + if (AOTCodeCache::is_on_for_dump()) { + address b = c->as_pointer(); + if (b == (address)ThreadIdentifier::unsafe_offset()) { + __ lea(dest->as_register_lo(), ExternalAddress(b)); + break; + } + } +#endif assert(patch_code == lir_patch_none, "no patching handled here"); #if INCLUDE_CDS if (AOTCodeCache::is_on_for_dump()) { diff --git a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.hpp b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.hpp index c4a368b54d8..6f179255e4a 100644 --- a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.hpp @@ -58,4 +58,7 @@ public: void store_parameter(jobject c, int offset_from_esp_in_words); void store_parameter(Metadata* c, int offset_from_esp_in_words); +#if INCLUDE_CDS + void static init_AOTAddressTable(GrowableArray
& external_addresses); +#endif // INCLUDE_CDS #endif // CPU_X86_C1_LIRASSEMBLER_X86_HPP diff --git a/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.cpp index 47a3dad54e7..c20551b5084 100644 --- a/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.cpp @@ -31,6 +31,7 @@ #include "gc/z/zBarrierSetAssembler.hpp" #include "gc/z/zBarrierSetRuntime.hpp" #include "gc/z/zThreadLocalData.hpp" +#include "logging/log.hpp" #include "memory/resourceArea.hpp" #include "runtime/jniHandles.hpp" #include "runtime/sharedRuntime.hpp" @@ -1391,10 +1392,13 @@ static uint16_t patch_barrier_relocation_value(int format) { } } -void ZBarrierSetAssembler::patch_barrier_relocation(address addr, int format) { +void ZBarrierSetAssembler::patch_barrier_relocation(address addr, int format, bool log) { const int offset = patch_barrier_relocation_offset(format); const uint16_t value = patch_barrier_relocation_value(format); uint8_t* const patch_addr = (uint8_t*)addr + offset; + if (log) { + log_trace(aot, codecache, stubs)("patching address " INTPTR_FORMAT " offset %d value 0x%x", p2i(addr), offset, value); + } if (format == ZBarrierRelocationFormatLoadGoodBeforeShl) { if (VM_Version::supports_apx_f()) { NativeInstruction* instruction = nativeInstruction_at(addr); @@ -1426,6 +1430,74 @@ void ZBarrierSetAssembler::patch_barriers() { #undef __ #define __ masm-> +void ZBarrierSetAssembler::register_reloc_addresses(GrowableArray
&entries, int begin, int count) { + int formats[] = { + ZBarrierRelocationFormatLoadBadAfterTest, + ZBarrierRelocationFormatStoreBadAfterTest, + ZBarrierRelocationFormatStoreGoodAfterOr, + -1 + }; + int format_idx = 0; + int format = formats[format_idx++]; + for (int i = begin; i < begin + count; i++) { + address addr = entries.at(i); + // reloc addresses occur in 3 groups terminated with a nullptr + if (addr == nullptr) { + assert(format_idx < (int)(sizeof(formats) / sizeof(formats[0])), + "too many reloc groups"); + format = formats[format_idx++]; + } else { + switch(format) { + case ZBarrierRelocationFormatLoadBadAfterTest: + _load_bad_relocations.append(addr); + break; + case ZBarrierRelocationFormatStoreBadAfterTest: + _store_bad_relocations.append(addr); + break; + case ZBarrierRelocationFormatStoreGoodAfterOr: + _store_good_relocations.append(addr); + break; + default: + ShouldNotReachHere(); + break; + } + patch_barrier_relocation(addr, format, true); + } + } + assert(format == -1, "unterminated format list"); +} + +void ZBarrierSetAssembler::retrieve_reloc_addresses(address start, address end, GrowableArray
&entries) { + assert(start != nullptr, "start address must not be null"); + assert(end != nullptr, "start address must not be null"); + assert(start < end, "stub range must not be empty"); + for (int i = 0; i < _load_bad_relocations.length(); i++) { + address addr = _load_bad_relocations.at(i); + assert(addr != nullptr, "load bad reloc address shoudl not be null!"); + if (start <= addr && addr < end) { + entries.append(addr); + } + } + entries.append(nullptr); + for (int i = 0; i < _store_bad_relocations.length(); i++) { + address addr = _store_bad_relocations.at(i); + assert(addr != nullptr, "store bad reloc address shoudl not be null!"); + if (start <= addr && addr < end) { + entries.append(addr); + } + } + entries.append(nullptr); + for (int i = 0; i < _store_good_relocations.length(); i++) { + address addr = _store_good_relocations.at(i); + assert(addr != nullptr, "store good reloc address shoudl not be null!"); + if (start <= addr && addr < end) { + entries.append(addr); + } + } + entries.append(nullptr); +} + + void ZBarrierSetAssembler::check_oop(MacroAssembler* masm, Register obj, Register tmp1, Register tmp2, Label& error) { // C1 calls verfy_oop in the middle of barriers, before they have been uncolored // and after being colored. Therefore, we must deal with colored oops as well. diff --git a/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.hpp b/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.hpp index e91e2b9ea20..ce0c4769716 100644 --- a/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.hpp @@ -189,10 +189,14 @@ public: Label& slow_path, Label& slow_path_continuation) const; - void patch_barrier_relocation(address addr, int format); + void patch_barrier_relocation(address addr, int format, bool log = false); void patch_barriers(); + void register_reloc_addresses(GrowableArray
&entries, int begin, int count); + + void retrieve_reloc_addresses(address start, address end, GrowableArray
&entries); + void check_oop(MacroAssembler* masm, Register obj, Register tmp1, Register tmp2, Label& error); }; diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp index 356bf8af5c0..5ab3ca339aa 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp @@ -385,7 +385,8 @@ void MacroAssembler::warn(const char* msg) { // Windows always allocates space for its register args subq(rsp, frame::arg_reg_save_area_bytes); #endif - lea(c_rarg0, ExternalAddress((address) msg)); + const char* str = (code_section()->scratch_emit()) ? msg : AOTCodeCache::add_C_string(msg); + lea(c_rarg0, ExternalAddress((address) str)); call(RuntimeAddress(CAST_FROM_FN_PTR(address, warning))); #ifdef _WIN64 @@ -5672,7 +5673,12 @@ void MacroAssembler::encode_and_move_klass_not_null(Register dst, Register src) BLOCK_COMMENT("encode_and_move_klass_not_null {"); assert_different_registers(src, dst); if (CompressedKlassPointers::base() != nullptr) { - movptr(dst, -(intptr_t)CompressedKlassPointers::base()); + if (AOTCodeCache::is_on_for_dump()) { + movptr(dst, ExternalAddress(CompressedKlassPointers::base_addr())); + negq(dst); + } else { + movptr(dst, -(intptr_t)CompressedKlassPointers::base()); + } addq(dst, src); } else { movptr(dst, src); @@ -5720,7 +5726,11 @@ void MacroAssembler::decode_and_move_klass_not_null(Register dst, Register src) } else { if (CompressedKlassPointers::shift() <= Address::times_8) { if (CompressedKlassPointers::base() != nullptr) { - movptr(dst, (intptr_t)CompressedKlassPointers::base()); + if (AOTCodeCache::is_on_for_dump()) { + movptr(dst, ExternalAddress(CompressedKlassPointers::base_addr())); + } else { + movptr(dst, (intptr_t)CompressedKlassPointers::base()); + } } else { xorq(dst, dst); } @@ -5732,9 +5742,14 @@ void MacroAssembler::decode_and_move_klass_not_null(Register dst, Register src) } } else { if (CompressedKlassPointers::base() != nullptr) { - const intptr_t base_right_shifted = - (intptr_t)CompressedKlassPointers::base() >> CompressedKlassPointers::shift(); - movptr(dst, base_right_shifted); + if (AOTCodeCache::is_on_for_dump()) { + movptr(dst, ExternalAddress(CompressedKlassPointers::base_addr())); + shrq(dst, CompressedKlassPointers::shift()); + } else { + const intptr_t base_right_shifted = + (intptr_t)CompressedKlassPointers::base() >> CompressedKlassPointers::shift(); + movptr(dst, base_right_shifted); + } } else { xorq(dst, dst); } @@ -5811,7 +5826,7 @@ void MacroAssembler::cmp_narrow_klass(Address dst, Klass* k) { void MacroAssembler::reinit_heapbase() { if (UseCompressedOops) { - if (Universe::heap() != nullptr) { + if (Universe::heap() != nullptr && !AOTCodeCache::is_on_for_dump()) { if (CompressedOops::base() == nullptr) { MacroAssembler::xorptr(r12_heapbase, r12_heapbase); } else { diff --git a/src/hotspot/cpu/x86/macroAssembler_x86_sha.cpp b/src/hotspot/cpu/x86/macroAssembler_x86_sha.cpp index 9f0232075cd..401d5dc22cc 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86_sha.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86_sha.cpp @@ -242,7 +242,6 @@ void MacroAssembler::fast_sha256(XMMRegister msg, XMMRegister state0, XMMRegiste Label done_hash, loop0; address K256 = StubRoutines::x86::k256_addr(); - address pshuffle_byte_flip_mask = StubRoutines::x86::pshuffle_byte_flip_mask_addr(); movdqu(state0, Address(state, 0)); movdqu(state1, Address(state, 16)); @@ -253,7 +252,7 @@ void MacroAssembler::fast_sha256(XMMRegister msg, XMMRegister state0, XMMRegiste palignr(state0, state1, 8); pblendw(state1, msgtmp4, 0xF0); - movdqu(shuf_mask, ExternalAddress(pshuffle_byte_flip_mask)); + movdqu(shuf_mask, ExternalAddress(StubRoutines::x86::pshuffle_byte_flip_mask_addr())); lea(rax, ExternalAddress(K256)); bind(loop0); @@ -661,8 +660,6 @@ void MacroAssembler::sha256_AVX2(XMMRegister msg, XMMRegister state0, XMMRegiste compute_size1, compute_size_end1; address K256_W = StubRoutines::x86::k256_W_addr(); - address pshuffle_byte_flip_mask = StubRoutines::x86::pshuffle_byte_flip_mask_addr(); - address pshuffle_byte_flip_mask_addr = nullptr; const XMMRegister& SHUF_00BA = xmm10; // ymm10: shuffle xBxA -> 00BA const XMMRegister& SHUF_DC00 = xmm12; // ymm12: shuffle xDxC -> DC00 @@ -791,10 +788,14 @@ enum { // load g - r10 after it is used as scratch movl(h, Address(CTX, 4*7)); - pshuffle_byte_flip_mask_addr = pshuffle_byte_flip_mask; - vmovdqu(BYTE_FLIP_MASK, ExternalAddress(pshuffle_byte_flip_mask_addr + 0)); // [PSHUFFLE_BYTE_FLIP_MASK wrt rip] - vmovdqu(SHUF_00BA, ExternalAddress(pshuffle_byte_flip_mask_addr + 32)); // [_SHUF_00BA wrt rip] - vmovdqu(SHUF_DC00, ExternalAddress(pshuffle_byte_flip_mask_addr + 64)); // [_SHUF_DC00 wrt rip] + // the three successive pshuffle_byte_flip_mask stub entries should + // be offset by 32 bytes + assert(StubRoutines::x86::pshuffle_byte_flip_mask_addr() + 32 == StubRoutines::x86::pshuffle_byte_flip_mask_00ba_addr(), "sanity"); + assert(StubRoutines::x86::pshuffle_byte_flip_mask_addr() + 64 == StubRoutines::x86::pshuffle_byte_flip_mask_dc00_addr(), "sanity"); + + vmovdqu(BYTE_FLIP_MASK, ExternalAddress(StubRoutines::x86::pshuffle_byte_flip_mask_addr())); // [PSHUFFLE_BYTE_FLIP_MASK wrt rip] + vmovdqu(SHUF_00BA, ExternalAddress(StubRoutines::x86::pshuffle_byte_flip_mask_00ba_addr())); // [_SHUF_00BA wrt rip] + vmovdqu(SHUF_DC00, ExternalAddress(StubRoutines::x86::pshuffle_byte_flip_mask_dc00_addr())); // [_SHUF_DC00 wrt rip] movl(g, Address(CTX, 4*6)); @@ -953,11 +954,9 @@ bind(only_one_block); // load g - r10 after use as scratch movl(h, Address(CTX, 4*7)); // 0x5be0cd19 - - pshuffle_byte_flip_mask_addr = pshuffle_byte_flip_mask; - vmovdqu(BYTE_FLIP_MASK, ExternalAddress(pshuffle_byte_flip_mask_addr + 0)); // [PSHUFFLE_BYTE_FLIP_MASK wrt rip] - vmovdqu(SHUF_00BA, ExternalAddress(pshuffle_byte_flip_mask_addr + 32)); // [_SHUF_00BA wrt rip] - vmovdqu(SHUF_DC00, ExternalAddress(pshuffle_byte_flip_mask_addr + 64)); // [_SHUF_DC00 wrt rip] + vmovdqu(BYTE_FLIP_MASK, ExternalAddress(StubRoutines::x86::pshuffle_byte_flip_mask_addr())); // [PSHUFFLE_BYTE_FLIP_MASK wrt rip] + vmovdqu(SHUF_00BA, ExternalAddress(StubRoutines::x86::pshuffle_byte_flip_mask_00ba_addr())); // [_SHUF_00BA wrt rip] + vmovdqu(SHUF_DC00, ExternalAddress(StubRoutines::x86::pshuffle_byte_flip_mask_dc00_addr())); // [_SHUF_DC00 wrt rip] movl(g, Address(CTX, 4*6)); // 0x1f83d9ab @@ -1346,9 +1345,12 @@ void MacroAssembler::sha512_AVX2(XMMRegister msg, XMMRegister state0, XMMRegiste // load g - r10 after it is used as scratch movq(h, Address(CTX, 8 * 7)); - pshuffle_byte_flip_mask_addr = pshuffle_byte_flip_mask_sha512; - vmovdqu(BYTE_FLIP_MASK, ExternalAddress(pshuffle_byte_flip_mask_addr + 0)); // PSHUFFLE_BYTE_FLIP_MASK wrt rip - vmovdqu(YMM_MASK_LO, ExternalAddress(pshuffle_byte_flip_mask_addr + 32)); + // the two successive pshuffle_byte_flip_mask_sha512 stub entries should + // be offset by 32 bytes + assert(StubRoutines::x86::pshuffle_byte_flip_mask_addr_sha512() + 32 == StubRoutines::x86::pshuffle_byte_flip_mask_ymm_lo_addr_sha512(), "sanity"); + + vmovdqu(BYTE_FLIP_MASK, ExternalAddress(StubRoutines::x86::pshuffle_byte_flip_mask_addr_sha512())); // PSHUFFLE_BYTE_FLIP_MASK wrt rip + vmovdqu(YMM_MASK_LO, ExternalAddress(StubRoutines::x86::pshuffle_byte_flip_mask_ymm_lo_addr_sha512())); // MASK_YMM_LO wrt rip movq(g, Address(CTX, 8 * 6)); diff --git a/src/hotspot/cpu/x86/stubDeclarations_x86.hpp b/src/hotspot/cpu/x86/stubDeclarations_x86.hpp index 971c8fd3c44..07a1ab622ed 100644 --- a/src/hotspot/cpu/x86/stubDeclarations_x86.hpp +++ b/src/hotspot/cpu/x86/stubDeclarations_x86.hpp @@ -161,6 +161,12 @@ do_arch_entry(x86, compiler, pshuffle_byte_flip_mask, \ pshuffle_byte_flip_mask_addr, \ pshuffle_byte_flip_mask_addr) \ + do_arch_entry(x86, compiler, pshuffle_byte_flip_mask, \ + pshuffle_byte_flip_mask_00ba_addr, \ + pshuffle_byte_flip_mask_00ba_addr) \ + do_arch_entry(x86, compiler, pshuffle_byte_flip_mask, \ + pshuffle_byte_flip_mask_dc00_addr, \ + pshuffle_byte_flip_mask_dc00_addr) \ /* x86_64 exposes these 3 stubs via a generic entry array */ \ /* other arches use arch-specific entries */ \ /* this really needs rationalising */ \ @@ -171,6 +177,9 @@ do_arch_entry(x86, compiler, pshuffle_byte_flip_mask_sha512, \ pshuffle_byte_flip_mask_addr_sha512, \ pshuffle_byte_flip_mask_addr_sha512) \ + do_arch_entry(x86, compiler, pshuffle_byte_flip_mask_sha512, \ + pshuffle_byte_flip_mask_ymm_lo_addr_sha512, \ + pshuffle_byte_flip_mask_ymm_lo_addr_sha512) \ do_stub(compiler, compress_perm_table32) \ do_arch_entry(x86, compiler, compress_perm_table32, \ compress_perm_table32, compress_perm_table32) \ diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp index efb0411aa39..40be816fbf0 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp @@ -188,8 +188,18 @@ address StubGenerator::generate_call_stub(address& return_address) { (int)frame::entry_frame_call_wrapper_offset == (int)call_wrapper_off, "adjust this code"); StubId stub_id = StubId::stubgen_call_stub_id; + GrowableArray
entries; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 2, "sanity check"); + address start = load_archive_data(stub_id, &entries); + if (start != nullptr) { + assert(entries.length() == 1, "expected 1 extra entry"); + return_address = entries.at(0); + return start; + } + StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); // same as in generate_catch_exception()! const Address rsp_after_call(rbp, rsp_after_call_off * wordSize); @@ -298,6 +308,7 @@ address StubGenerator::generate_call_stub(address& return_address) { BLOCK_COMMENT("call_stub_return_address:"); return_address = __ pc(); + entries.append(return_address); // store result depending on type (everything that is not // T_OBJECT, T_LONG, T_FLOAT or T_DOUBLE is treated as T_INT) @@ -394,6 +405,9 @@ address StubGenerator::generate_call_stub(address& return_address) { __ movdbl(Address(c_rarg0, 0), xmm0); __ jmp(exit); + // record the stub entry and end plus the auxiliary entry + store_archive_data(stub_id, start, __ pc(), &entries); + return start; } @@ -411,8 +425,15 @@ address StubGenerator::generate_call_stub(address& return_address) { address StubGenerator::generate_catch_exception() { StubId stub_id = StubId::stubgen_catch_exception_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); // same as in generate_call_stub(): const Address rsp_after_call(rbp, rsp_after_call_off * wordSize); @@ -442,7 +463,9 @@ address StubGenerator::generate_catch_exception() { __ verify_oop(rax); __ movptr(Address(r15_thread, Thread::pending_exception_offset()), rax); - __ lea(rscratch1, ExternalAddress((address)__FILE__)); + // special case -- add file name string to AOT address table + address file = (address)AOTCodeCache::add_C_string(__FILE__); + __ lea(rscratch1, ExternalAddress(file)); __ movptr(Address(r15_thread, Thread::exception_file_offset()), rscratch1); __ movl(Address(r15_thread, Thread::exception_line_offset()), (int) __LINE__); @@ -451,6 +474,9 @@ address StubGenerator::generate_catch_exception() { "_call_stub_return_address must have been generated before"); __ jump(RuntimeAddress(StubRoutines::_call_stub_return_address)); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -467,8 +493,14 @@ address StubGenerator::generate_catch_exception() { address StubGenerator::generate_forward_exception() { StubId stub_id = StubId::stubgen_forward_exception_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); // Upon entry, the sp points to the return address returning into // Java (interpreted or compiled) code; i.e., the return address @@ -521,6 +553,9 @@ address StubGenerator::generate_forward_exception() { __ verify_oop(rax); __ jmp(rbx); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -531,12 +566,21 @@ address StubGenerator::generate_forward_exception() { // Result: address StubGenerator::generate_orderaccess_fence() { StubId stub_id = StubId::stubgen_fence_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); __ membar(Assembler::StoreLoad); __ ret(0); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -550,8 +594,14 @@ address StubGenerator::generate_orderaccess_fence() { address StubGenerator::generate_verify_mxcsr() { StubId stub_id = StubId::stubgen_verify_mxcsr_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); const Address mxcsr_save(rsp, 0); @@ -574,15 +624,24 @@ address StubGenerator::generate_verify_mxcsr() { __ ret(0); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } address StubGenerator::generate_f2i_fixup() { StubId stub_id = StubId::stubgen_f2i_fixup_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } StubCodeMark mark(this, stub_id); Address inout(rsp, 5 * wordSize); // return address + 4 saves - address start = __ pc(); + start = __ pc(); Label L; @@ -613,14 +672,23 @@ address StubGenerator::generate_f2i_fixup() { __ ret(0); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } address StubGenerator::generate_f2l_fixup() { StubId stub_id = StubId::stubgen_f2l_fixup_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } StubCodeMark mark(this, stub_id); Address inout(rsp, 5 * wordSize); // return address + 4 saves - address start = __ pc(); + start = __ pc(); Label L; @@ -651,15 +719,24 @@ address StubGenerator::generate_f2l_fixup() { __ ret(0); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } address StubGenerator::generate_d2i_fixup() { StubId stub_id = StubId::stubgen_d2i_fixup_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } StubCodeMark mark(this, stub_id); Address inout(rsp, 6 * wordSize); // return address + 5 saves - address start = __ pc(); + start = __ pc(); Label L; @@ -699,15 +776,24 @@ address StubGenerator::generate_d2i_fixup() { __ ret(0); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } address StubGenerator::generate_d2l_fixup() { StubId stub_id = StubId::stubgen_d2l_fixup_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } StubCodeMark mark(this, stub_id); Address inout(rsp, 6 * wordSize); // return address + 5 saves - address start = __ pc(); + start = __ pc(); Label L; @@ -747,14 +833,23 @@ address StubGenerator::generate_d2l_fixup() { __ ret(0); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } address StubGenerator::generate_count_leading_zeros_lut() { - __ align64(); StubId stub_id = StubId::stubgen_vector_count_leading_zeros_lut_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align64(); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); __ emit_data64(0x0101010102020304, relocInfo::none); __ emit_data64(0x0000000000000000, relocInfo::none); @@ -765,14 +860,23 @@ address StubGenerator::generate_count_leading_zeros_lut() { __ emit_data64(0x0101010102020304, relocInfo::none); __ emit_data64(0x0000000000000000, relocInfo::none); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } address StubGenerator::generate_popcount_avx_lut() { - __ align64(); StubId stub_id = StubId::stubgen_vector_popcount_lut_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align64(); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); __ emit_data64(0x0302020102010100, relocInfo::none); __ emit_data64(0x0403030203020201, relocInfo::none); @@ -783,14 +887,23 @@ address StubGenerator::generate_popcount_avx_lut() { __ emit_data64(0x0302020102010100, relocInfo::none); __ emit_data64(0x0403030203020201, relocInfo::none); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } address StubGenerator::generate_iota_indices() { - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_vector_iota_indices_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); // B __ emit_data64(0x0706050403020100, relocInfo::none); __ emit_data64(0x0F0E0D0C0B0A0908, relocInfo::none); @@ -845,14 +958,24 @@ address StubGenerator::generate_iota_indices() { __ emit_data64(0x4014000000000000, relocInfo::none); // 5.0d __ emit_data64(0x4018000000000000, relocInfo::none); // 6.0d __ emit_data64(0x401c000000000000, relocInfo::none); // 7.0d + + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } address StubGenerator::generate_vector_reverse_bit_lut() { - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_vector_reverse_bit_lut_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); __ emit_data64(0x0E060A020C040800, relocInfo::none); __ emit_data64(0x0F070B030D050901, relocInfo::none); @@ -863,14 +986,23 @@ address StubGenerator::generate_vector_reverse_bit_lut() { __ emit_data64(0x0E060A020C040800, relocInfo::none); __ emit_data64(0x0F070B030D050901, relocInfo::none); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } address StubGenerator::generate_vector_reverse_byte_perm_mask_long() { - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_vector_reverse_byte_perm_mask_long_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); __ emit_data64(0x0001020304050607, relocInfo::none); __ emit_data64(0x08090A0B0C0D0E0F, relocInfo::none); @@ -881,14 +1013,23 @@ address StubGenerator::generate_vector_reverse_byte_perm_mask_long() { __ emit_data64(0x0001020304050607, relocInfo::none); __ emit_data64(0x08090A0B0C0D0E0F, relocInfo::none); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } address StubGenerator::generate_vector_reverse_byte_perm_mask_int() { - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_vector_reverse_byte_perm_mask_int_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); __ emit_data64(0x0405060700010203, relocInfo::none); __ emit_data64(0x0C0D0E0F08090A0B, relocInfo::none); @@ -899,14 +1040,23 @@ address StubGenerator::generate_vector_reverse_byte_perm_mask_int() { __ emit_data64(0x0405060700010203, relocInfo::none); __ emit_data64(0x0C0D0E0F08090A0B, relocInfo::none); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } address StubGenerator::generate_vector_reverse_byte_perm_mask_short() { - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_vector_reverse_byte_perm_mask_short_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); __ emit_data64(0x0607040502030001, relocInfo::none); __ emit_data64(0x0E0F0C0D0A0B0809, relocInfo::none); @@ -917,31 +1067,52 @@ address StubGenerator::generate_vector_reverse_byte_perm_mask_short() { __ emit_data64(0x0607040502030001, relocInfo::none); __ emit_data64(0x0E0F0C0D0A0B0809, relocInfo::none); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } address StubGenerator::generate_vector_byte_shuffle_mask() { - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_vector_byte_shuffle_mask_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); __ emit_data64(0x7070707070707070, relocInfo::none); __ emit_data64(0x7070707070707070, relocInfo::none); __ emit_data64(0xF0F0F0F0F0F0F0F0, relocInfo::none); __ emit_data64(0xF0F0F0F0F0F0F0F0, relocInfo::none); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } address StubGenerator::generate_fp_mask(StubId stub_id, int64_t mask) { + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); __ emit_data64( mask, relocInfo::none ); __ emit_data64( mask, relocInfo::none ); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -957,9 +1128,15 @@ address StubGenerator::generate_compress_perm_table(StubId stub_id) { default: ShouldNotReachHere(); } + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); if (esize == 32) { // Loop to generate 256 x 8 int compression permute index table. A row is // accessed using 8 bit index computed using vector mask. An entry in @@ -997,6 +1174,9 @@ address StubGenerator::generate_compress_perm_table(StubId stub_id) { } } } + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -1012,9 +1192,15 @@ address StubGenerator::generate_expand_perm_table(StubId stub_id) { default: ShouldNotReachHere(); } + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); if (esize == 32) { // Loop to generate 256 x 8 int expand permute index table. A row is accessed // using 8 bit index computed using vector mask. An entry in a row holds either @@ -1050,13 +1236,22 @@ address StubGenerator::generate_expand_perm_table(StubId stub_id) { } } } + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } address StubGenerator::generate_vector_mask(StubId stub_id, int64_t mask) { + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); __ emit_data64(mask, relocInfo::none); __ emit_data64(mask, relocInfo::none); @@ -1067,14 +1262,23 @@ address StubGenerator::generate_vector_mask(StubId stub_id, int64_t mask) { __ emit_data64(mask, relocInfo::none); __ emit_data64(mask, relocInfo::none); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } address StubGenerator::generate_vector_byte_perm_mask() { - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_vector_byte_perm_mask_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); __ emit_data64(0x0000000000000001, relocInfo::none); __ emit_data64(0x0000000000000003, relocInfo::none); @@ -1085,13 +1289,22 @@ address StubGenerator::generate_vector_byte_perm_mask() { __ emit_data64(0x0000000000000004, relocInfo::none); __ emit_data64(0x0000000000000006, relocInfo::none); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } address StubGenerator::generate_vector_fp_mask(StubId stub_id, int64_t mask) { + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); __ emit_data64(mask, relocInfo::none); __ emit_data64(mask, relocInfo::none); @@ -1102,6 +1315,9 @@ address StubGenerator::generate_vector_fp_mask(StubId stub_id, int64_t mask) { __ emit_data64(mask, relocInfo::none); __ emit_data64(mask, relocInfo::none); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -1110,9 +1326,15 @@ address StubGenerator::generate_vector_custom_i32(StubId stub_id, Assembler::Avx int32_t val4, int32_t val5, int32_t val6, int32_t val7, int32_t val8, int32_t val9, int32_t val10, int32_t val11, int32_t val12, int32_t val13, int32_t val14, int32_t val15) { + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); assert(len != Assembler::AVX_NoVec, "vector len must be specified"); __ emit_data(val0, relocInfo::none, 0); @@ -1135,6 +1357,9 @@ address StubGenerator::generate_vector_custom_i32(StubId stub_id, Assembler::Avx __ emit_data(val15, relocInfo::none, 0); } } + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -1156,8 +1381,14 @@ address StubGenerator::generate_vector_custom_i32(StubId stub_id, Assembler::Avx // * = popped on exit address StubGenerator::generate_verify_oop() { StubId stub_id = StubId::stubgen_verify_oop_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); Label exit, error; @@ -1235,6 +1466,9 @@ address StubGenerator::generate_verify_oop() { __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, MacroAssembler::debug64))); __ hlt(); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -1350,35 +1584,46 @@ void StubGenerator::restore_argument_regs(BasicType type) { address StubGenerator::generate_data_cache_writeback() { const Register src = c_rarg0; // source address - - __ align(CodeEntryAlignment); - StubId stub_id = StubId::stubgen_data_cache_writeback_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); __ enter(); __ cache_wb(Address(src, 0)); __ leave(); __ ret(0); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } address StubGenerator::generate_data_cache_writeback_sync() { const Register is_pre = c_rarg0; // pre or post sync - - __ align(CodeEntryAlignment); - StubId stub_id = StubId::stubgen_data_cache_writeback_sync_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); // pre wbsync is a no-op // post wbsync translates to an sfence Label skip; - address start = __ pc(); + start = __ pc(); __ enter(); __ cmpl(is_pre, 0); @@ -1388,6 +1633,9 @@ address StubGenerator::generate_data_cache_writeback_sync() { __ leave(); __ ret(0); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -1405,9 +1653,15 @@ address StubGenerator::generate_md5_implCompress(StubId stub_id) { default: ShouldNotReachHere(); } + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); const Register buf_param = r15; const Address state_param(rsp, 0 * wordSize); @@ -1437,30 +1691,51 @@ address StubGenerator::generate_md5_implCompress(StubId stub_id) { __ leave(); __ ret(0); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } address StubGenerator::generate_upper_word_mask() { - __ align64(); StubId stub_id = StubId::stubgen_upper_word_mask_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align64(); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); __ emit_data64(0x0000000000000000, relocInfo::none); __ emit_data64(0xFFFFFFFF00000000, relocInfo::none); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } address StubGenerator::generate_shuffle_byte_flip_mask() { - __ align64(); StubId stub_id = StubId::stubgen_shuffle_byte_flip_mask_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align64(); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); __ emit_data64(0x08090a0b0c0d0e0f, relocInfo::none); __ emit_data64(0x0001020304050607, relocInfo::none); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -1478,9 +1753,15 @@ address StubGenerator::generate_sha1_implCompress(StubId stub_id) { default: ShouldNotReachHere(); } + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); Register buf = c_rarg0; Register state = c_rarg1; @@ -1509,15 +1790,32 @@ address StubGenerator::generate_sha1_implCompress(StubId stub_id) { __ leave(); __ ret(0); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } -address StubGenerator::generate_pshuffle_byte_flip_mask() { - __ align64(); +address StubGenerator::generate_pshuffle_byte_flip_mask(address& entry_00ba, address& entry_dc00) { StubId stub_id = StubId::stubgen_pshuffle_byte_flip_mask_id; + GrowableArray
entries; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 3, "sanity check"); + address start = load_archive_data(stub_id, &entries); + if (start != nullptr) { + assert(entries.length() == entry_count - 1, + "unexpected extra entry count %d", entries.length()); + entry_00ba = entries.at(0); + entry_dc00 = entries.at(1); + assert(VM_Version::supports_avx2() == (entry_00ba != nullptr && entry_dc00 != nullptr), + "entries cannot be null when avx2 is enabled"); + return start; + } + __ align64(); StubCodeMark mark(this, stub_id); - address start = __ pc(); - + start = __ pc(); + address entry2 = nullptr; + address entry3 = nullptr; __ emit_data64(0x0405060700010203, relocInfo::none); __ emit_data64(0x0c0d0e0f08090a0b, relocInfo::none); @@ -1525,37 +1823,66 @@ address StubGenerator::generate_pshuffle_byte_flip_mask() { __ emit_data64(0x0405060700010203, relocInfo::none); // second copy __ emit_data64(0x0c0d0e0f08090a0b, relocInfo::none); // _SHUF_00BA + entry2 = __ pc(); __ emit_data64(0x0b0a090803020100, relocInfo::none); __ emit_data64(0xFFFFFFFFFFFFFFFF, relocInfo::none); __ emit_data64(0x0b0a090803020100, relocInfo::none); __ emit_data64(0xFFFFFFFFFFFFFFFF, relocInfo::none); // _SHUF_DC00 + entry3 = __ pc(); __ emit_data64(0xFFFFFFFFFFFFFFFF, relocInfo::none); __ emit_data64(0x0b0a090803020100, relocInfo::none); __ emit_data64(0xFFFFFFFFFFFFFFFF, relocInfo::none); __ emit_data64(0x0b0a090803020100, relocInfo::none); } + // have to track the 2nd and 3rd entries even if they are null + entry_00ba = entry2; + entries.push(entry_00ba); + entry_dc00 = entry3; + entries.push(entry_dc00); + + // record the stub entry and end plus all the auxiliary entries + store_archive_data(stub_id, start, __ pc(), &entries); return start; } //Mask for byte-swapping a couple of qwords in an XMM register using (v)pshufb. -address StubGenerator::generate_pshuffle_byte_flip_mask_sha512() { - __ align32(); +address StubGenerator::generate_pshuffle_byte_flip_mask_sha512(address& entry_ymm_lo) { StubId stub_id = StubId::stubgen_pshuffle_byte_flip_mask_sha512_id; + GrowableArray
entries; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 2, "sanity check"); + address start = load_archive_data(stub_id, &entries); + if (start != nullptr) { + assert(entries.length() == entry_count - 1, + "unexpected extra entry count %d", entries.length()); + entry_ymm_lo = entries.at(0); + assert(VM_Version::supports_avx2() == (entry_ymm_lo != nullptr), + "entry cannot be null when avx2 is enabled"); + return start; + } + __ align32(); StubCodeMark mark(this, stub_id); - address start = __ pc(); - + start = __ pc(); + address entry2 = nullptr; if (VM_Version::supports_avx2()) { __ emit_data64(0x0001020304050607, relocInfo::none); // PSHUFFLE_BYTE_FLIP_MASK __ emit_data64(0x08090a0b0c0d0e0f, relocInfo::none); __ emit_data64(0x1011121314151617, relocInfo::none); __ emit_data64(0x18191a1b1c1d1e1f, relocInfo::none); + // capture 2nd entry + entry2 = __ pc(); __ emit_data64(0x0000000000000000, relocInfo::none); //MASK_YMM_LO __ emit_data64(0x0000000000000000, relocInfo::none); __ emit_data64(0xFFFFFFFFFFFFFFFF, relocInfo::none); __ emit_data64(0xFFFFFFFFFFFFFFFF, relocInfo::none); } + // have to track the 2nd entry even if it is null + entry_ymm_lo = entry2; + entries.push(entry2); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc(), &entries); return start; } @@ -1575,9 +1902,15 @@ address StubGenerator::generate_sha256_implCompress(StubId stub_id) { ShouldNotReachHere(); } assert(VM_Version::supports_sha() || VM_Version::supports_avx2(), ""); + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); Register buf = c_rarg0; Register state = c_rarg1; @@ -1612,6 +1945,9 @@ address StubGenerator::generate_sha256_implCompress(StubId stub_id) { __ leave(); __ ret(0); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -1629,9 +1965,15 @@ address StubGenerator::generate_sha512_implCompress(StubId stub_id) { } assert(VM_Version::supports_avx2(), ""); assert(VM_Version::supports_bmi2() || VM_Version::supports_sha512(), ""); + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); Register buf = c_rarg0; Register state = c_rarg1; @@ -1660,14 +2002,23 @@ address StubGenerator::generate_sha512_implCompress(StubId stub_id) { __ leave(); __ ret(0); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } address StubGenerator::base64_shuffle_addr() { - __ align64(); StubId stub_id = StubId::stubgen_shuffle_base64_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align64(); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); assert(((unsigned long long)start & 0x3f) == 0, "Alignment problem (0x%08llx)", (unsigned long long)start); @@ -1680,42 +2031,69 @@ address StubGenerator::base64_shuffle_addr() { __ emit_data64(0x2829272825262425, relocInfo::none); __ emit_data64(0x2e2f2d2e2b2c2a2b, relocInfo::none); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } address StubGenerator::base64_avx2_shuffle_addr() { - __ align32(); StubId stub_id = StubId::stubgen_avx2_shuffle_base64_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align32(); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); __ emit_data64(0x0809070805060405, relocInfo::none); __ emit_data64(0x0e0f0d0e0b0c0a0b, relocInfo::none); __ emit_data64(0x0405030401020001, relocInfo::none); __ emit_data64(0x0a0b090a07080607, relocInfo::none); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } address StubGenerator::base64_avx2_input_mask_addr() { - __ align32(); StubId stub_id = StubId::stubgen_avx2_input_mask_base64_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align32(); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); __ emit_data64(0x8000000000000000, relocInfo::none); __ emit_data64(0x8000000080000000, relocInfo::none); __ emit_data64(0x8000000080000000, relocInfo::none); __ emit_data64(0x8000000080000000, relocInfo::none); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } address StubGenerator::base64_avx2_lut_addr() { - __ align32(); StubId stub_id = StubId::stubgen_avx2_lut_base64_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align32(); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); __ emit_data64(0xfcfcfcfcfcfc4741, relocInfo::none); __ emit_data64(0x0000f0edfcfcfcfc, relocInfo::none); @@ -1728,14 +2106,23 @@ address StubGenerator::base64_avx2_lut_addr() { __ emit_data64(0xfcfcfcfcfcfc4741, relocInfo::none); __ emit_data64(0x000020effcfcfcfc, relocInfo::none); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } address StubGenerator::base64_encoding_table_addr() { - __ align64(); StubId stub_id = StubId::stubgen_encoding_table_base64_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align64(); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); assert(((unsigned long long)start & 0x3f) == 0, "Alignment problem (0x%08llx)", (unsigned long long)start); __ emit_data64(0x4847464544434241, relocInfo::none); @@ -1757,6 +2144,9 @@ address StubGenerator::base64_encoding_table_addr() { __ emit_data64(0x333231307a797877, relocInfo::none); __ emit_data64(0x5f2d393837363534, relocInfo::none); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -1766,10 +2156,16 @@ address StubGenerator::base64_encoding_table_addr() { // boolean isURL) { address StubGenerator::generate_base64_encodeBlock() { - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_base64_encodeBlock_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); __ enter(); @@ -2144,15 +2540,24 @@ address StubGenerator::generate_base64_encodeBlock() __ leave(); __ ret(0); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } // base64 AVX512vbmi tables address StubGenerator::base64_vbmi_lookup_lo_addr() { - __ align64(); StubId stub_id = StubId::stubgen_lookup_lo_base64_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align64(); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); assert(((unsigned long long)start & 0x3f) == 0, "Alignment problem (0x%08llx)", (unsigned long long)start); @@ -2165,14 +2570,23 @@ address StubGenerator::base64_vbmi_lookup_lo_addr() { __ emit_data64(0x3b3a393837363534, relocInfo::none); __ emit_data64(0x8080808080803d3c, relocInfo::none); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } address StubGenerator::base64_vbmi_lookup_hi_addr() { - __ align64(); StubId stub_id = StubId::stubgen_lookup_hi_base64_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align64(); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); assert(((unsigned long long)start & 0x3f) == 0, "Alignment problem (0x%08llx)", (unsigned long long)start); @@ -2185,13 +2599,22 @@ address StubGenerator::base64_vbmi_lookup_hi_addr() { __ emit_data64(0x302f2e2d2c2b2a29, relocInfo::none); __ emit_data64(0x8080808080333231, relocInfo::none); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } address StubGenerator::base64_vbmi_lookup_lo_url_addr() { - __ align64(); StubId stub_id = StubId::stubgen_lookup_lo_base64url_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align64(); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); assert(((unsigned long long)start & 0x3f) == 0, "Alignment problem (0x%08llx)", (unsigned long long)start); @@ -2204,14 +2627,23 @@ address StubGenerator::base64_vbmi_lookup_lo_url_addr() { __ emit_data64(0x3b3a393837363534, relocInfo::none); __ emit_data64(0x8080808080803d3c, relocInfo::none); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } address StubGenerator::base64_vbmi_lookup_hi_url_addr() { - __ align64(); StubId stub_id = StubId::stubgen_lookup_hi_base64url_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align64(); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); assert(((unsigned long long)start & 0x3f) == 0, "Alignment problem (0x%08llx)", (unsigned long long)start); @@ -2224,14 +2656,23 @@ address StubGenerator::base64_vbmi_lookup_hi_url_addr() { __ emit_data64(0x302f2e2d2c2b2a29, relocInfo::none); __ emit_data64(0x8080808080333231, relocInfo::none); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } address StubGenerator::base64_vbmi_pack_vec_addr() { - __ align64(); StubId stub_id = StubId::stubgen_pack_vec_base64_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align64(); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); assert(((unsigned long long)start & 0x3f) == 0, "Alignment problem (0x%08llx)", (unsigned long long)start); @@ -2244,14 +2685,23 @@ address StubGenerator::base64_vbmi_pack_vec_addr() { __ emit_data64(0x0000000000000000, relocInfo::none); __ emit_data64(0x0000000000000000, relocInfo::none); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } address StubGenerator::base64_vbmi_join_0_1_addr() { - __ align64(); StubId stub_id = StubId::stubgen_join_0_1_base64_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align64(); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); assert(((unsigned long long)start & 0x3f) == 0, "Alignment problem (0x%08llx)", (unsigned long long)start); @@ -2264,14 +2714,23 @@ address StubGenerator::base64_vbmi_join_0_1_addr() { __ emit_data64(0x494a444546404142, relocInfo::none); __ emit_data64(0x565051524c4d4e48, relocInfo::none); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } address StubGenerator::base64_vbmi_join_1_2_addr() { - __ align64(); StubId stub_id = StubId::stubgen_join_1_2_base64_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align64(); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); assert(((unsigned long long)start & 0x3f) == 0, "Alignment problem (0x%08llx)", (unsigned long long)start); @@ -2284,14 +2743,23 @@ address StubGenerator::base64_vbmi_join_1_2_addr() { __ emit_data64(0x5c5d5e58595a5455, relocInfo::none); __ emit_data64(0x696a646566606162, relocInfo::none); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } address StubGenerator::base64_vbmi_join_2_3_addr() { - __ align64(); StubId stub_id = StubId::stubgen_join_2_3_base64_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align64(); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); assert(((unsigned long long)start & 0x3f) == 0, "Alignment problem (0x%08llx)", (unsigned long long)start); @@ -2304,14 +2772,23 @@ address StubGenerator::base64_vbmi_join_2_3_addr() { __ emit_data64(0x767071726c6d6e68, relocInfo::none); __ emit_data64(0x7c7d7e78797a7475, relocInfo::none); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } address StubGenerator::base64_AVX2_decode_tables_addr() { - __ align64(); StubId stub_id = StubId::stubgen_avx2_decode_tables_base64_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align64(); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); assert(((unsigned long long)start & 0x3f) == 0, "Alignment problem (0x%08llx)", (unsigned long long)start); @@ -2339,14 +2816,23 @@ address StubGenerator::base64_AVX2_decode_tables_addr() { // merge multiplier __ emit_data(0x00011000, relocInfo::none, 0); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } address StubGenerator::base64_AVX2_decode_LUT_tables_addr() { - __ align64(); StubId stub_id = StubId::stubgen_avx2_decode_lut_tables_base64_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align64(); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); assert(((unsigned long long)start & 0x3f) == 0, "Alignment problem (0x%08llx)", (unsigned long long)start); @@ -2380,13 +2866,22 @@ address StubGenerator::base64_AVX2_decode_LUT_tables_addr() { __ emit_data64(0x0804080402011010, relocInfo::none); __ emit_data64(0x1010101010101010, relocInfo::none); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } address StubGenerator::base64_decoding_table_addr() { StubId stub_id = StubId::stubgen_decoding_table_base64_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); __ emit_data64(0xffffffffffffffff, relocInfo::none); __ emit_data64(0xffffffffffffffff, relocInfo::none); @@ -2455,6 +2950,9 @@ address StubGenerator::base64_decoding_table_addr() { __ emit_data64(0xffffffffffffffff, relocInfo::none); __ emit_data64(0xffffffffffffffff, relocInfo::none); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -2466,10 +2964,16 @@ address StubGenerator::base64_decoding_table_addr() { // Intrinsic function prototype in Base64.java: // private void decodeBlock(byte[] src, int sp, int sl, byte[] dst, int dp, boolean isURL, isMIME) { address StubGenerator::generate_base64_decodeBlock() { - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_base64_decodeBlock_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); __ enter(); @@ -2982,6 +3486,9 @@ address StubGenerator::generate_base64_decodeBlock() { __ leave(); __ ret(0); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -3000,11 +3507,17 @@ address StubGenerator::generate_base64_decodeBlock() { address StubGenerator::generate_updateBytesCRC32() { assert(UseCRC32Intrinsics, "need AVX and CLMUL instructions"); - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_updateBytesCRC32_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); // Win64: rcx, rdx, r8, r9 (c_rarg0, c_rarg1, ...) // Unix: rdi, rsi, rdx, rcx, r8, r9 (c_rarg0, c_rarg1, ...) @@ -3039,6 +3552,9 @@ address StubGenerator::generate_updateBytesCRC32() { __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(0); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -3057,10 +3573,16 @@ address StubGenerator::generate_updateBytesCRC32() { */ address StubGenerator::generate_updateBytesCRC32C(bool is_pclmulqdq_supported) { assert(UseCRC32CIntrinsics, "need SSE4_2"); - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_updateBytesCRC32C_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); //reg.arg int#0 int#1 int#2 int#3 int#4 int#5 float regs //Windows RCX RDX R8 R9 none none XMM0..XMM3 @@ -3120,6 +3642,9 @@ address StubGenerator::generate_updateBytesCRC32C(bool is_pclmulqdq_supported) { __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(0); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -3138,10 +3663,16 @@ address StubGenerator::generate_updateBytesCRC32C(bool is_pclmulqdq_supported) { * rsp+40 - z address */ address StubGenerator::generate_multiplyToLen() { - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_multiplyToLen_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); // Win64: rcx, rdx, r8, r9 (c_rarg0, c_rarg1, ...) // Unix: rdi, rsi, rdx, rcx, r8, r9 (c_rarg0, c_rarg1, ...) @@ -3179,6 +3710,9 @@ address StubGenerator::generate_multiplyToLen() { __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(0); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -3195,10 +3729,16 @@ address StubGenerator::generate_multiplyToLen() { * rax - int >= mismatched index, < 0 bitwise complement of tail */ address StubGenerator::generate_vectorizedMismatch() { - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_vectorizedMismatch_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); BLOCK_COMMENT("Entry:"); __ enter(); @@ -3232,6 +3772,9 @@ address StubGenerator::generate_vectorizedMismatch() { __ leave(); __ ret(0); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -3247,10 +3790,16 @@ address StubGenerator::generate_vectorizedMismatch() { */ address StubGenerator::generate_squareToLen() { - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_squareToLen_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); // Win64: rcx, rdx, r8, r9 (c_rarg0, c_rarg1, ...) // Unix: rdi, rsi, rdx, rcx (c_rarg0, c_rarg1, ...) @@ -3279,14 +3828,23 @@ address StubGenerator::generate_squareToLen() { __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(0); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } address StubGenerator::generate_method_entry_barrier() { - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_method_entry_barrier_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); Label deoptimize_label; @@ -3356,6 +3914,9 @@ address StubGenerator::generate_method_entry_barrier() { __ movptr(rsp, Address(rsp, 0)); // new rsp was written in the barrier __ jmp(Address(rsp, -1 * wordSize)); // jmp target should be callers verified_entry_point + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -3373,10 +3934,16 @@ address StubGenerator::generate_method_entry_barrier() { * rsp+40 - k */ address StubGenerator::generate_mulAdd() { - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_mulAdd_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); // Win64: rcx, rdx, r8, r9 (c_rarg0, c_rarg1, ...) // Unix: rdi, rsi, rdx, rcx, r8, r9 (c_rarg0, c_rarg1, ...) @@ -3411,14 +3978,23 @@ address StubGenerator::generate_mulAdd() { __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(0); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } address StubGenerator::generate_bigIntegerRightShift() { - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_bigIntegerRightShiftWorker_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); Label Shift512Loop, ShiftTwo, ShiftTwoLoop, ShiftOne, Exit; // For Unix, the arguments are as follows: rdi, rsi, rdx, rcx, r8. @@ -3534,6 +4110,9 @@ address StubGenerator::generate_bigIntegerRightShift() { __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(0); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -3551,10 +4130,16 @@ address StubGenerator::generate_bigIntegerRightShift() { * rsp40 - numIter */ address StubGenerator::generate_bigIntegerLeftShift() { - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_bigIntegerLeftShiftWorker_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); Label Shift512Loop, ShiftTwo, ShiftTwoLoop, ShiftOne, Exit; // For Unix, the arguments are as follows: rdi, rsi, rdx, rcx, r8. @@ -3659,6 +4244,9 @@ address StubGenerator::generate_bigIntegerLeftShift() { __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(0); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -3708,9 +4296,15 @@ void StubGenerator::generate_libm_stubs() { */ address StubGenerator::generate_float16ToFloat() { StubId stub_id = StubId::stubgen_hf2f_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); BLOCK_COMMENT("Entry:"); // No need for RuntimeStub frame since it is called only during JIT compilation @@ -3720,6 +4314,9 @@ address StubGenerator::generate_float16ToFloat() { __ ret(0); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -3734,9 +4331,15 @@ address StubGenerator::generate_float16ToFloat() { */ address StubGenerator::generate_floatToFloat16() { StubId stub_id = StubId::stubgen_f2hf_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); BLOCK_COMMENT("Entry:"); // No need for RuntimeStub frame since it is called only during JIT compilation @@ -3746,6 +4349,9 @@ address StubGenerator::generate_floatToFloat16() { __ ret(0); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -3775,8 +4381,14 @@ address StubGenerator::generate_cont_thaw(StubId stub_id) { default: ShouldNotReachHere(); } + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); // TODO: Handle Valhalla return types. May require generating different return barriers. @@ -3889,6 +4501,9 @@ address StubGenerator::generate_cont_thaw(StubId stub_id) { __ ret(0); } + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -3909,8 +4524,14 @@ address StubGenerator::generate_cont_returnBarrier_exception() { address StubGenerator::generate_cont_preempt_stub() { if (!Continuations::enabled()) return nullptr; StubId stub_id = StubId::stubgen_cont_preempt_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); __ reset_last_Java_frame(true); @@ -3934,14 +4555,23 @@ address StubGenerator::generate_cont_preempt_stub() { __ movptr(rscratch1, ExternalAddress(ContinuationEntry::thaw_call_pc_address())); __ jmp(rscratch1); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } // exception handler for upcall stubs address StubGenerator::generate_upcall_stub_exception_handler() { StubId stub_id = StubId::stubgen_upcall_stub_exception_handler_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); // native caller has no idea how to handle exceptions // we just crash here. Up to callee to catch exceptions. @@ -3953,6 +4583,9 @@ address StubGenerator::generate_upcall_stub_exception_handler() { __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, UpcallLinker::handle_uncaught_exception))); __ should_not_reach_here(); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -3961,8 +4594,14 @@ address StubGenerator::generate_upcall_stub_exception_handler() { // rbx = result address StubGenerator::generate_upcall_stub_load_target() { StubId stub_id = StubId::stubgen_upcall_stub_load_target_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); __ resolve_global_jobject(j_rarg0, rscratch1); // Load target method from receiver @@ -3976,11 +4615,27 @@ address StubGenerator::generate_upcall_stub_load_target() { __ ret(0); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } void StubGenerator::generate_lookup_secondary_supers_table_stub() { StubId stub_id = StubId::stubgen_lookup_secondary_supers_table_id; + GrowableArray
entries; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == Klass::SECONDARY_SUPERS_TABLE_SIZE, "sanity check"); + address start = load_archive_data(stub_id, &entries); + if (start != nullptr) { + assert(entries.length() == Klass::SECONDARY_SUPERS_TABLE_SIZE - 1, + "unexpected extra entry count %d", entries.length()); + StubRoutines::_lookup_secondary_supers_table_stubs[0] = start; + for (int slot = 1; slot < Klass::SECONDARY_SUPERS_TABLE_SIZE; slot++) { + StubRoutines::_lookup_secondary_supers_table_stubs[slot] = entries.at(slot - 1); + } + return; + } StubCodeMark mark(this, stub_id); const Register @@ -3989,21 +4644,35 @@ void StubGenerator::generate_lookup_secondary_supers_table_stub() { result = rdi; for (int slot = 0; slot < Klass::SECONDARY_SUPERS_TABLE_SIZE; slot++) { - StubRoutines::_lookup_secondary_supers_table_stubs[slot] = __ pc(); + address next_entry = __ pc(); + if (slot == 0) { + start = next_entry; + } else { + entries.append(next_entry); + } + StubRoutines::_lookup_secondary_supers_table_stubs[slot] = next_entry; __ lookup_secondary_supers_table_const(r_sub_klass, r_super_klass, rdx, rcx, rbx, r11, // temps result, slot); __ ret(0); } + + // record the stub entry and end plus all the auxiliary entries + store_archive_data(stub_id, start, __ pc(), &entries); } // Slow path implementation for UseSecondarySupersTable. address StubGenerator::generate_lookup_secondary_supers_table_slow_path_stub() { StubId stub_id = StubId::stubgen_lookup_secondary_supers_table_slow_path_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } StubCodeMark mark(this, stub_id); - - address start = __ pc(); + start = __ pc(); const Register r_super_klass = rax, @@ -4025,6 +4694,9 @@ address StubGenerator::generate_lookup_secondary_supers_table_slow_path_stub() { __ movl(result, 0); __ ret(0); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -4232,6 +4904,8 @@ void StubGenerator::generate_compiler_stubs() { } if (UseSHA256Intrinsics) { + address entry2 = nullptr; + address entry3 = nullptr; StubRoutines::x86::_k256_adr = (address)StubRoutines::x86::_k256; char* dst = (char*)StubRoutines::x86::_k256_W; char* src = (char*)StubRoutines::x86::_k256; @@ -4240,14 +4914,18 @@ void StubGenerator::generate_compiler_stubs() { memcpy(dst + 32 * ii + 16, src + 16 * ii, 16); } StubRoutines::x86::_k256_W_adr = (address)StubRoutines::x86::_k256_W; - StubRoutines::x86::_pshuffle_byte_flip_mask_addr = generate_pshuffle_byte_flip_mask(); + StubRoutines::x86::_pshuffle_byte_flip_mask_addr = generate_pshuffle_byte_flip_mask(entry2, entry3); + StubRoutines::x86::_pshuffle_byte_flip_mask_00ba_addr = entry2; + StubRoutines::x86::_pshuffle_byte_flip_mask_dc00_addr = entry3; StubRoutines::_sha256_implCompress = generate_sha256_implCompress(StubId::stubgen_sha256_implCompress_id); StubRoutines::_sha256_implCompressMB = generate_sha256_implCompress(StubId::stubgen_sha256_implCompressMB_id); } if (UseSHA512Intrinsics) { + address entry2 = nullptr; StubRoutines::x86::_k512_W_addr = (address)StubRoutines::x86::_k512_W; - StubRoutines::x86::_pshuffle_byte_flip_mask_addr_sha512 = generate_pshuffle_byte_flip_mask_sha512(); + StubRoutines::x86::_pshuffle_byte_flip_mask_addr_sha512 = generate_pshuffle_byte_flip_mask_sha512(entry2); + StubRoutines::x86::_pshuffle_byte_flip_mask_ymm_lo_addr_sha512 = entry2; StubRoutines::_sha512_implCompress = generate_sha512_implCompress(StubId::stubgen_sha512_implCompress_id); StubRoutines::_sha512_implCompressMB = generate_sha512_implCompress(StubId::stubgen_sha512_implCompressMB_id); } @@ -4325,7 +5003,7 @@ void StubGenerator::generate_compiler_stubs() { #endif // COMPILER2_OR_JVMCI } -StubGenerator::StubGenerator(CodeBuffer* code, BlobId blob_id) : StubCodeGenerator(code, blob_id) { +StubGenerator::StubGenerator(CodeBuffer* code, BlobId blob_id, AOTStubData* stub_data) : StubCodeGenerator(code, blob_id, stub_data) { switch(blob_id) { case BlobId::stubgen_preuniverse_id: generate_preuniverse_stubs(); @@ -4348,8 +5026,35 @@ StubGenerator::StubGenerator(CodeBuffer* code, BlobId blob_id) : StubCodeGenerat }; } -void StubGenerator_generate(CodeBuffer* code, BlobId blob_id) { - StubGenerator g(code, blob_id); +#if INCLUDE_CDS +// publish addresses of static data defined in this file and in other +// stubgen stub generator files +void StubGenerator::init_AOTAddressTable(GrowableArray
& external_addresses) { + init_AOTAddressTable_adler(external_addresses); + init_AOTAddressTable_aes(external_addresses); + init_AOTAddressTable_cbrt(external_addresses); + init_AOTAddressTable_chacha(external_addresses); + // constants publishes for all of address use by cos and almost all of sin + init_AOTAddressTable_constants(external_addresses); + init_AOTAddressTable_dilithium(external_addresses); + init_AOTAddressTable_exp(external_addresses); + init_AOTAddressTable_fmod(external_addresses); + init_AOTAddressTable_ghash(external_addresses); + init_AOTAddressTable_kyber(external_addresses); + init_AOTAddressTable_log(external_addresses); + init_AOTAddressTable_poly1305(external_addresses); + init_AOTAddressTable_poly_mont(external_addresses); + init_AOTAddressTable_pow(external_addresses); + init_AOTAddressTable_sha3(external_addresses); + init_AOTAddressTable_sin(external_addresses); + init_AOTAddressTable_sinh(external_addresses); + init_AOTAddressTable_tan(external_addresses); + init_AOTAddressTable_tanh(external_addresses); +} +#endif // INCLUDE_CDS + +void StubGenerator_generate(CodeBuffer* code, BlobId blob_id, AOTStubData* stub_data) { + StubGenerator g(code, blob_id, stub_data); } #undef __ diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp b/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp index 332add6dcd4..05e8384d636 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp @@ -303,11 +303,11 @@ class StubGenerator: public StubCodeGenerator { address generate_sha512_implCompress(StubId stub_id); // Mask for byte-swapping a couple of qwords in an XMM register using (v)pshufb. - address generate_pshuffle_byte_flip_mask_sha512(); + address generate_pshuffle_byte_flip_mask_sha512(address& entry_ymm_lo); address generate_upper_word_mask(); address generate_shuffle_byte_flip_mask(); - address generate_pshuffle_byte_flip_mask(); + address generate_pshuffle_byte_flip_mask(address& entry_00ba, address& entry_dc0); // AES intrinsic stubs @@ -650,8 +650,33 @@ class StubGenerator: public StubCodeGenerator { void generate_compiler_stubs(); void generate_final_stubs(); +#if INCLUDE_CDS + static void init_AOTAddressTable_adler(GrowableArray
& external_addresses); + static void init_AOTAddressTable_aes(GrowableArray
& external_addresses); + static void init_AOTAddressTable_cbrt(GrowableArray
& external_addresses); + static void init_AOTAddressTable_chacha(GrowableArray
& external_addresses); + static void init_AOTAddressTable_constants(GrowableArray
& external_addresses); + static void init_AOTAddressTable_dilithium(GrowableArray
& external_addresses); + static void init_AOTAddressTable_exp(GrowableArray
& external_addresses); + static void init_AOTAddressTable_fmod(GrowableArray
& external_addresses); + static void init_AOTAddressTable_ghash(GrowableArray
& external_addresses); + static void init_AOTAddressTable_kyber(GrowableArray
& external_addresses); + static void init_AOTAddressTable_log(GrowableArray
& external_addresses); + static void init_AOTAddressTable_poly1305(GrowableArray
& external_addresses); + static void init_AOTAddressTable_poly_mont(GrowableArray
& external_addresses); + static void init_AOTAddressTable_pow(GrowableArray
& external_addresses); + static void init_AOTAddressTable_sha3(GrowableArray
& external_addresses); + static void init_AOTAddressTable_sin(GrowableArray
& external_addresses); + static void init_AOTAddressTable_sinh(GrowableArray
& external_addresses); + static void init_AOTAddressTable_tan(GrowableArray
& external_addresses); + static void init_AOTAddressTable_tanh(GrowableArray
& external_addresses); +#endif // INCLUDE_CDS + public: - StubGenerator(CodeBuffer* code, BlobId blob_id); + StubGenerator(CodeBuffer* code, BlobId blob_id, AOTStubData* stub_data); +#if INCLUDE_CDS + static void init_AOTAddressTable(GrowableArray
& external_addresses); +#endif // INCLUDE_CDS }; #endif // CPU_X86_STUBGENERATOR_X86_64_HPP diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_adler.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_adler.cpp index 1d3e7afde1d..a9424978e0e 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_adler.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_adler.cpp @@ -67,8 +67,14 @@ address StubGenerator::generate_updateBytesAdler32() { __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_updateBytesAdler32_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); // Choose an appropriate LIMIT for inner loop based on the granularity // of intermediate results. For int, LIMIT of 5552 will ensure intermediate @@ -334,7 +340,19 @@ address StubGenerator::generate_updateBytesAdler32() { __ leave(); __ ret(0); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); return start; } #undef __ + +#if INCLUDE_CDS +void StubGenerator::init_AOTAddressTable_adler(GrowableArray
& external_addresses) { +#define ADD(addr) external_addresses.append((address)(addr)) + ADD(ADLER32_ASCALE_TABLE); + ADD(ADLER32_SHUF0_TABLE); + ADD(ADLER32_SHUF1_TABLE); +#undef ADD +} +#endif // INCLUDE_CDS diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp index 162c92d5190..b95aa5f8818 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp @@ -250,10 +250,16 @@ void StubGenerator::generate_aes_stubs() { // Output: // rax - number of processed bytes address StubGenerator::generate_galoisCounterMode_AESCrypt() { - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_galoisCounterMode_AESCrypt_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); const Register in = c_rarg0; const Register len = c_rarg1; @@ -319,6 +325,9 @@ address StubGenerator::generate_galoisCounterMode_AESCrypt() { __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(0); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -337,10 +346,16 @@ address StubGenerator::generate_galoisCounterMode_AESCrypt() { // Output: // rax - number of processed bytes address StubGenerator::generate_avx2_galoisCounterMode_AESCrypt() { - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_galoisCounterMode_AESCrypt_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); const Register in = c_rarg0; const Register len = c_rarg1; @@ -404,15 +419,24 @@ address StubGenerator::generate_avx2_galoisCounterMode_AESCrypt() { __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(0); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } // Vector AES Counter implementation address StubGenerator::generate_counterMode_VectorAESCrypt() { - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_counterMode_AESCrypt_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); const Register from = c_rarg0; // source array address const Register to = c_rarg1; // destination array address @@ -471,6 +495,9 @@ address StubGenerator::generate_counterMode_VectorAESCrypt() { __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(0); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -498,10 +525,16 @@ address StubGenerator::generate_counterMode_VectorAESCrypt() { // address StubGenerator::generate_counterMode_AESCrypt_Parallel() { assert(UseAES, "need AES instructions and misaligned SSE support"); - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_counterMode_AESCrypt_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); const Register from = c_rarg0; // source array address const Register to = c_rarg1; // destination array address @@ -781,15 +814,24 @@ address StubGenerator::generate_counterMode_AESCrypt_Parallel() { __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(0); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } address StubGenerator::generate_cipherBlockChaining_decryptVectorAESCrypt() { assert(VM_Version::supports_avx512_vaes(), "need AES instructions and misaligned SSE support"); - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_cipherBlockChaining_decryptAESCrypt_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); const Register from = c_rarg0; // source array address const Register to = c_rarg1; // destination array address @@ -1057,6 +1099,9 @@ address StubGenerator::generate_cipherBlockChaining_decryptVectorAESCrypt() { __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(0); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -1069,11 +1114,17 @@ address StubGenerator::generate_cipherBlockChaining_decryptVectorAESCrypt() { // address StubGenerator::generate_aescrypt_encryptBlock() { assert(UseAES, "need AES instructions and misaligned SSE support"); - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_aescrypt_encryptBlock_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); Label L_doLast; - address start = __ pc(); + start = __ pc(); const Register from = c_rarg0; // source array address const Register to = c_rarg1; // destination array address @@ -1152,6 +1203,9 @@ address StubGenerator::generate_aescrypt_encryptBlock() { __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(0); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -1164,11 +1218,17 @@ address StubGenerator::generate_aescrypt_encryptBlock() { // address StubGenerator::generate_aescrypt_decryptBlock() { assert(UseAES, "need AES instructions and misaligned SSE support"); - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_aescrypt_decryptBlock_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); Label L_doLast; - address start = __ pc(); + start = __ pc(); const Register from = c_rarg0; // source array address const Register to = c_rarg1; // destination array address @@ -1248,6 +1308,9 @@ address StubGenerator::generate_aescrypt_decryptBlock() { __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(0); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -1266,10 +1329,16 @@ address StubGenerator::generate_aescrypt_decryptBlock() { // address StubGenerator::generate_cipherBlockChaining_encryptAESCrypt() { assert(UseAES, "need AES instructions and misaligned SSE support"); - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_cipherBlockChaining_encryptAESCrypt_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); Label L_exit, L_key_192_256, L_key_256, L_loopTop_128, L_loopTop_192, L_loopTop_256; const Register from = c_rarg0; // source array address @@ -1398,6 +1467,9 @@ address StubGenerator::generate_cipherBlockChaining_encryptAESCrypt() { __ jcc(Assembler::notEqual, L_loopTop_256); __ jmp(L_exit); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -1422,11 +1494,15 @@ address StubGenerator::generate_cipherBlockChaining_encryptAESCrypt() { // address StubGenerator::generate_electronicCodeBook_AESCrypt_Parallel(bool is_encrypt) { assert(UseAES, "need AES instructions and misaligned SSE support"); - __ align(CodeEntryAlignment); StubId stub_id = is_encrypt ? StubId::stubgen_electronicCodeBook_encryptAESCrypt_id : StubId::stubgen_electronicCodeBook_decryptAESCrypt_id; + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); const Register from = c_rarg0; // source array address const Register to = c_rarg1; // destination array address @@ -1581,6 +1657,9 @@ __ opc(xmm_result0, reg); __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(0); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; #undef DoFour @@ -1612,10 +1691,16 @@ address StubGenerator::generate_electronicCodeBook_decryptAESCrypt_Parallel() { // address StubGenerator::generate_cipherBlockChaining_decryptAESCrypt_Parallel() { assert(UseAES, "need AES instructions and misaligned SSE support"); - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_cipherBlockChaining_decryptAESCrypt_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); const Register from = c_rarg0; // source array address const Register to = c_rarg1; // destination array address @@ -1851,14 +1936,23 @@ __ opc(xmm_result3, src_reg); __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(0); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } address StubGenerator::generate_electronicCodeBook_encryptAESCrypt() { - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_electronicCodeBook_encryptAESCrypt_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); const Register from = c_rarg0; // source array address const Register to = c_rarg1; // destination array address @@ -1872,14 +1966,23 @@ address StubGenerator::generate_electronicCodeBook_encryptAESCrypt() { __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(0); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } address StubGenerator::generate_electronicCodeBook_decryptAESCrypt() { - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_electronicCodeBook_decryptAESCrypt_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); const Register from = c_rarg0; // source array address const Register to = c_rarg1; // destination array address @@ -1893,6 +1996,9 @@ address StubGenerator::generate_electronicCodeBook_decryptAESCrypt() { __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(0); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -4292,3 +4398,27 @@ void StubGenerator::aesgcm_avx2(Register in, Register len, Register ct, Register } #undef __ + +#if INCLUDE_CDS +void StubGenerator::init_AOTAddressTable_aes(GrowableArray
& external_addresses) { +#define ADD(addr) external_addresses.append((address)(addr)) + ADD(key_shuffle_mask_addr()); + ADD(counter_shuffle_mask_addr()); + ADD(counter_mask_linc0_addr()); + ADD(counter_mask_linc1_addr()); + ADD(counter_mask_linc1f_addr()); + ADD(counter_mask_linc2_addr()); + ADD(counter_mask_linc2f_addr()); + ADD(counter_mask_linc4_addr()); + ADD(counter_mask_linc8_addr()); + ADD(counter_mask_linc16_addr()); + ADD(counter_mask_linc32_addr()); + ADD(counter_mask_ones_addr()); + ADD(ghash_polynomial_reduction_addr()); + ADD(ghash_polynomial_two_one_addr()); + ADD(counter_mask_addbe_4444_addr()); + ADD(counter_mask_addbe_1234_addr()); + ADD(counter_mask_add_1234_addr()); +#undef ADD +} +#endif // INCLUDE_CDS diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_arraycopy.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_arraycopy.cpp index 01e004b7b43..5530e5325de 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_arraycopy.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_arraycopy.cpp @@ -570,10 +570,45 @@ address StubGenerator::generate_disjoint_copy_avx3_masked(StubId stub_id, addres default: ShouldNotReachHere(); } + GrowableArray
entries; + GrowableArray
extras; + bool add_handlers = !is_oop && !aligned; + bool add_relocs = UseZGC && is_oop; + bool add_extras = add_handlers || add_relocs; + // The stub employs one unsafe handler region by default but has two + // when MaxVectorSize == 64 So we may expect 0, 3 or 6 extras. + int handlers_count = (MaxVectorSize == 64 ? 2 : 1); + int expected_entry_count = (entry != nullptr ? 2 : 1); + int expected_extra_count = (add_handlers ? handlers_count : 0) * UnsafeMemoryAccess::COLUMN_COUNT; // 0/1/2 x UMAM {start,end,handler} + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == expected_entry_count, "sanity check"); + GrowableArray
* entries_ptr = (entry_count == 1 ? nullptr : &entries); + GrowableArray
* extras_ptr = (add_extras ? &extras : nullptr); + address start = load_archive_data(stub_id, entries_ptr, extras_ptr); + if (start != nullptr) { + assert(entries.length() == expected_entry_count - 1, + "unexpected entry count %d", entries.length()); + assert(!add_handlers || extras.length() == expected_extra_count, + "unexpected handler addresses count %d", extras.length()); + if (entry != nullptr) { + *entry = entries.at(0); + } + if (add_handlers) { + // restore 1/2 x UMAM {start,end,handler} addresses from extras + register_unsafe_access_handlers(extras, 0, handlers_count); + } +#if INCLUDE_ZGC + // register addresses at which ZGC does colour patching + if (add_relocs) { + register_reloc_addresses(extras, 0, extras.length()); + } +#endif // INCLUDE_ZGC + return start; + } __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); bool use64byteVector = (MaxVectorSize > 32) && (CopyAVX3Threshold == 0); const int large_threshold = 2621440; // 2.5 MB @@ -595,6 +630,7 @@ address StubGenerator::generate_disjoint_copy_avx3_masked(StubId stub_id, addres if (entry != nullptr) { *entry = __ pc(); + entries.append(*entry); // caller can pass a 64-bit byte count here (from Unsafe.copyMemory) BLOCK_COMMENT("Entry:"); } @@ -620,7 +656,7 @@ address StubGenerator::generate_disjoint_copy_avx3_masked(StubId stub_id, addres int threshold[] = { 4096, 2048, 1024, 512}; // UnsafeMemoryAccess page error: continue after unsafe access - UnsafeMemoryAccessMark umam(this, !is_oop && !aligned, true); + UnsafeMemoryAccessMark umam(this, add_handlers, true); // 'from', 'to' and 'count' are now valid // temp1 holds remaining count and temp4 holds running count used to compute @@ -789,10 +825,28 @@ address StubGenerator::generate_disjoint_copy_avx3_masked(StubId stub_id, addres if (MaxVectorSize == 64) { __ BIND(L_copy_large); - UnsafeMemoryAccessMark umam(this, !is_oop && !aligned, false, ucme_exit_pc); + UnsafeMemoryAccessMark umam(this, add_handlers, false, ucme_exit_pc); arraycopy_avx3_large(to, from, temp1, temp2, temp3, temp4, count, xmm1, xmm2, xmm3, xmm4, shift); __ jmp(L_finish); } + // retrieve the registered handler addresses + address end = __ pc(); + if (add_handlers) { + retrieve_unsafe_access_handlers(start, end, extras); + } + assert(extras.length() == expected_extra_count, + "unexpected handler addresses count %d", extras.length()); +#if INCLUDE_ZGC + // retrieve addresses at which ZGC does colour patching + if (add_relocs) { + retrieve_reloc_addresses(start, end, extras); + } +#endif // INCLUDE_ZGC + + // record the stub entry and end plus the no_push entry and any + // extra handler addresses + store_archive_data(stub_id, start, end, entries_ptr, extras_ptr); + return start; } @@ -907,10 +961,41 @@ address StubGenerator::generate_conjoint_copy_avx3_masked(StubId stub_id, addres default: ShouldNotReachHere(); } - + GrowableArray
entries; + GrowableArray
extras; + bool add_handlers = !is_oop && !aligned; + bool add_relocs = UseZGC && is_oop; + bool add_extras = add_handlers || add_relocs; + int expected_entry_count = (entry != nullptr ? 2 : 1); + int expected_handler_count = (add_handlers ? 1 : 0) * UnsafeMemoryAccess::COLUMN_COUNT; // 0/1 x UMAM {start,end,handler} + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == expected_entry_count, "sanity check"); + GrowableArray
* entries_ptr = (entry_count == 1 ? nullptr : &entries); + GrowableArray
* extras_ptr = (add_extras ? &extras : nullptr); + address start = load_archive_data(stub_id, entries_ptr, extras_ptr); + if (start != nullptr) { + assert(entries.length() == expected_entry_count - 1, + "unexpected entry count %d", entries.length()); + assert(!add_handlers || extras.length() == expected_handler_count, + "unexpected handler addresses count %d", extras.length()); + if (entry != nullptr) { + *entry = entries.at(0); + } + if (add_handlers) { + // restore 1 x UMAM {start,end,handler} addresses from extras + register_unsafe_access_handlers(extras, 0, 1); + } +#if INCLUDE_ZGC + if (add_relocs) { + // register addresses at which ZGC does colour patching + register_reloc_addresses(extras, 0, extras.length()); + } +#endif // INCLUDE_ZGC + return start; + } __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); bool use64byteVector = (MaxVectorSize > 32) && (CopyAVX3Threshold == 0); @@ -931,6 +1016,7 @@ address StubGenerator::generate_conjoint_copy_avx3_masked(StubId stub_id, addres if (entry != nullptr) { *entry = __ pc(); + entries.append(*entry); // caller can pass a 64-bit byte count here (from Unsafe.copyMemory) BLOCK_COMMENT("Entry:"); } @@ -957,7 +1043,7 @@ address StubGenerator::generate_conjoint_copy_avx3_masked(StubId stub_id, addres int threshold[] = { 4096, 2048, 1024, 512}; // UnsafeMemoryAccess page error: continue after unsafe access - UnsafeMemoryAccessMark umam(this, !is_oop && !aligned, true); + UnsafeMemoryAccessMark umam(this, add_handlers, true); // 'from', 'to' and 'count' are now valid // temp1 holds remaining count. @@ -1071,6 +1157,23 @@ address StubGenerator::generate_conjoint_copy_avx3_masked(StubId stub_id, addres __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(0); + // retrieve the registered handler addresses + address end = __ pc(); + if (add_handlers) { + retrieve_unsafe_access_handlers(start, end, extras); + } + assert(extras.length() == expected_handler_count, + "unexpected handler addresses count %d", extras.length()); +#if INCLUDE_ZGC + // retrieve addresses at which ZGC does colour patching + if (add_relocs) { + retrieve_reloc_addresses(start, end, extras); + } +#endif // INCLUDE_ZGC + // record the stub entry and end plus the no_push entry and any + // extra handler addresses + store_archive_data(stub_id, start, end, entries_ptr, extras_ptr); + return start; } @@ -1385,9 +1488,29 @@ address StubGenerator::generate_disjoint_byte_copy(address* entry) { return generate_disjoint_copy_avx3_masked(stub_id, entry); } #endif + GrowableArray
entries; + GrowableArray
extras; + int expected_entry_count = (entry != nullptr ? 2 : 1); + int expected_handler_count = (2 * UnsafeMemoryAccess::COLUMN_COUNT); // 2 x UMAM {start,end,handler} + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == expected_entry_count, "sanity check"); + GrowableArray
* entries_ptr = (entry_count == 1 ? nullptr : &entries); + address start = load_archive_data(stub_id, entries_ptr, &extras); + if (start != nullptr) { + assert(entries.length() == expected_entry_count - 1, + "unexpected entry count %d", entries.length()); + assert(extras.length() == expected_handler_count, + "unexpected handler addresses count %d", extras.length()); + if (entry != nullptr) { + *entry = entries.at(0); + } + // restore 2 UMAM {start,end,handler} addresses from extras + register_unsafe_access_handlers(extras, 0, 2); + return start; + } __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); DecoratorSet decorators = IN_HEAP | IS_ARRAY | ARRAYCOPY_DISJOINT; Label L_copy_bytes, L_copy_8_bytes, L_copy_4_bytes, L_copy_2_bytes; @@ -1407,6 +1530,7 @@ address StubGenerator::generate_disjoint_byte_copy(address* entry) { if (entry != nullptr) { *entry = __ pc(); + entries.append(*entry); // caller can pass a 64-bit byte count here (from Unsafe.copyMemory) BLOCK_COMMENT("Entry:"); } @@ -1476,6 +1600,17 @@ __ BIND(L_exit); copy_bytes_forward(end_from, end_to, qword_count, rax, r10, L_copy_bytes, L_copy_8_bytes, decorators, T_BYTE); __ jmp(L_copy_4_bytes); } + + // retrieve the registered handler addresses + address end = __ pc(); + retrieve_unsafe_access_handlers(start, end, extras); + assert(extras.length() == expected_handler_count, + "unexpected handler addresses count %d", extras.length()); + + // record the stub entry and end plus the no_push entry and any + // extra handler addresses + store_archive_data(stub_id, start, end, entries_ptr, &extras); + return start; } @@ -1503,9 +1638,29 @@ address StubGenerator::generate_conjoint_byte_copy(address nooverlap_target, add return generate_conjoint_copy_avx3_masked(stub_id, entry, nooverlap_target); } #endif + GrowableArray
entries; + GrowableArray
extras; + int expected_entry_count = (entry != nullptr ? 2 : 1); + int expected_handler_count = (2 * UnsafeMemoryAccess::COLUMN_COUNT); // 2 x UMAM {start,end,handler} + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == expected_entry_count, "sanity check"); + GrowableArray
* entries_ptr = (entry_count == 1 ? nullptr : &entries); + address start = load_archive_data(stub_id, entries_ptr, &extras); + if (start != nullptr) { + assert(entries.length() == expected_entry_count - 1, + "unexpected entry count %d", entries.length()); + assert(extras.length() == expected_handler_count, + "unexpected handler addresses count %d", extras.length()); + if (entry != nullptr) { + *entry = entries.at(0); + } + // restore 2 UMAM {start,end,handler} addresses from extras + register_unsafe_access_handlers(extras, 0, 2); + return start; + } __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); DecoratorSet decorators = IN_HEAP | IS_ARRAY; Label L_copy_bytes, L_copy_8_bytes, L_copy_4_bytes, L_copy_2_bytes; @@ -1520,6 +1675,7 @@ address StubGenerator::generate_conjoint_byte_copy(address nooverlap_target, add if (entry != nullptr) { *entry = __ pc(); + entries.append(*entry); // caller can pass a 64-bit byte count here (from Unsafe.copyMemory) BLOCK_COMMENT("Entry:"); } @@ -1586,6 +1742,16 @@ address StubGenerator::generate_conjoint_byte_copy(address nooverlap_target, add __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(0); + // retrieve the registered handler addresses + address end = __ pc(); + retrieve_unsafe_access_handlers(start, end, extras); + assert(extras.length() == expected_handler_count, + "unexpected handler addresses count %d", extras.length()); + + // record the stub entry and end plus the no_push entry and any + // extra handler addresses + store_archive_data(stub_id, start, end, entries_ptr, &extras); + return start; } @@ -1616,10 +1782,29 @@ address StubGenerator::generate_disjoint_short_copy(address *entry) { return generate_disjoint_copy_avx3_masked(stub_id, entry); } #endif - + GrowableArray
entries; + GrowableArray
extras; + int expected_entry_count = (entry != nullptr ? 2 : 1); + int expected_handler_count = (2 * UnsafeMemoryAccess::COLUMN_COUNT); // 2 x UMAM {start,end,handler} + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == expected_entry_count, "sanity check"); + GrowableArray
* entries_ptr = (entry_count == 1 ? nullptr : &entries); + address start = load_archive_data(stub_id, entries_ptr, &extras); + if (start != nullptr) { + assert(entries.length() == expected_entry_count - 1, + "unexpected entry count %d", entries.length()); + assert(extras.length() == expected_handler_count, + "unexpected handler addresses count %d", extras.length()); + if (entry != nullptr) { + *entry = entries.at(0); + } + // restore 2 UMAM {start,end,handler} addresses from extras + register_unsafe_access_handlers(extras, 0, 2); + return start; + } __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); DecoratorSet decorators = IN_HEAP | IS_ARRAY | ARRAYCOPY_DISJOINT; Label L_copy_bytes, L_copy_8_bytes, L_copy_4_bytes,L_copy_2_bytes,L_exit; @@ -1638,6 +1823,7 @@ address StubGenerator::generate_disjoint_short_copy(address *entry) { if (entry != nullptr) { *entry = __ pc(); + entries.append(*entry); // caller can pass a 64-bit byte count here (from Unsafe.copyMemory) BLOCK_COMMENT("Entry:"); } @@ -1701,6 +1887,16 @@ __ BIND(L_exit); __ jmp(L_copy_4_bytes); } + // retrieve the registered handler addresses + address end = __ pc(); + retrieve_unsafe_access_handlers(start, end, extras); + assert(extras.length() == expected_handler_count, + "unexpected handler addresses count %d", extras.length()); + + // record the stub entry and end plus the no_push entry and any + // extra handler addresses + store_archive_data(stub_id, start, end, entries_ptr, &extras); + return start; } @@ -1708,7 +1904,6 @@ __ BIND(L_exit); address StubGenerator::generate_fill(StubId stub_id) { BasicType t; bool aligned; - switch (stub_id) { case StubId::stubgen_jbyte_fill_id: t = T_BYTE; @@ -1737,10 +1932,27 @@ address StubGenerator::generate_fill(StubId stub_id) { default: ShouldNotReachHere(); } + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + GrowableArray
extras; + bool add_handlers = ((t == T_BYTE) && !aligned); + int handlers_count = (add_handlers ? 1 : 0); + int expected_extras_count = (handlers_count * UnsafeMemoryAccess::COLUMN_COUNT); // 0/1 x UMAM {start,end,handler} + GrowableArray
* extras_ptr = (add_handlers ? &extras : nullptr); + address start = load_archive_data(stub_id, nullptr, extras_ptr); + if (start != nullptr) { + assert(extras.length() == expected_extras_count, + "unexpected handler addresses count %d", extras.length()); + if (add_handlers) { + // restore 1 x UMAM {start,end,handler} addresses from extras + register_unsafe_access_handlers(extras, 0, 1); + } + return start; + } __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); BLOCK_COMMENT("Entry:"); @@ -1753,7 +1965,7 @@ address StubGenerator::generate_fill(StubId stub_id) { { // Add set memory mark to protect against unsafe accesses faulting - UnsafeMemoryAccessMark umam(this, ((t == T_BYTE) && !aligned), true); + UnsafeMemoryAccessMark umam(this, add_handlers, true); __ generate_fill(t, aligned, to, value, r11, rax, xmm0); } @@ -1761,6 +1973,15 @@ address StubGenerator::generate_fill(StubId stub_id) { __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(0); + address end = __ pc(); + if (add_handlers) { + retrieve_unsafe_access_handlers(start, end, extras); + } + assert(extras.length() == expected_extras_count, + "unexpected handler addresses count %d", extras.length()); + // record the stub entry and end + store_archive_data(stub_id, start, end, nullptr, extras_ptr); + return start; } @@ -1788,10 +2009,29 @@ address StubGenerator::generate_conjoint_short_copy(address nooverlap_target, ad return generate_conjoint_copy_avx3_masked(stub_id, entry, nooverlap_target); } #endif - + GrowableArray
entries; + GrowableArray
extras; + int expected_entry_count = (entry != nullptr ? 2 : 1); + int expected_handler_count = (2 * UnsafeMemoryAccess::COLUMN_COUNT); // 2 x UMAM {start,end,handler} + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == expected_entry_count, "sanity check"); + GrowableArray
* entries_ptr = (entry_count == 1 ? nullptr : &entries); + address start = load_archive_data(stub_id, entries_ptr, &extras); + if (start != nullptr) { + assert(entries.length() == expected_entry_count - 1, + "unexpected entry count %d", entries.length()); + assert(extras.length() == expected_handler_count, + "unexpected handler addresses count %d", extras.length()); + if (entry != nullptr) { + *entry = entries.at(0); + } + // restore 2 UMAM {start,end,handler} addresses from extras + register_unsafe_access_handlers(extras, 0, 2); + return start; + } __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); DecoratorSet decorators = IN_HEAP | IS_ARRAY; Label L_copy_bytes, L_copy_8_bytes, L_copy_4_bytes; @@ -1806,6 +2046,7 @@ address StubGenerator::generate_conjoint_short_copy(address nooverlap_target, ad if (entry != nullptr) { *entry = __ pc(); + entries.append(*entry); // caller can pass a 64-bit byte count here (from Unsafe.copyMemory) BLOCK_COMMENT("Entry:"); } @@ -1864,6 +2105,16 @@ address StubGenerator::generate_conjoint_short_copy(address nooverlap_target, ad __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(0); + // retrieve the registered handler addresses + address end = __ pc(); + retrieve_unsafe_access_handlers(start, end, extras); + assert(extras.length() == expected_handler_count, + "unexpected handler addresses count %d", extras.length()); + + // record the stub entry and end plus the no_push entry and any + // extra handler addresses + store_archive_data(stub_id, start, end, entries_ptr, &extras); + return start; } @@ -1916,10 +2167,42 @@ address StubGenerator::generate_disjoint_int_oop_copy(StubId stub_id, address* e return generate_disjoint_copy_avx3_masked(stub_id, entry); } #endif + GrowableArray
entries; + GrowableArray
extras; + bool add_handlers = !is_oop && !aligned; + bool add_relocs = UseZGC && is_oop; + bool add_extras = add_handlers || add_relocs; + int expected_entry_count = (entry != nullptr ? 2 : 1); + int expected_handler_count = (add_handlers ? 2 : 0) * UnsafeMemoryAccess::COLUMN_COUNT; // 0/2 x UMAM {start,end,handler} + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == expected_entry_count, "sanity check"); + GrowableArray
* entries_ptr = (entry_count == 1 ? nullptr : &entries); + GrowableArray
* extras_ptr = (add_extras ? &extras : nullptr); + address start = load_archive_data(stub_id, entries_ptr, extras_ptr); + if (start != nullptr) { + assert(entries.length() == expected_entry_count - 1, + "unexpected entry count %d", entries.length()); + assert(!add_handlers || extras.length() == expected_handler_count, + "unexpected handler addresses count %d", extras.length()); + if (entry != nullptr) { + *entry = entries.at(0); + } + if (add_handlers) { + // restore 2 UMAM {start,end,handler} addresses from extras + register_unsafe_access_handlers(extras, 0, 2); + } +#if INCLUDE_ZGC + // register addresses at which ZGC does colour patching + if (add_relocs) { + register_reloc_addresses(extras, 0, extras.length()); + } +#endif // INCLUDE_ZGC + return start; + } __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); Label L_copy_bytes, L_copy_8_bytes, L_copy_4_bytes, L_exit; const Register from = rdi; // source array address @@ -1937,6 +2220,7 @@ address StubGenerator::generate_disjoint_int_oop_copy(StubId stub_id, address* e if (entry != nullptr) { *entry = __ pc(); + entries.append(*entry); // caller can pass a 64-bit byte count here (from Unsafe.copyMemory) BLOCK_COMMENT("Entry:"); } @@ -1957,7 +2241,7 @@ address StubGenerator::generate_disjoint_int_oop_copy(StubId stub_id, address* e { // UnsafeMemoryAccess page error: continue after unsafe access - UnsafeMemoryAccessMark umam(this, !is_oop && !aligned, true); + UnsafeMemoryAccessMark umam(this, add_handlers, true); // 'from', 'to' and 'count' are now valid __ movptr(dword_count, count); __ shrptr(count, 1); // count => qword_count @@ -1969,20 +2253,20 @@ address StubGenerator::generate_disjoint_int_oop_copy(StubId stub_id, address* e __ jmp(L_copy_bytes); // Copy trailing qwords - __ BIND(L_copy_8_bytes); + __ BIND(L_copy_8_bytes); __ movq(rax, Address(end_from, qword_count, Address::times_8, 8)); __ movq(Address(end_to, qword_count, Address::times_8, 8), rax); __ increment(qword_count); __ jcc(Assembler::notZero, L_copy_8_bytes); // Check for and copy trailing dword - __ BIND(L_copy_4_bytes); + __ BIND(L_copy_4_bytes); __ testl(dword_count, 1); // Only byte test since the value is 0 or 1 __ jccb(Assembler::zero, L_exit); __ movl(rax, Address(end_from, 8)); __ movl(Address(end_to, 8), rax); } -__ BIND(L_exit); + __ BIND(L_exit); address ucme_exit_pc = __ pc(); bs->arraycopy_epilogue(_masm, decorators, type, from, to, dword_count); restore_arg_regs_using_thread(); @@ -1993,12 +2277,30 @@ __ BIND(L_exit); __ ret(0); { - UnsafeMemoryAccessMark umam(this, !is_oop && !aligned, false, ucme_exit_pc); + UnsafeMemoryAccessMark umam(this, add_handlers, false, ucme_exit_pc); // Copy in multi-bytes chunks copy_bytes_forward(end_from, end_to, qword_count, rax, r10, L_copy_bytes, L_copy_8_bytes, decorators, is_oop ? T_OBJECT : T_INT); __ jmp(L_copy_4_bytes); } + // retrieve the registered handler addresses + address end = __ pc(); + if (add_handlers) { + retrieve_unsafe_access_handlers(start, end, extras); + } + assert(extras.length() == expected_handler_count, + "unexpected handler addresses count %d", extras.length()); +#if INCLUDE_ZGC + // retrieve addresses at which ZGC does colour patching + if (add_relocs) { + retrieve_reloc_addresses(start, end, extras); + } +#endif // INCLUDE_ZGC + + // record the stub entry and end plus the no_push entry and any + // extra handler addresses + store_archive_data(stub_id, start, end, entries_ptr, extras_ptr); + return start; } @@ -2047,10 +2349,42 @@ address StubGenerator::generate_conjoint_int_oop_copy(StubId stub_id, address no return generate_conjoint_copy_avx3_masked(stub_id, entry, nooverlap_target); } #endif + bool add_handlers = !is_oop && !aligned; + bool add_relocs = UseZGC && is_oop; + bool add_extras = add_handlers || add_relocs; + GrowableArray
entries; + GrowableArray
extras; + int expected_entry_count = (entry != nullptr ? 2 : 1); + int expected_handler_count = (add_handlers ? 2 : 0) * UnsafeMemoryAccess::COLUMN_COUNT; // 0/2 x UMAM {start,end,handler} + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == expected_entry_count, "sanity check"); + GrowableArray
* entries_ptr = (entry_count == 1 ? nullptr : &entries); + GrowableArray
* extras_ptr = (add_extras ? &extras : nullptr); + address start = load_archive_data(stub_id, entries_ptr, extras_ptr); + if (start != nullptr) { + assert(entries.length() == expected_entry_count - 1, + "unexpected entry count %d", entries.length()); + assert(!add_handlers || extras.length() == expected_handler_count, + "unexpected handler addresses count %d", extras.length()); + if (entry != nullptr) { + *entry = entries.at(0); + } + if (add_handlers) { + // restore 2 UMAM {start,end,handler} addresses from extras + register_unsafe_access_handlers(extras, 0, 2); + } +#if INCLUDE_ZGC + // register addresses at which ZGC does colour patching + if (add_relocs) { + register_reloc_addresses(extras, 6, extras.length()); + } +#endif // INCLUDE_ZGC + return start; + } __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); Label L_copy_bytes, L_copy_8_bytes, L_exit; const Register from = rdi; // source array address @@ -2064,7 +2398,8 @@ address StubGenerator::generate_conjoint_int_oop_copy(StubId stub_id, address no if (entry != nullptr) { *entry = __ pc(); - // caller can pass a 64-bit byte count here (from Unsafe.copyMemory) + entries.append(*entry); + // caller can pass a 64-bit byte count here (from Unsafe.copyMemory) BLOCK_COMMENT("Entry:"); } @@ -2087,7 +2422,7 @@ address StubGenerator::generate_conjoint_int_oop_copy(StubId stub_id, address no assert_clean_int(count, rax); // Make sure 'count' is clean int. { // UnsafeMemoryAccess page error: continue after unsafe access - UnsafeMemoryAccessMark umam(this, !is_oop && !aligned, true); + UnsafeMemoryAccessMark umam(this, add_handlers, true); // 'from', 'to' and 'count' are now valid __ movptr(dword_count, count); __ shrptr(count, 1); // count => qword_count @@ -2102,7 +2437,7 @@ address StubGenerator::generate_conjoint_int_oop_copy(StubId stub_id, address no __ jmp(L_copy_bytes); // Copy trailing qwords - __ BIND(L_copy_8_bytes); + __ BIND(L_copy_8_bytes); __ movq(rax, Address(from, qword_count, Address::times_8, -8)); __ movq(Address(to, qword_count, Address::times_8, -8), rax); __ decrement(qword_count); @@ -2120,12 +2455,12 @@ address StubGenerator::generate_conjoint_int_oop_copy(StubId stub_id, address no { // UnsafeMemoryAccess page error: continue after unsafe access - UnsafeMemoryAccessMark umam(this, !is_oop && !aligned, true); + UnsafeMemoryAccessMark umam(this, add_handlers, true); // Copy in multi-bytes chunks copy_bytes_backward(from, to, qword_count, rax, r10, L_copy_bytes, L_copy_8_bytes, decorators, is_oop ? T_OBJECT : T_INT); } -__ BIND(L_exit); + __ BIND(L_exit); bs->arraycopy_epilogue(_masm, decorators, type, from, to, dword_count); restore_arg_regs_using_thread(); INC_COUNTER_NP(SharedRuntime::_jint_array_copy_ctr, rscratch1); // Update counter after rscratch1 is free @@ -2134,6 +2469,23 @@ __ BIND(L_exit); __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(0); + // retrieve the registered handler addresses + address end = __ pc(); + if (add_handlers) { + retrieve_unsafe_access_handlers(start, end, extras); + } + assert(extras.length() == expected_handler_count, + "unexpected handler addresses count %d", extras.length()); +#if INCLUDE_ZGC + // retrieve addresses at which ZGC does colour patching + if (add_relocs) { + retrieve_reloc_addresses(start, end, extras); + } +#endif // INCLUDE_ZGC + // record the stub entry and end plus the no_push entry and any + // extra handler addresses + store_archive_data(stub_id, start, end, entries_ptr, extras_ptr); + return start; } @@ -2180,10 +2532,42 @@ address StubGenerator::generate_disjoint_long_oop_copy(StubId stub_id, address * return generate_disjoint_copy_avx3_masked(stub_id, entry); } #endif + bool add_handlers = !is_oop && !aligned; + bool add_relocs = UseZGC && is_oop; + bool add_extras = add_handlers || add_relocs; + GrowableArray
entries; + GrowableArray
extras; + int expected_entry_count = (entry != nullptr ? 2 : 1); + int expected_handler_count = (add_handlers ? 2 : 0) * UnsafeMemoryAccess::COLUMN_COUNT; // 0/2 x UMAM {start,end,handler} + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == expected_entry_count, "sanity check"); + GrowableArray
* entries_ptr = (entry_count == 1 ? nullptr : &entries); + GrowableArray
* extras_ptr = (add_extras ? &extras : nullptr); + address start = load_archive_data(stub_id, entries_ptr, extras_ptr); + if (start != nullptr) { + assert(entries.length() == expected_entry_count - 1, + "unexpected entry count %d", entries.length()); + assert(!add_handlers || extras.length() == expected_handler_count, + "unexpected handler addresses count %d", extras.length()); + if (entry != nullptr) { + *entry = entries.at(0); + } + if (add_handlers) { + // restore 2 UMAM {start,end,handler} addresses from extras + register_unsafe_access_handlers(extras, 0, 2); + } +#if INCLUDE_ZGC + // register addresses at which ZGC does colour patching + if (add_relocs) { + register_reloc_addresses(extras, 0, extras.length()); + } +#endif // INCLUDE_ZGC + return start; + } __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); Label L_copy_bytes, L_copy_8_bytes, L_exit; const Register from = rdi; // source array address @@ -2201,6 +2585,7 @@ address StubGenerator::generate_disjoint_long_oop_copy(StubId stub_id, address * if (entry != nullptr) { *entry = __ pc(); + entries.append(*entry); // caller can pass a 64-bit byte count here (from Unsafe.copyMemory) BLOCK_COMMENT("Entry:"); } @@ -2221,7 +2606,7 @@ address StubGenerator::generate_disjoint_long_oop_copy(StubId stub_id, address * bs->arraycopy_prologue(_masm, decorators, type, from, to, qword_count); { // UnsafeMemoryAccess page error: continue after unsafe access - UnsafeMemoryAccessMark umam(this, !is_oop && !aligned, true); + UnsafeMemoryAccessMark umam(this, add_handlers, true); // Copy from low to high addresses. Use 'to' as scratch. __ lea(end_from, Address(from, qword_count, Address::times_8, -8)); @@ -2253,7 +2638,7 @@ address StubGenerator::generate_disjoint_long_oop_copy(StubId stub_id, address * { // UnsafeMemoryAccess page error: continue after unsafe access - UnsafeMemoryAccessMark umam(this, !is_oop && !aligned, true); + UnsafeMemoryAccessMark umam(this, add_handlers, true); // Copy in multi-bytes chunks copy_bytes_forward(end_from, end_to, qword_count, rax, r10, L_copy_bytes, L_copy_8_bytes, decorators, is_oop ? T_OBJECT : T_LONG); } @@ -2269,6 +2654,23 @@ address StubGenerator::generate_disjoint_long_oop_copy(StubId stub_id, address * __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(0); + // retrieve the registered handler addresses + address end = __ pc(); + if (add_handlers) { + retrieve_unsafe_access_handlers(start, end, extras); + } + assert(extras.length() == expected_handler_count, + "unexpected handler addresses count %d", extras.length()); +#if INCLUDE_ZGC + // retrieve addresses at which ZGC does colour patching + if (add_relocs) { + retrieve_reloc_addresses(start, end, extras); + } +#endif // INCLUDE_ZGC + // record the stub entry and end plus the no_push entry and any + // extra handler addresses + store_archive_data(stub_id, start, end, entries_ptr, extras_ptr); + return start; } @@ -2313,10 +2715,42 @@ address StubGenerator::generate_conjoint_long_oop_copy(StubId stub_id, address n return generate_conjoint_copy_avx3_masked(stub_id, entry, nooverlap_target); } #endif + bool add_handlers = !is_oop && !aligned; + bool add_relocs = UseZGC && is_oop; + bool add_extras = add_handlers || add_relocs; + GrowableArray
entries; + GrowableArray
extras; + int expected_entry_count = (entry != nullptr ? 2 : 1); + int expected_handler_count = (add_handlers ? 2 : 0) * UnsafeMemoryAccess::COLUMN_COUNT; // 0/2 x UMAM {start,end,handler} + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == expected_entry_count, "sanity check"); + GrowableArray
* entries_ptr = (entry_count == 1 ? nullptr : &entries); + GrowableArray
* extras_ptr = (add_extras ? &extras : nullptr); + address start = load_archive_data(stub_id, entries_ptr, extras_ptr); + if (start != nullptr) { + assert(entries.length() == expected_entry_count - 1, + "unexpected entry count %d", entries.length()); + assert(!add_handlers || extras.length() == expected_handler_count, + "unexpected handler addresses count %d", extras.length()); + if (entry != nullptr) { + *entry = entries.at(0); + } + if (add_handlers) { + // restore 2 UMAM {start,end,handler} addresses from extras + register_unsafe_access_handlers(extras, 0, 2); + } +#if INCLUDE_ZGC + // register addresses at which ZGC does colour patching + if (add_relocs) { + register_reloc_addresses(extras, 0, extras.length()); + } +#endif // INCLUDE_ZGC + return start; + } __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); Label L_copy_bytes, L_copy_8_bytes, L_exit; const Register from = rdi; // source array address @@ -2329,6 +2763,7 @@ address StubGenerator::generate_conjoint_long_oop_copy(StubId stub_id, address n if (entry != nullptr) { *entry = __ pc(); + entries.append(*entry); // caller can pass a 64-bit byte count here (from Unsafe.copyMemory) BLOCK_COMMENT("Entry:"); } @@ -2350,7 +2785,7 @@ address StubGenerator::generate_conjoint_long_oop_copy(StubId stub_id, address n bs->arraycopy_prologue(_masm, decorators, type, from, to, qword_count); { // UnsafeMemoryAccess page error: continue after unsafe access - UnsafeMemoryAccessMark umam(this, !is_oop && !aligned, true); + UnsafeMemoryAccessMark umam(this, add_handlers, true); __ jmp(L_copy_bytes); @@ -2377,7 +2812,7 @@ address StubGenerator::generate_conjoint_long_oop_copy(StubId stub_id, address n } { // UnsafeMemoryAccess page error: continue after unsafe access - UnsafeMemoryAccessMark umam(this, !is_oop && !aligned, true); + UnsafeMemoryAccessMark umam(this, add_handlers, true); // Copy in multi-bytes chunks copy_bytes_backward(from, to, qword_count, rax, r10, L_copy_bytes, L_copy_8_bytes, decorators, is_oop ? T_OBJECT : T_LONG); @@ -2393,6 +2828,24 @@ address StubGenerator::generate_conjoint_long_oop_copy(StubId stub_id, address n __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(0); + + // retrieve the registered handler addresses + address end = __ pc(); + if (add_handlers) { + retrieve_unsafe_access_handlers(start, end, extras); + } + assert(extras.length() == expected_handler_count, + "unexpected handler addresses count %d", extras.length()); +#if INCLUDE_ZGC + // retrieve addresses at which ZGC does colour patching + if ((UseZGC && is_oop)) { + retrieve_reloc_addresses(start, end, extras); + } +#endif // INCLUDE_ZGC + // record the stub entry and end plus the no_push entry and any + // extra handler addresses + store_archive_data(stub_id, start, end, entries_ptr, extras_ptr); + return start; } @@ -2448,6 +2901,28 @@ address StubGenerator::generate_checkcast_copy(StubId stub_id, address *entry) { ShouldNotReachHere(); } + GrowableArray
entries; + GrowableArray
extras; + int expected_entry_count = (entry != nullptr ? 2 : 1); + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == expected_entry_count, "sanity check"); + GrowableArray
* entries_ptr = (entry_count == 1 ? nullptr : &entries); + GrowableArray
* extras_ptr = (UseZGC ? &extras : nullptr); + address start = load_archive_data(stub_id, entries_ptr, extras_ptr); + if (start != nullptr) { + assert(entries.length() == expected_entry_count - 1, + "unexpected addresses count %d", entries.length()); + if (entry != nullptr) { + *entry = entries.at(0); + } +#if INCLUDE_ZGC + if (UseZGC) { + register_reloc_addresses(extras, 0, extras.length()); + } +#endif // INCLUDE_ZGC + return start; + } + Label L_load_element, L_store_element, L_do_card_marks, L_done; // Input registers (after setup_arg_regs) @@ -2477,7 +2952,7 @@ address StubGenerator::generate_checkcast_copy(StubId stub_id, address *entry) { __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); __ enter(); // required for proper stackwalking of RuntimeStub frame @@ -2502,6 +2977,7 @@ address StubGenerator::generate_checkcast_copy(StubId stub_id, address *entry) { // Caller of this entry point must set up the argument registers. if (entry != nullptr) { *entry = __ pc(); + entries.append(*entry); BLOCK_COMMENT("Entry:"); } @@ -2636,6 +3112,16 @@ address StubGenerator::generate_checkcast_copy(StubId stub_id, address *entry) { __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(0); + address end = __ pc(); +#if INCLUDE_ZGC + // retrieve addresses at which ZGC does colour patching + if (UseZGC) { + retrieve_reloc_addresses(start, end, extras); + } +#endif // INCLUDE_ZGC + // record the stub entry and end plus the no_push entry + store_archive_data(stub_id, start, end, entries_ptr, extras_ptr); + return start; } @@ -2655,6 +3141,14 @@ address StubGenerator::generate_checkcast_copy(StubId stub_id, address *entry) { address StubGenerator::generate_unsafe_copy(address byte_copy_entry, address short_copy_entry, address int_copy_entry, address long_copy_entry) { + StubId stub_id = StubId::stubgen_unsafe_arraycopy_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + Label L_long_aligned, L_int_aligned, L_short_aligned; // Input registers (before setup_arg_regs) @@ -2666,9 +3160,8 @@ address StubGenerator::generate_unsafe_copy(address byte_copy_entry, address sho const Register bits = rax; // test copy of low bits __ align(CodeEntryAlignment); - StubId stub_id = StubId::stubgen_unsafe_arraycopy_id; StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); __ enter(); // required for proper stackwalking of RuntimeStub frame @@ -2700,6 +3193,9 @@ address StubGenerator::generate_unsafe_copy(address byte_copy_entry, address sho __ shrptr(size, LogBytesPerLong); // size => qword_count __ jump(RuntimeAddress(long_copy_entry)); + // record the stub entry and end plus + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -2801,10 +3297,23 @@ static void do_setmemory_atomic_loop(USM_TYPE type, Register dest, // to an int, short, or byte fill loop. // address StubGenerator::generate_unsafe_setmemory(address unsafe_byte_fill) { - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_unsafe_setmemory_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + // we expect three set of extra unsafememory access handler entries + GrowableArray
extras; + int expected_handler_count = 3 * UnsafeMemoryAccess::COLUMN_COUNT; + address start = load_archive_data(stub_id, nullptr, &extras); + if (start != nullptr) { + assert(extras.length() == expected_handler_count, + "unexpected handler addresses count %d", extras.length()); + register_unsafe_access_handlers(extras, 0, 3); + return start; + } + + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); __ enter(); // required for proper stackwalking of RuntimeStub frame assert(unsafe_byte_fill != nullptr, "Invalid call"); @@ -2894,6 +3403,16 @@ address StubGenerator::generate_unsafe_setmemory(address unsafe_byte_fill) { __ jump(RuntimeAddress(unsafe_byte_fill)); } + // retrieve the registered handler addresses + address end = __ pc(); + retrieve_unsafe_access_handlers(start, end, extras); + assert(extras.length() == expected_handler_count, + "unexpected handler addresses count %d", extras.length()); + + // record the stub entry and end plus the no_push entry and any + // extra handler addresses + store_archive_data(stub_id, start, end, nullptr, &extras); + return start; } @@ -2950,7 +3469,15 @@ address StubGenerator::generate_generic_copy(address byte_copy_entry, address sh address int_copy_entry, address oop_copy_entry, address long_copy_entry, address checkcast_copy_entry) { - Label L_failed, L_failed_0, L_objArray; + StubId stub_id = StubId::stubgen_generic_arraycopy_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + + Label L_failed, L_failed_0, L_skip_failed_0, L_objArray; Label L_copy_shorts, L_copy_ints, L_copy_longs; // Input registers @@ -2966,22 +3493,9 @@ address StubGenerator::generate_generic_copy(address byte_copy_entry, address sh const Register rklass_tmp = rdi; // load_klass #endif - { int modulus = CodeEntryAlignment; - int target = modulus - 5; // 5 = sizeof jmp(L_failed) - int advance = target - (__ offset() % modulus); - if (advance < 0) advance += modulus; - if (advance > 0) __ nop(advance); - } - StubId stub_id = StubId::stubgen_generic_arraycopy_id; StubCodeMark mark(this, stub_id); - - // Short-hop target to L_failed. Makes for denser prologue code. - __ BIND(L_failed_0); - __ jmp(L_failed); - assert(__ offset() % CodeEntryAlignment == 0, "no further alignment needed"); - __ align(CodeEntryAlignment); - address start = __ pc(); + start = __ pc(); __ enter(); // required for proper stackwalking of RuntimeStub frame @@ -3022,7 +3536,8 @@ address StubGenerator::generate_generic_copy(address byte_copy_entry, address sh // if (dst_pos < 0) return -1; __ testl(dst_pos, dst_pos); // dst_pos (32-bits) size_t j4off = __ offset(); - __ jccb(Assembler::negative, L_failed_0); + // skip over the failure trampoline + __ jccb(Assembler::positive, L_skip_failed_0); // The first four tests are very dense code, // but not quite dense enough to put four @@ -3032,6 +3547,13 @@ address StubGenerator::generate_generic_copy(address byte_copy_entry, address sh // Make sure of this. guarantee(((j1off ^ j4off) & ~15) != 0, "I$ line of 1st & 4th jumps"); + // Short-hop target to L_failed. Makes for denser prologue code. + __ BIND(L_failed_0); + __ jmp(L_failed); + + // continue here if first 4 checks pass + __ bind(L_skip_failed_0); + // registers used as temp const Register r11_length = r11; // elements count to copy const Register r10_src_klass = r10; // array klass @@ -3254,6 +3776,9 @@ __ BIND(L_failed); __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(0); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_cbrt.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_cbrt.cpp index 73330dedc0f..4c647b7d9dc 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_cbrt.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_cbrt.cpp @@ -191,8 +191,14 @@ ATTRIBUTE_ALIGNED(4) static const juint _D_table[] = address StubGenerator::generate_libmCbrt() { StubId stub_id = StubId::stubgen_dcbrt_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); Label L_2TAG_PACKET_0_0_1, L_2TAG_PACKET_1_0_1, L_2TAG_PACKET_2_0_1; Label B1_1, B1_2, B1_4; @@ -335,7 +341,34 @@ address StubGenerator::generate_libmCbrt() { __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(0); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } #undef __ + +#if INCLUDE_CDS +void StubGenerator::init_AOTAddressTable_cbrt(GrowableArray
& external_addresses) { +#define ADD(addr) external_addresses.append((address)(addr)) + ADD(_ABS_MASK); + ADD(_SIG_MASK); + ADD(_EXP_MASK); + ADD(_EXP_MSK2); + ADD(_EXP_MSK3); + ADD(_SCALE63); + ADD(_ZERON); + ADD(_INF); + ADD(_NEG_INF); + address coeff_table = (address)_coeff_table; + ADD(coeff_table); + ADD(coeff_table + 16); + ADD(coeff_table + 32); + ADD(coeff_table + 48); + ADD(_rcp_table); + ADD(_cbrt_table); + ADD(_D_table); +#undef ADD +} +#endif // INCLUDE_CDS diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_chacha.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_chacha.cpp index 7afaf34e031..1fa51cd2f18 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_chacha.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_chacha.cpp @@ -111,10 +111,16 @@ void StubGenerator::generate_chacha_stubs() { /* The 2-block AVX/AVX2-enabled ChaCha20 block function implementation */ address StubGenerator::generate_chacha20Block_avx() { - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_chacha20Block_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); Label L_twoRounds; const Register state = c_rarg0; @@ -295,15 +301,25 @@ address StubGenerator::generate_chacha20Block_avx() { } __ leave(); __ ret(0); + + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } /* The 4-block AVX512-enabled ChaCha20 block function implementation */ address StubGenerator::generate_chacha20Block_avx512() { - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_chacha20Block_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); Label L_twoRounds; const Register state = c_rarg0; @@ -466,6 +482,10 @@ address StubGenerator::generate_chacha20Block_avx512() { __ vzeroupper(); __ leave(); __ ret(0); + + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -584,3 +604,13 @@ bVec, } #undef __ + +#if INCLUDE_CDS +void StubGenerator::init_AOTAddressTable_chacha(GrowableArray
& external_addresses) { +#define ADD(addr) external_addresses.append((address)(addr)) + ADD(CC20_COUNTER_ADD_AVX); + ADD(CC20_COUNTER_ADD_AVX512); + ADD(CC20_LROT_CONSTS); +#undef ADD +} +#endif // INCLUDE_CDS diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_constants.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_constants.cpp index 93fa7e650db..45c13b7b397 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_constants.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_constants.cpp @@ -233,3 +233,29 @@ ATTRIBUTE_ALIGNED(16) static const juint _Ctable[] = { }; address StubGenerator::Ctable = (address)_Ctable; +#if INCLUDE_CDS +void StubGenerator::init_AOTAddressTable_constants(GrowableArray
& external_addresses) { +#define ADD(addr) external_addresses.append((address)(addr)) + ADD(_ONE); + ADD(_ONEHALF); + ADD(_SIGN_MASK); + ADD(_TWO_POW_55); + ADD(_TWO_POW_M55); + ADD(_SHIFTER); + ADD(_ZERO); + ADD(_SC_1); + ADD(_SC_2); + ADD(_SC_3); + ADD(_SC_4); + ADD(_PI_4); + ADD(((address)_PI_4+8)); + ADD(_PI32INV); + ADD(_NEG_ZERO); + ADD(_P_1); + ADD(_P_2); + ADD(_P_3); + ADD(_PI_INV_TABLE); + ADD(_Ctable); +#undef ADD +} +#endif // INCLUDE_CDS diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_cos.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_cos.cpp index 8cb6ead21fd..8dedd50cd97 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_cos.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_cos.cpp @@ -174,8 +174,14 @@ address StubGenerator::generate_libmCos() { StubId stub_id = StubId::stubgen_dcos_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); Label L_2TAG_PACKET_0_0_1, L_2TAG_PACKET_1_0_1, L_2TAG_PACKET_2_0_1, L_2TAG_PACKET_3_0_1; Label L_2TAG_PACKET_4_0_1, L_2TAG_PACKET_5_0_1, L_2TAG_PACKET_6_0_1, L_2TAG_PACKET_7_0_1; @@ -619,6 +625,9 @@ address StubGenerator::generate_libmCos() { __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(0); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_dilithium.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_dilithium.cpp index b9590939468..de8f52a3c05 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_dilithium.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_dilithium.cpp @@ -401,10 +401,16 @@ static void storeXmms(Register destination, int offset, const XMMRegister xmmReg // static address generate_dilithiumAlmostNtt_avx(StubGenerator *stubgen, int vector_len, MacroAssembler *_masm) { - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_dilithiumAlmostNtt_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = stubgen->load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(stubgen, stub_id); - address start = __ pc(); + start = __ pc(); __ enter(); const Register coeffs = c_rarg0; @@ -646,6 +652,9 @@ static address generate_dilithiumAlmostNtt_avx(StubGenerator *stubgen, __ mov64(rax, 0); // return 0 __ ret(0); + // record the stub entry and end + stubgen->store_archive_data(stub_id, start, __ pc()); + return start; } @@ -657,10 +666,16 @@ static address generate_dilithiumAlmostNtt_avx(StubGenerator *stubgen, // zetas (int[128*8]) = c_rarg1 static address generate_dilithiumAlmostInverseNtt_avx(StubGenerator *stubgen, int vector_len, MacroAssembler *_masm) { - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_dilithiumAlmostInverseNtt_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = stubgen->load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(stubgen, stub_id); - address start = __ pc(); + start = __ pc(); __ enter(); const Register coeffs = c_rarg0; @@ -886,6 +901,9 @@ static address generate_dilithiumAlmostInverseNtt_avx(StubGenerator *stubgen, __ mov64(rax, 0); // return 0 __ ret(0); + // record the stub entry and end + stubgen->store_archive_data(stub_id, start, __ pc()); + return start; } @@ -900,10 +918,16 @@ static address generate_dilithiumAlmostInverseNtt_avx(StubGenerator *stubgen, static address generate_dilithiumNttMult_avx(StubGenerator *stubgen, int vector_len, MacroAssembler *_masm) { - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_dilithiumNttMult_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = stubgen->load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(stubgen, stub_id); - address start = __ pc(); + start = __ pc(); __ enter(); Label L_loop; @@ -972,6 +996,9 @@ static address generate_dilithiumNttMult_avx(StubGenerator *stubgen, __ mov64(rax, 0); // return 0 __ ret(0); + // record the stub entry and end + stubgen->store_archive_data(stub_id, start, __ pc()); + return start; } @@ -984,10 +1011,16 @@ static address generate_dilithiumNttMult_avx(StubGenerator *stubgen, static address generate_dilithiumMontMulByConstant_avx(StubGenerator *stubgen, int vector_len, MacroAssembler *_masm) { - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_dilithiumMontMulByConstant_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = stubgen->load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(stubgen, stub_id); - address start = __ pc(); + start = __ pc(); __ enter(); Label L_loop; @@ -1059,6 +1092,9 @@ static address generate_dilithiumMontMulByConstant_avx(StubGenerator *stubgen, __ mov64(rax, 0); // return 0 __ ret(0); + // record the stub entry and end + stubgen->store_archive_data(stub_id, start, __ pc()); + return start; } @@ -1073,10 +1109,16 @@ static address generate_dilithiumMontMulByConstant_avx(StubGenerator *stubgen, // multiplier (int) = c_rarg4 static address generate_dilithiumDecomposePoly_avx(StubGenerator *stubgen, int vector_len, MacroAssembler *_masm) { - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_dilithiumDecomposePoly_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = stubgen->load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(stubgen, stub_id); - address start = __ pc(); + start = __ pc(); __ enter(); Label L_loop; @@ -1318,6 +1360,9 @@ static address generate_dilithiumDecomposePoly_avx(StubGenerator *stubgen, __ mov64(rax, 0); // return 0 __ ret(0); + // record the stub entry and end + stubgen->store_archive_data(stub_id, start, __ pc()); + return start; } @@ -1340,3 +1385,21 @@ void StubGenerator::generate_dilithium_stubs() { generate_dilithiumDecomposePoly_avx(this, vector_len, _masm); } } + +#if INCLUDE_CDS +void StubGenerator::init_AOTAddressTable_dilithium(GrowableArray
& external_addresses) { +#define ADD(addr) external_addresses.append((address)(addr)) + // use accessors to correctly identify the relevant addresses + ADD(unshufflePermsAddr(0)); + ADD(unshufflePermsAddr(1)); + ADD(unshufflePermsAddr(2)); + ADD(unshufflePermsAddr(3)); + ADD(unshufflePermsAddr(4)); + ADD(unshufflePermsAddr(5)); + ADD(dilithiumAvx512ConstsAddr(montQInvModRIdx)); + ADD(dilithiumAvx512ConstsAddr(dilithium_qIdx)); + ADD(dilithiumAvx512ConstsAddr(montRSquareModQIdx)); + ADD(dilithiumAvx512ConstsAddr(barrettAddendIdx)); +#undef ADD +} +#endif // INCLUDE_CDS diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_exp.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_exp.cpp index 5130fd2c9d2..2ed9858bf0c 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_exp.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_exp.cpp @@ -166,8 +166,14 @@ ATTRIBUTE_ALIGNED(4) static const juint _INF[] = address StubGenerator::generate_libmExp() { StubId stub_id = StubId::stubgen_dexp_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); Label L_2TAG_PACKET_0_0_2, L_2TAG_PACKET_1_0_2, L_2TAG_PACKET_2_0_2, L_2TAG_PACKET_3_0_2; Label L_2TAG_PACKET_4_0_2, L_2TAG_PACKET_5_0_2, L_2TAG_PACKET_6_0_2, L_2TAG_PACKET_7_0_2; @@ -381,7 +387,31 @@ address StubGenerator::generate_libmExp() { __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(0); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } #undef __ + +#if INCLUDE_CDS +void StubGenerator::init_AOTAddressTable_exp(GrowableArray
& external_addresses) { +#define ADD(addr) external_addresses.append((address)addr); + ADD(_cv); + ADD(((address)_cv+16)); + ADD(((address)_cv+32)); + ADD(((address)_cv+48)); + ADD(((address)_cv+64)); + ADD(((address)_cv+80)); + ADD(_mmask); + ADD(_bias); + ADD(_Tbl_addr); + ADD(_ALLONES); + ADD(_ebias); + ADD(_XMAX); + ADD(_XMIN); + ADD(_INF); +#undef ADD +} +#endif // INCLUDE_CDS diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_fmod.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_fmod.cpp index a0962943556..f73c8ed459e 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_fmod.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_fmod.cpp @@ -72,10 +72,16 @@ ATTRIBUTE_ALIGNED(32) static const uint64_t CONST_e307[] = { }; address StubGenerator::generate_libmFmod() { - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_fmod_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); __ enter(); // required for proper stackwalking of RuntimeStub frame if (VM_Version::supports_avx512vlbwdq() && VM_Version::supports_fma()) { // AVX512 version @@ -521,7 +527,22 @@ address StubGenerator::generate_libmFmod() { __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(0); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } #undef __ + +#if INCLUDE_CDS +void StubGenerator::init_AOTAddressTable_fmod(GrowableArray
& external_addresses) { +#define ADD(addr) external_addresses.append((address)addr); + ADD(CONST_NaN); + ADD(CONST_1p260); + ADD(CONST_MAX); + ADD(CONST_INF); + ADD(CONST_e307); +#undef ADD +} +#endif // INCLUDE_CDS diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_ghash.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_ghash.cpp index 6f05b1ab5e6..557fe623351 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_ghash.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_ghash.cpp @@ -80,11 +80,17 @@ void StubGenerator::generate_ghash_stubs() { // Single and multi-block ghash operations. address StubGenerator::generate_ghash_processBlocks() { - __ align(CodeEntryAlignment); - Label L_ghash_loop, L_exit; StubId stub_id = StubId::stubgen_ghash_processBlocks_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + Label L_ghash_loop, L_exit; + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); const Register state = c_rarg0; const Register subkeyH = c_rarg1; @@ -211,17 +217,25 @@ address StubGenerator::generate_ghash_processBlocks() { __ leave(); __ ret(0); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } // Ghash single and multi block operations using AVX instructions address StubGenerator::generate_avx_ghash_processBlocks() { - __ align(CodeEntryAlignment); - StubId stub_id = StubId::stubgen_ghash_processBlocks_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); // arguments const Register state = c_rarg0; @@ -237,6 +251,9 @@ address StubGenerator::generate_avx_ghash_processBlocks() { __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(0); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -538,3 +555,14 @@ void StubGenerator::generateHtbl_eight_blocks(Register htbl) { } #undef __ + +#if INCLUDE_CDS +void StubGenerator::init_AOTAddressTable_ghash(GrowableArray
& external_addresses) { +#define ADD(addr) external_addresses.append((address)addr); + ADD(GHASH_SHUFFLE_MASK); + ADD(GHASH_LONG_SWAP_MASK); + ADD(GHASH_BYTE_SWAP_MASK); + ADD(GHASH_POLYNOMIAL); +#undef ADD +} +#endif // INCLUDE_CDS diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_kyber.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_kyber.cpp index 7d5dee6a5df..347a9b936a8 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_kyber.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_kyber.cpp @@ -400,10 +400,16 @@ static int xmm29_29[] = {29, 29, 29, 29}; // ntt_zetas (short[256]) = c_rarg1 address generate_kyberNtt_avx512(StubGenerator *stubgen, MacroAssembler *_masm) { - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_kyberNtt_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = stubgen->load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(stubgen, stub_id); - address start = __ pc(); + start = __ pc(); __ enter(); const Register coeffs = c_rarg0; @@ -487,6 +493,9 @@ address generate_kyberNtt_avx512(StubGenerator *stubgen, __ mov64(rax, 0); // return 0 __ ret(0); + // record the stub entry and end + stubgen->store_archive_data(stub_id, start, __ pc()); + return start; } @@ -496,11 +505,16 @@ address generate_kyberNtt_avx512(StubGenerator *stubgen, // ntt_zetas (short[256]) = c_rarg1 address generate_kyberInverseNtt_avx512(StubGenerator *stubgen, MacroAssembler *_masm) { - - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_kyberInverseNtt_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = stubgen->load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(stubgen, stub_id); - address start = __ pc(); + start = __ pc(); __ enter(); const Register coeffs = c_rarg0; @@ -610,6 +624,9 @@ address generate_kyberInverseNtt_avx512(StubGenerator *stubgen, __ mov64(rax, 0); // return 0 __ ret(0); + // record the stub entry and end + stubgen->store_archive_data(stub_id, start, __ pc()); + return start; } @@ -621,11 +638,16 @@ address generate_kyberInverseNtt_avx512(StubGenerator *stubgen, // zetas (short[128]) = c_rarg3 address generate_kyberNttMult_avx512(StubGenerator *stubgen, MacroAssembler *_masm) { - - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_kyberNttMult_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = stubgen->load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(stubgen, stub_id); - address start = __ pc(); + start = __ pc(); __ enter(); const Register result = c_rarg0; @@ -731,6 +753,9 @@ address generate_kyberNttMult_avx512(StubGenerator *stubgen, __ mov64(rax, 0); // return 0 __ ret(0); + // record the stub entry and end + stubgen->store_archive_data(stub_id, start, __ pc()); + return start; } @@ -741,11 +766,16 @@ address generate_kyberNttMult_avx512(StubGenerator *stubgen, // b (short[256]) = c_rarg2 address generate_kyberAddPoly_2_avx512(StubGenerator *stubgen, MacroAssembler *_masm) { - - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_kyberAddPoly_2_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = stubgen->load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(stubgen, stub_id); - address start = __ pc(); + start = __ pc(); __ enter(); const Register result = c_rarg0; @@ -776,6 +806,9 @@ address generate_kyberAddPoly_2_avx512(StubGenerator *stubgen, __ mov64(rax, 0); // return 0 __ ret(0); + // record the stub entry and end + stubgen->store_archive_data(stub_id, start, __ pc()); + return start; } @@ -787,11 +820,16 @@ address generate_kyberAddPoly_2_avx512(StubGenerator *stubgen, // c (short[256]) = c_rarg3 address generate_kyberAddPoly_3_avx512(StubGenerator *stubgen, MacroAssembler *_masm) { - - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_kyberAddPoly_3_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = stubgen->load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(stubgen, stub_id); - address start = __ pc(); + start = __ pc(); __ enter(); const Register result = c_rarg0; @@ -830,6 +868,9 @@ address generate_kyberAddPoly_3_avx512(StubGenerator *stubgen, __ mov64(rax, 0); // return 0 __ ret(0); + // record the stub entry and end + stubgen->store_archive_data(stub_id, start, __ pc()); + return start; } @@ -841,11 +882,16 @@ address generate_kyberAddPoly_3_avx512(StubGenerator *stubgen, // parsedLength (int) = c_rarg3 address generate_kyber12To16_avx512(StubGenerator *stubgen, MacroAssembler *_masm) { - - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_kyber12To16_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = stubgen->load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(stubgen, stub_id); - address start = __ pc(); + start = __ pc(); __ enter(); const Register condensed = c_rarg0; @@ -984,6 +1030,9 @@ address generate_kyber12To16_avx512(StubGenerator *stubgen, __ mov64(rax, 0); // return 0 __ ret(0); + // record the stub entry and end + stubgen->store_archive_data(stub_id, start, __ pc()); + return start; } @@ -993,11 +1042,16 @@ address generate_kyber12To16_avx512(StubGenerator *stubgen, // coeffs (short[256]) = c_rarg0 address generate_kyberBarrettReduce_avx512(StubGenerator *stubgen, MacroAssembler *_masm) { - - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_kyberBarrettReduce_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = stubgen->load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(stubgen, stub_id); - address start = __ pc(); + start = __ pc(); __ enter(); const Register coeffs = c_rarg0; @@ -1021,6 +1075,9 @@ address generate_kyberBarrettReduce_avx512(StubGenerator *stubgen, __ mov64(rax, 0); // return 0 __ ret(0); + // record the stub entry and end + stubgen->store_archive_data(stub_id, start, __ pc()); + return start; } @@ -1038,3 +1095,24 @@ void StubGenerator::generate_kyber_stubs() { } } } + +#if INCLUDE_CDS +void StubGenerator::init_AOTAddressTable_kyber(GrowableArray
& external_addresses) { +#define ADD(addr) external_addresses.append((address)(addr)) + // use accessors to correctly identify the relevant addresses + ADD(kyberAvx512NttPermsAddr()); + ADD(kyberAvx512InverseNttPermsAddr()); + ADD(kyberAvx512_nttMultPermsAddr()); + ADD(kyberAvx512_12To16PermsAddr()); + ADD(kyberAvx512_12To16DupAddr()); + ADD(kyberAvx512_12To16ShiftAddr()); + ADD(kyberAvx512_12To16AndAddr()); + ADD(kyberAvx512ConstsAddr(qOffset)); + ADD(kyberAvx512ConstsAddr(qInvModROffset)); + ADD(kyberAvx512ConstsAddr(dimHalfInverseOffset)); + ADD(kyberAvx512ConstsAddr(barretMultiplierOffset)); + ADD(kyberAvx512ConstsAddr(montRSquareModqOffset)); + ADD(kyberAvx512ConstsAddr(f00Offset)); +#undef ADD +} +#endif // INCLUDE_CDS diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_log.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_log.cpp index 6b5b4d704e3..8849597c94b 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_log.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_log.cpp @@ -177,8 +177,14 @@ ATTRIBUTE_ALIGNED(16) static const juint _coeff[] = address StubGenerator::generate_libmLog() { StubId stub_id = StubId::stubgen_dlog_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); Label L_2TAG_PACKET_0_0_2, L_2TAG_PACKET_1_0_2, L_2TAG_PACKET_2_0_2, L_2TAG_PACKET_3_0_2; Label L_2TAG_PACKET_4_0_2, L_2TAG_PACKET_5_0_2, L_2TAG_PACKET_6_0_2, L_2TAG_PACKET_7_0_2; @@ -359,6 +365,9 @@ address StubGenerator::generate_libmLog() { __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(0); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -516,8 +525,14 @@ ATTRIBUTE_ALIGNED(16) static const juint _coeff_log10[] = address StubGenerator::generate_libmLog10() { StubId stub_id = StubId::stubgen_dlog10_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); Label L_2TAG_PACKET_0_0_2, L_2TAG_PACKET_1_0_2, L_2TAG_PACKET_2_0_2, L_2TAG_PACKET_3_0_2; Label L_2TAG_PACKET_4_0_2, L_2TAG_PACKET_5_0_2, L_2TAG_PACKET_6_0_2, L_2TAG_PACKET_7_0_2; @@ -704,7 +719,32 @@ address StubGenerator::generate_libmLog10() { __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(0); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } #undef __ + +#if INCLUDE_CDS +void StubGenerator::init_AOTAddressTable_log(GrowableArray
& external_addresses) { +#define ADD(addr) external_addresses.append((address)addr); + ADD(_L_tbl); + ADD(_log2); + ADD(((address)_log2+8)); + ADD(_coeff); + ADD(((address)_coeff+16)); + ADD(((address)_coeff+32)); + ADD(_HIGHSIGMASK_log10); + ADD(_LOG10_E); + ADD(((address)_LOG10_E+8)); + ADD(_L_tbl_log10); + ADD(_log2_log10); + ADD(((address)_log2_log10+8)); + ADD(_coeff_log10); + ADD(((address)_coeff_log10+16)); + ADD(((address)_coeff_log10+32)); +#undef ADD +} +#endif // INCLUDE_CDS diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_poly1305.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_poly1305.cpp index c80b2d16181..1d0e961c82d 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_poly1305.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_poly1305.cpp @@ -909,10 +909,16 @@ void StubGenerator::poly1305_process_blocks_avx512( // After execution, input and length will point at remaining (unprocessed) data // and accumulator will point to the current accumulator value address StubGenerator::generate_poly1305_processBlocks() { - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_poly1305_processBlocks_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); __ enter(); // Save all 'SOE' registers @@ -1028,6 +1034,10 @@ address StubGenerator::generate_poly1305_processBlocks() { __ leave(); __ ret(0); + + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -1695,3 +1705,14 @@ void StubGenerator::poly1305_msg_mul_reduce_vec4_avx2( __ vpaddq(A1, A1, YTMP2, Assembler::AVX_256bit); //Add medium 42-bit bits from new blocks to accumulator __ vpaddq(A1, A1, YTMP5, Assembler::AVX_256bit); } +#undef __ + +#if INCLUDE_CDS +void StubGenerator::init_AOTAddressTable_poly1305(GrowableArray
& external_addresses) { +#define ADD(addr) external_addresses.append((address)addr); + ADD(POLY1305_PAD_MSG); + ADD(POLY1305_MASK42); + ADD(POLY1305_MASK44); +#undef ADD +} +#endif // INCLUDE_CDS diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_poly_mont.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_poly_mont.cpp index c439e0b370f..4648fe03aa0 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_poly_mont.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_poly_mont.cpp @@ -558,10 +558,16 @@ void montgomeryMultiplyAVX2(const Register aLimbs, const Register bLimbs, const } address StubGenerator::generate_intpoly_montgomeryMult_P256() { - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_intpoly_montgomeryMult_P256_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); __ enter(); if (VM_Version::supports_avx512ifma() && VM_Version::supports_avx512vlbw()) { @@ -620,6 +626,10 @@ address StubGenerator::generate_intpoly_montgomeryMult_P256() { __ leave(); __ ret(0); + + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } @@ -680,10 +690,16 @@ address StubGenerator::generate_intpoly_assign() { // P521OrderField: 19 = 8 + 8 + 2 + 1 // Special Cases 5, 10, 14, 16, 19 - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_intpoly_assign_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); __ enter(); // Inputs @@ -762,5 +778,24 @@ address StubGenerator::generate_intpoly_assign() { __ bind(L_Done); __ leave(); __ ret(0); + + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } +#undef __ + +#if INCLUDE_CDS +void StubGenerator::init_AOTAddressTable_poly_mont(GrowableArray
& external_addresses) { +#define ADD(addr) external_addresses.append((address)addr); + // use accessors to retrieve all correct addresses + ADD(shift_1L()); + ADD(shift_1R()); + ADD(p256_mask52()); + ADD(mask_limb5()); + ADD(modulus_p256()); + ADD(modulus_p256(1)); +#undef ADD +} +#endif // INCLUDE_CDS diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_pow.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_pow.cpp index 3c3df7e6ac4..5ff09e2b377 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_pow.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_pow.cpp @@ -760,8 +760,14 @@ ATTRIBUTE_ALIGNED(8) static const juint _DOUBLE0DOT5[] = { address StubGenerator::generate_libmPow() { StubId stub_id = StubId::stubgen_dpow_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); Label L_2TAG_PACKET_0_0_2, L_2TAG_PACKET_1_0_2, L_2TAG_PACKET_2_0_2, L_2TAG_PACKET_3_0_2; Label L_2TAG_PACKET_4_0_2, L_2TAG_PACKET_5_0_2, L_2TAG_PACKET_6_0_2, L_2TAG_PACKET_7_0_2; @@ -1859,7 +1865,40 @@ address StubGenerator::generate_libmPow() { __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(0); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } #undef __ + +#if INCLUDE_CDS +void StubGenerator::init_AOTAddressTable_pow(GrowableArray
& external_addresses) { +#define ADD(addr) external_addresses.append((address)addr); + ADD(_HIGHSIGMASK); + ADD(_LOG2_E); + ADD(_HIGHMASK_Y); + ADD((address)_HIGHMASK_Y+8); + ADD(_T_exp); + ADD(_e_coeff); + ADD((address)_e_coeff+16); + ADD((address)_e_coeff+32); + ADD(_coeff_h); + ADD((address)_coeff_h+8); + ADD(_HIGHMASK_LOG_X); + ADD(_HALFMASK); + ADD(_coeff_pow); + ADD((address)_coeff_pow+16); + ADD((address)_coeff_pow+32); + ADD((address)_coeff_pow+48); + ADD((address)_coeff_pow+64); + ADD((address)_coeff_pow+80); + ADD(_L_tbl_pow); + ADD(_log2_pow); + ADD(_DOUBLE2); + ADD(_DOUBLE0); + ADD(_DOUBLE0DOT5); +#undef ADD +} +#endif // INCLUDE_CDS diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_sha3.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_sha3.cpp index f9d876f34f3..075d25dcac8 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_sha3.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_sha3.cpp @@ -104,10 +104,15 @@ static address generate_sha3_implCompress(StubId stub_id, default: ShouldNotReachHere(); } - + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = stubgen->load_archive_data(stub_id); + if (start != nullptr) { + return start; + } __ align(CodeEntryAlignment); StubCodeMark mark(stubgen, stub_id); - address start = __ pc(); + start = __ pc(); const Register buf = c_rarg0; const Register state = c_rarg1; @@ -316,6 +321,9 @@ static address generate_sha3_implCompress(StubId stub_id, __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(0); + // record the stub entry and end + stubgen->store_archive_data(stub_id, start, __ pc()); + return start; } @@ -326,10 +334,16 @@ static address generate_sha3_implCompress(StubId stub_id, // Performs two keccak() computations in parallel. The steps of the // two computations are executed interleaved. static address generate_double_keccak(StubGenerator *stubgen, MacroAssembler *_masm) { - __ align(CodeEntryAlignment); StubId stub_id = StubId::stubgen_double_keccak_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = stubgen->load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + __ align(CodeEntryAlignment); StubCodeMark mark(stubgen, stub_id); - address start = __ pc(); + start = __ pc(); const Register state0 = c_rarg0; const Register state1 = c_rarg1; @@ -495,6 +509,9 @@ static address generate_double_keccak(StubGenerator *stubgen, MacroAssembler *_m __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(0); + // record the stub entry and end + stubgen->store_archive_data(stub_id, start, __ pc()); + return start; } @@ -508,3 +525,14 @@ void StubGenerator::generate_sha3_stubs() { generate_sha3_implCompress(StubId::stubgen_sha3_implCompressMB_id, this, _masm); } } + +#undef __ + +#if INCLUDE_CDS +void StubGenerator::init_AOTAddressTable_sha3(GrowableArray
& external_addresses) { +#define ADD(addr) external_addresses.append((address)addr); + ADD(round_constsAddr()); + ADD(permsAndRotsAddr()); +#undef ADD +} +#endif // INCLUDE_CDS diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_sin.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_sin.cpp index 5290e737581..eaeaea2c566 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_sin.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_sin.cpp @@ -181,8 +181,14 @@ ATTRIBUTE_ALIGNED(8) static const juint _ALL_ONES[] = address StubGenerator::generate_libmSin() { StubId stub_id = StubId::stubgen_dsin_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); Label L_2TAG_PACKET_0_0_1, L_2TAG_PACKET_1_0_1, L_2TAG_PACKET_2_0_1, L_2TAG_PACKET_3_0_1; Label L_2TAG_PACKET_4_0_1, L_2TAG_PACKET_5_0_1, L_2TAG_PACKET_6_0_1, L_2TAG_PACKET_7_0_1; @@ -645,7 +651,18 @@ address StubGenerator::generate_libmSin() { __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(0); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } #undef __ + +#if INCLUDE_CDS +void StubGenerator::init_AOTAddressTable_sin(GrowableArray
& external_addresses) { +#define ADD(addr) external_addresses.append((address)addr); + ADD(_ALL_ONES); +#undef ADD +} +#endif // INCLUDE_CDS diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_sinh.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_sinh.cpp index 86e4ac20176..f6e1d241948 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_sinh.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_sinh.cpp @@ -290,8 +290,14 @@ ATTRIBUTE_ALIGNED(16) static const juint _T2_neg_f[] = address StubGenerator::generate_libmSinh() { StubId stub_id = StubId::stubgen_dsinh_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); Label L_2TAG_PACKET_0_0_2, L_2TAG_PACKET_1_0_2, L_2TAG_PACKET_3_0_2, L_2TAG_PACKET_4_0_2; Label L_2TAG_PACKET_5_0_2, L_2TAG_PACKET_6_0_2; @@ -519,7 +525,32 @@ address StubGenerator::generate_libmSinh() { __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(0); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } #undef __ + +#if INCLUDE_CDS +void StubGenerator::init_AOTAddressTable_sinh(GrowableArray
& external_addresses) { +#define ADD(addr) external_addresses.append((address)addr); + ADD(_L2E); + ADD(_L2E + 8); + ADD(_HALFMASK); + ADD(_Shifter); + ADD(_cv); + ADD(_cv + 16); + ADD(_cv + 32); + ADD(_cv + 48); + ADD(_cv + 64); + ADD(_T2f); + ADD(_T2_neg_f); + ADD(_pv); + ADD(_pv + 16); + ADD(_pv + 32); + ADD(_MASK3); +#undef ADD +} +#endif // INCLUDE_CDS diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_tan.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_tan.cpp index 4f14414652c..3bfa5a7277f 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_tan.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_tan.cpp @@ -456,8 +456,14 @@ ATTRIBUTE_ALIGNED(8) static const juint _QQ_2_tan[] = address StubGenerator::generate_libmTan() { StubId stub_id = StubId::stubgen_dtan_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); Label L_2TAG_PACKET_0_0_1, L_2TAG_PACKET_1_0_1, L_2TAG_PACKET_2_0_1, L_2TAG_PACKET_3_0_1; Label L_2TAG_PACKET_4_0_1, L_2TAG_PACKET_5_0_1, L_2TAG_PACKET_6_0_1, L_2TAG_PACKET_7_0_1; @@ -1025,7 +1031,33 @@ address StubGenerator::generate_libmTan() { __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(0); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } #undef __ + +#if INCLUDE_CDS +void StubGenerator::init_AOTAddressTable_tan(GrowableArray
& external_addresses) { +#define ADD(addr) external_addresses.append((address)addr); + ADD(_MUL16); + ADD(_sign_mask_tan); + ADD(_PI32INV_tan); + ADD(_P_1_tan); + ADD(_P_2_tan); + ADD(_P_3_tan); + ADD(_Ctable_tan); + ADD(_MASK_35_tan); + ADD(_Q_11_tan); + ADD(_Q_9_tan); + ADD(_Q_7_tan); + ADD(_Q_5_tan); + ADD(_Q_3_tan); + ADD(_PI_4_tan); + ADD(((address)_PI_4_tan+8)); + ADD(_QQ_2_tan); +#undef ADD +} +#endif // INCLUDE_CDS diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_tanh.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_tanh.cpp index dce4fbfc455..dcf5f3eb824 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_tanh.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_tanh.cpp @@ -303,8 +303,14 @@ ATTRIBUTE_ALIGNED(16) static const juint _T2_neg_f[] = address StubGenerator::generate_libmTanh() { StubId stub_id = StubId::stubgen_dtanh_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } StubCodeMark mark(this, stub_id); - address start = __ pc(); + start = __ pc(); Label L_2TAG_PACKET_0_0_1, L_2TAG_PACKET_1_0_1, L_2TAG_PACKET_2_0_1, L_2TAG_PACKET_3_0_1; Label L_2TAG_PACKET_4_0_1, L_2TAG_PACKET_5_0_1; @@ -495,7 +501,32 @@ address StubGenerator::generate_libmTanh() { __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(0); + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + return start; } #undef __ + +#if INCLUDE_CDS +void StubGenerator::init_AOTAddressTable_tanh(GrowableArray
& external_addresses) { +#define ADD(addr) external_addresses.append((address)addr); + ADD(_L2E); + ADD(_L2E + 8); + ADD(_HALFMASK); + ADD(_ONEMASK); + ADD(_TWOMASK); + ADD(_Shifter); + ADD(_cv); + ADD(_cv + 16); + ADD(_cv + 32); + ADD(_T2_neg_f); + ADD(_pv); + ADD(_pv + 16); + ADD(_pv + 32); + ADD(_MASK3); + ADD(_RMASK); +#undef ADD +} +#endif // INCLUDE_CDS diff --git a/src/hotspot/cpu/x86/stubRoutines_x86.cpp b/src/hotspot/cpu/x86/stubRoutines_x86.cpp index ee9cea08e64..8696180c512 100644 --- a/src/hotspot/cpu/x86/stubRoutines_x86.cpp +++ b/src/hotspot/cpu/x86/stubRoutines_x86.cpp @@ -28,6 +28,10 @@ #include "runtime/stubRoutines.hpp" #include "utilities/globalDefinitions.hpp" #include "crc32c.h" +#include "stubGenerator_x86_64.hpp" +#ifdef COMPILER1 +#include "c1/c1_LIRAssembler.hpp" +#endif // Implementation of the platform-specific part of StubRoutines - for // a description of how to extend it, see the stubRoutines.hpp file. @@ -411,3 +415,46 @@ ATTRIBUTE_ALIGNED(64) const julong StubRoutines::x86::_k512_W[] = 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL, }; + +#if INCLUDE_CDS + +void StubRoutines::init_AOTAddressTable() { + ResourceMark rm; + GrowableArray
external_addresses; + // publish static addresses referred to by main x86 generator and + // auxiliary x86 generators + StubGenerator::init_AOTAddressTable(external_addresses); + // publish external data addresses defined in nested x86 class + StubRoutines::x86::init_AOTAddressTable(external_addresses); +#ifdef COMPILER1 + LIR_Assembler::init_AOTAddressTable(external_addresses); +#endif + AOTCodeCache::publish_external_addresses(external_addresses); +} + +// publish addresses of external data defined in this file which may +// be referenced from stub or code +void StubRoutines::x86::init_AOTAddressTable(GrowableArray
& external_addresses) { +#define ADD(addr) external_addresses.append((address)addr); + ADD(&_mxcsr_std); + ADD(&_mxcsr_rz); + ADD(crc_by128_masks_addr()); + ADD(crc_by128_masks_addr() + 16); + ADD(crc_by128_masks_addr() + 32); + // this is added in generic code + // ADD(_crc_table); + ADD(crc_by128_masks_avx512_addr()); + ADD(crc_by128_masks_avx512_addr() + 16); + ADD(crc_by128_masks_avx512_addr() + 32); + ADD(_crc_table_avx512); + ADD(_crc32c_table_avx512); + ADD(_shuf_table_crc32_avx512); + // n.b. call accessor for this one to ensure the table is generated + ADD(crc32c_table_addr()); + ADD(_arrays_hashcode_powers_of_31); + ADD(_k256); + ADD(_k256_W); + ADD(_k512_W); +#undef ADD +} +#endif // INCLUDE_CDS diff --git a/src/hotspot/cpu/x86/stubRoutines_x86.hpp b/src/hotspot/cpu/x86/stubRoutines_x86.hpp index 3654b644131..3c6d75c1d4e 100644 --- a/src/hotspot/cpu/x86/stubRoutines_x86.hpp +++ b/src/hotspot/cpu/x86/stubRoutines_x86.hpp @@ -112,6 +112,8 @@ public: static address arrays_hashcode_powers_of_31() { return (address)_arrays_hashcode_powers_of_31; } static void generate_CRC32C_table(bool is_pclmulqdq_supported); + + static void init_AOTAddressTable(GrowableArray
& external_addresses); }; #endif // CPU_X86_STUBROUTINES_X86_HPP diff --git a/src/hotspot/cpu/zero/stubGenerator_zero.cpp b/src/hotspot/cpu/zero/stubGenerator_zero.cpp index 08cb173b507..569a2fa8ca9 100644 --- a/src/hotspot/cpu/zero/stubGenerator_zero.cpp +++ b/src/hotspot/cpu/zero/stubGenerator_zero.cpp @@ -213,7 +213,7 @@ class StubGenerator: public StubCodeGenerator { } public: - StubGenerator(CodeBuffer* code, BlobId blob_id) : StubCodeGenerator(code, blob_id) { + StubGenerator(CodeBuffer* code, BlobId blob_id, AOTStubData *stub_data) : StubCodeGenerator(code, blob_id, stub_data) { switch(blob_id) { case BlobId::stubgen_preuniverse_id: generate_preuniverse_stubs(); @@ -237,8 +237,8 @@ class StubGenerator: public StubCodeGenerator { } }; -void StubGenerator_generate(CodeBuffer* code, BlobId blob_id) { - StubGenerator g(code, blob_id); +void StubGenerator_generate(CodeBuffer* code, BlobId blob_id, AOTStubData *stub_data) { + StubGenerator g(code, blob_id, stub_data); } EntryFrame *EntryFrame::build(const intptr_t* parameters, diff --git a/src/hotspot/cpu/zero/stubRoutines_zero.cpp b/src/hotspot/cpu/zero/stubRoutines_zero.cpp index 9b53f09be5d..196907b061f 100644 --- a/src/hotspot/cpu/zero/stubRoutines_zero.cpp +++ b/src/hotspot/cpu/zero/stubRoutines_zero.cpp @@ -30,3 +30,9 @@ address StubRoutines::crc_table_addr() { ShouldNotCallThis(); return nullptr; } address StubRoutines::crc32c_table_addr() { ShouldNotCallThis(); return nullptr; } + +#if INCLUDE_CDS +// nothing to do for zero +void StubRoutines::init_AOTAddressTable() { +} +#endif // INCLUDE_CDS diff --git a/src/hotspot/share/asm/codeBuffer.cpp b/src/hotspot/share/asm/codeBuffer.cpp index c6078c0ceee..6a288e0dad0 100644 --- a/src/hotspot/share/asm/codeBuffer.cpp +++ b/src/hotspot/share/asm/codeBuffer.cpp @@ -1136,7 +1136,7 @@ void AsmRemarks::clear() { uint AsmRemarks::print(uint offset, outputStream* strm) const { uint count = 0; const char* prefix = " ;; "; - const char* remstr = _remarks->lookup(offset); + const char* remstr = (_remarks ? _remarks->lookup(offset) : nullptr); while (remstr != nullptr) { strm->bol(); strm->print("%s", prefix); diff --git a/src/hotspot/share/c1/c1_Runtime1.cpp b/src/hotspot/share/c1/c1_Runtime1.cpp index 63764dd113a..38f563935e0 100644 --- a/src/hotspot/share/c1/c1_Runtime1.cpp +++ b/src/hotspot/share/c1/c1_Runtime1.cpp @@ -278,11 +278,9 @@ bool Runtime1::initialize(BufferBlob* blob) { if (!generate_blob_for(blob, id)) { return false; } - if (id == StubId::c1_forward_exception_id) { - // publish early c1 stubs at this point so later stubs can refer to them - AOTCodeCache::init_early_c1_table(); - } } + // disallow any further c1 stub generation + AOTCodeCache::set_c1_stubs_complete(); // printing #ifndef PRODUCT if (PrintSimpleStubs) { diff --git a/src/hotspot/share/code/aotCodeCache.cpp b/src/hotspot/share/code/aotCodeCache.cpp index e3cbc3c3c8b..d3888d1b7eb 100644 --- a/src/hotspot/share/code/aotCodeCache.cpp +++ b/src/hotspot/share/code/aotCodeCache.cpp @@ -33,13 +33,18 @@ #include "classfile/javaAssertions.hpp" #include "code/aotCodeCache.hpp" #include "code/codeCache.hpp" +#include "gc/shared/barrierSetAssembler.hpp" +#include "gc/shared/barrierSetNMethod.hpp" #include "gc/shared/cardTableBarrierSet.hpp" #include "gc/shared/gcConfig.hpp" #include "logging/logStream.hpp" #include "memory/memoryReserver.hpp" +#include "prims/jvmtiThreadState.hpp" +#include "prims/upcallLinker.hpp" #include "runtime/deoptimization.hpp" #include "runtime/flags/flagSetting.hpp" #include "runtime/globals_extension.hpp" +#include "runtime/icache.hpp" #include "runtime/java.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/os.inline.hpp" @@ -168,10 +173,13 @@ static uint32_t encode_id(AOTCodeEntry::Kind kind, int id) { } else if (kind == AOTCodeEntry::C1Blob) { assert(StubInfo::is_c1(static_cast(id)), "not a c1 blob id %d", id); return id; - } else { - // kind must be AOTCodeEntry::C2Blob + } else if (kind == AOTCodeEntry::C2Blob) { assert(StubInfo::is_c2(static_cast(id)), "not a c2 blob id %d", id); return id; + } else { + // kind must be AOTCodeEntry::StubGenBlob + assert(StubInfo::is_stubgen(static_cast(id)), "not a stubgen blob id %d", id); + return id; } } @@ -196,9 +204,6 @@ void AOTCodeCache::initialize() { return; // AOTCache must be specified to dump and use AOT code } - // Disable stubs caching until JDK-8357398 is fixed. - FLAG_SET_ERGO(AOTStubCaching, false); - if (VerifyOops) { // Disable AOT stubs caching when VerifyOops flag is on. // Verify oops code generated a lot of C strings which overflow @@ -296,6 +301,19 @@ bool AOTCodeCache::open_cache(bool is_dumping, bool is_using) { return true; } +// Called after continuations_init() when continuation stub callouts +// have been initialized +void AOTCodeCache::init3() { + if (opened_cache == nullptr) { + return; + } + // initialize external routines for continuations so we can save + // generated continuation blob that references them + AOTCodeAddressTable* table = opened_cache->_table; + assert(table != nullptr, "should be initialized already"); + table->init_extrs2(); +} + void AOTCodeCache::dump() { if (is_on()) { assert(is_on_for_dump(), "should be called only when dumping AOT code"); @@ -354,6 +372,7 @@ AOTCodeCache::AOTCodeCache(bool is_dumping, bool is_using) : log_info (aot, codecache, init)("Loaded %u AOT code entries from AOT Code Cache", _load_header->entries_count()); log_debug(aot, codecache, init)(" Adapters: total=%u", _load_header->adapters_count()); log_debug(aot, codecache, init)(" Shared Blobs: total=%u", _load_header->shared_blobs_count()); + log_debug(aot, codecache, init)(" StubGen Blobs: total=%d", _load_header->stubgen_blobs_count()); log_debug(aot, codecache, init)(" C1 Blobs: total=%u", _load_header->C1_blobs_count()); log_debug(aot, codecache, init)(" C2 Blobs: total=%u", _load_header->C2_blobs_count()); log_debug(aot, codecache, init)(" AOT code cache size: %u bytes", _load_header->cache_size()); @@ -371,24 +390,59 @@ AOTCodeCache::AOTCodeCache(bool is_dumping, bool is_using) : _table = new AOTCodeAddressTable(); } -void AOTCodeCache::init_early_stubs_table() { - AOTCodeAddressTable* table = addr_table(); - if (table != nullptr) { - table->init_early_stubs(); +void AOTCodeCache::add_stub_entries(StubId stub_id, address start, GrowableArray
*entries, int begin_idx) { + EntryId entry_id = StubInfo::entry_base(stub_id); + add_stub_entry(entry_id, start); + // skip past first entry + entry_id = StubInfo::next_in_stub(stub_id, entry_id); + // now check for any more entries + int count = StubInfo::entry_count(stub_id) - 1; + assert(start != nullptr, "invalid start address for stub %s", StubInfo::name(stub_id)); + assert(entries == nullptr || begin_idx + count <= entries->length(), "sanity"); + // write any extra entries + for (int i = 0; i < count; i++) { + assert(entry_id != EntryId::NO_ENTRYID, "not enough entries for stub %s", StubInfo::name(stub_id)); + address a = entries->at(begin_idx + i); + add_stub_entry(entry_id, a); + entry_id = StubInfo::next_in_stub(stub_id, entry_id); + } + assert(entry_id == EntryId::NO_ENTRYID, "too many entries for stub %s", StubInfo::name(stub_id)); +} + +void AOTCodeCache::add_stub_entry(EntryId entry_id, address a) { + if (a != nullptr) { + if (_table != nullptr) { + log_trace(aot, codecache, stubs)("Publishing stub entry %s at address " INTPTR_FORMAT, StubInfo::name(entry_id), p2i(a)); + return _table->add_stub_entry(entry_id, a); + } } } -void AOTCodeCache::init_shared_blobs_table() { +void AOTCodeCache::set_shared_stubs_complete() { AOTCodeAddressTable* table = addr_table(); if (table != nullptr) { - table->init_shared_blobs(); + table->set_shared_stubs_complete(); } } -void AOTCodeCache::init_early_c1_table() { +void AOTCodeCache::set_c1_stubs_complete() { AOTCodeAddressTable* table = addr_table(); if (table != nullptr) { - table->init_early_c1(); + table->set_c1_stubs_complete(); + } +} + +void AOTCodeCache::set_c2_stubs_complete() { + AOTCodeAddressTable* table = addr_table(); + if (table != nullptr) { + table->set_c2_stubs_complete(); + } +} + +void AOTCodeCache::set_stubgen_stubs_complete() { + AOTCodeAddressTable* table = addr_table(); + if (table != nullptr) { + table->set_stubgen_stubs_complete(); } } @@ -583,7 +637,11 @@ AOTCodeReader::AOTCodeReader(AOTCodeCache* cache, AOTCodeEntry* entry) { _lookup_failed = false; _name = nullptr; _reloc_data = nullptr; + _reloc_count = 0; _oop_maps = nullptr; + _entry_kind = AOTCodeEntry::None; + _stub_data = nullptr; + _id = -1; } void AOTCodeReader::set_read_position(uint pos) { @@ -801,6 +859,7 @@ bool AOTCodeCache::finish_write() { AOTCodeEntry* entries_address = _store_entries; // Pointer to latest entry uint adapters_count = 0; uint shared_blobs_count = 0; + uint stubgen_blobs_count = 0; uint C1_blobs_count = 0; uint C2_blobs_count = 0; uint max_size = 0; @@ -828,6 +887,8 @@ bool AOTCodeCache::finish_write() { adapters_count++; } else if (kind == AOTCodeEntry::SharedBlob) { shared_blobs_count++; + } else if (kind == AOTCodeEntry::StubGenBlob) { + stubgen_blobs_count++; } else if (kind == AOTCodeEntry::C1Blob) { C1_blobs_count++; } else if (kind == AOTCodeEntry::C2Blob) { @@ -864,6 +925,7 @@ bool AOTCodeCache::finish_write() { log_debug(aot, codecache, exit)(" Adapters: total=%u", adapters_count); log_debug(aot, codecache, exit)(" Shared Blobs: total=%d", shared_blobs_count); + log_debug(aot, codecache, exit)(" StubGen Blobs: total=%d", stubgen_blobs_count); log_debug(aot, codecache, exit)(" C1 Blobs: total=%d", C1_blobs_count); log_debug(aot, codecache, exit)(" C2 Blobs: total=%d", C2_blobs_count); log_debug(aot, codecache, exit)(" AOT code cache size: %u bytes, max entry's size: %u bytes", size, max_size); @@ -873,7 +935,8 @@ bool AOTCodeCache::finish_write() { header->init(size, (uint)strings_count, strings_offset, entries_count, new_entries_offset, adapters_count, shared_blobs_count, - C1_blobs_count, C2_blobs_count, cpu_features_offset); + stubgen_blobs_count, C1_blobs_count, + C2_blobs_count, cpu_features_offset); log_info(aot, codecache, exit)("Wrote %d AOT code entries to AOT Code Cache", entries_count); } @@ -882,19 +945,53 @@ bool AOTCodeCache::finish_write() { //------------------Store/Load AOT code ---------------------- -bool AOTCodeCache::store_code_blob(CodeBlob& blob, AOTCodeEntry::Kind entry_kind, uint id, const char* name) { +bool AOTCodeCache::store_code_blob(CodeBlob& blob, AOTCodeEntry::Kind entry_kind, uint id, const char* name, AOTStubData* stub_data, CodeBuffer* code_buffer) { + assert(AOTCodeEntry::is_valid_entry_kind(entry_kind), "invalid entry_kind %d", entry_kind); + + // we only expect stub data and a code buffer for a multi stub blob + assert(AOTCodeEntry::is_multi_stub_blob(entry_kind) == (stub_data != nullptr), + "entry_kind %d does not match stub_data pointer %p", + entry_kind, stub_data); + + assert((stub_data == nullptr) == (code_buffer == nullptr), + "stub data and code buffer must both be null or both non null"); + + // If this is a stub and the cache is on for either load or dump we + // need to insert the stub entries into the AOTCacheAddressTable so + // that relocs which refer to entries defined by this blob get + // translated correctly. + // + // Entry insertion needs to be be done up front before writing the + // blob because some blobs rely on internal daisy-chain references + // from one entry to another. + // + // Entry insertion also needs to be done even if the cache is open + // for use but not for dump. This may be needed when an archived + // blob omits some entries -- either because of a config change or a + // load failure -- with the result that the entries end up being + // generated. These generated entry addresses may be needed to + // resolve references from subsequently loaded blobs (for either + // stubs or nmethods). + + if (is_on() && AOTCodeEntry::is_blob(entry_kind)) { + publish_stub_addresses(blob, (BlobId)id, stub_data); + } + AOTCodeCache* cache = open_for_dump(); if (cache == nullptr) { return false; } - assert(AOTCodeEntry::is_valid_entry_kind(entry_kind), "invalid entry_kind %d", entry_kind); - if (AOTCodeEntry::is_adapter(entry_kind) && !is_dumping_adapter()) { return false; } if (AOTCodeEntry::is_blob(entry_kind) && !is_dumping_stub()) { return false; } + // we do not currently store C2 stubs because we are seeing weird + // memory errors when loading them -- see JDK-8357593 + if (entry_kind == AOTCodeEntry::C2Blob) { + return false; + } log_debug(aot, codecache, stubs)("Writing blob '%s' (id=%u, kind=%s) to AOT Code Cache", name, id, aot_code_entry_kind_name[entry_kind]); #ifdef ASSERT @@ -934,8 +1031,44 @@ bool AOTCodeCache::store_code_blob(CodeBlob& blob, AOTCodeEntry::Kind entry_kind } CodeBlob::archive_blob(&blob, archive_buffer); - uint reloc_data_size = blob.relocation_size(); - n = cache->write_bytes((address)blob.relocation_begin(), reloc_data_size); + // For a relocatable code blob its relocations are linked from the + // blob. However, for a non-relocatable (stubgen) blob we only have + // transient relocations attached to the code buffer that are added + // in order to support AOT-load time patching. in either case, we + // need to explicitly save these relocs when storing the blob to the + // archive so we can then reload them and reattach them to either + // the blob or to a code buffer when we reload the blob into a + // production JVM. + // + // Either way we are then in a position to iterate over the relocs + // and AOT patch the ones that refer to code that may move between + // assembly and production time. We also need to save and restore + // AOT address table indexes for the target addresses of affected + // relocs. That happens below. + + int reloc_count; + address reloc_data; + if (AOTCodeEntry::is_multi_stub_blob(entry_kind)) { + CodeSection* cs = code_buffer->code_section(CodeBuffer::SECT_INSTS); + reloc_count = (cs->has_locs() ? cs->locs_count() : 0); + reloc_data = (reloc_count > 0 ? (address)cs->locs_start() : nullptr); + } else { + reloc_count = blob.relocation_size() / sizeof(relocInfo); + reloc_data = (address)blob.relocation_begin(); + } + n = cache->write_bytes(&reloc_count, sizeof(int)); + if (n != sizeof(int)) { + return false; + } + if (AOTCodeEntry::is_multi_stub_blob(entry_kind)) { + // align to heap word size before writing the relocs so we can + // install them into a code buffer when they get restored + if (!cache->align_write()) { + return false; + } + } + uint reloc_data_size = (uint)(reloc_count * sizeof(relocInfo)); + n = cache->write_bytes(reloc_data, reloc_data_size); if (n != reloc_data_size) { return false; } @@ -948,7 +1081,29 @@ bool AOTCodeCache::store_code_blob(CodeBlob& blob, AOTCodeEntry::Kind entry_kind has_oop_maps = true; } - if (!cache->write_relocations(blob)) { + // In the case of a multi-stub blob we need to write start, end, + // secondary entries and extras. For any other blob entry addresses + // beyond the blob start will be stored in the blob as offsets. + if (stub_data != nullptr) { + if (!cache->write_stub_data(blob, stub_data)) { + return false; + } + } + + // now we have added all the other data we can write details of any + // extra the AOT relocations + + bool write_ok; + if (AOTCodeEntry::is_multi_stub_blob(entry_kind)) { + CodeSection* cs = code_buffer->code_section(CodeBuffer::SECT_INSTS); + RelocIterator iter(cs); + write_ok = cache->write_relocations(blob, iter); + } else { + RelocIterator iter(&blob); + write_ok = cache->write_relocations(blob, iter); + } + + if (!write_ok) { if (!cache->failed()) { // We may miss an address in AOT table - skip this code blob. cache->set_write_position(entry_position); @@ -967,6 +1122,7 @@ bool AOTCodeCache::store_code_blob(CodeBlob& blob, AOTCodeEntry::Kind entry_kind #endif /* PRODUCT */ uint entry_size = cache->_write_position - entry_position; + AOTCodeEntry* entry = new(cache) AOTCodeEntry(entry_kind, encode_id(entry_kind, id), entry_position, entry_size, name_offset, name_size, blob_offset, has_oop_maps, blob.content_begin()); @@ -974,25 +1130,141 @@ bool AOTCodeCache::store_code_blob(CodeBlob& blob, AOTCodeEntry::Kind entry_kind return true; } -bool AOTCodeCache::store_code_blob(CodeBlob& blob, AOTCodeEntry::Kind entry_kind, BlobId id) { - assert(AOTCodeEntry::is_blob(entry_kind), - "wrong entry kind for blob id %s", StubInfo::name(id)); - return store_code_blob(blob, entry_kind, (uint)id, StubInfo::name(id)); +bool AOTCodeCache::store_code_blob(CodeBlob& blob, AOTCodeEntry::Kind entry_kind, uint id, const char* name) { + assert(!AOTCodeEntry::is_blob(entry_kind), + "wrong entry kind for numeric id %d", id); + return store_code_blob(blob, entry_kind, (uint)id, name, nullptr, nullptr); } -CodeBlob* AOTCodeCache::load_code_blob(AOTCodeEntry::Kind entry_kind, uint id, const char* name) { +bool AOTCodeCache::store_code_blob(CodeBlob& blob, AOTCodeEntry::Kind entry_kind, BlobId id) { + assert(AOTCodeEntry::is_single_stub_blob(entry_kind), + "wrong entry kind for blob id %s", StubInfo::name(id)); + return store_code_blob(blob, entry_kind, (uint)id, StubInfo::name(id), nullptr, nullptr); +} + +bool AOTCodeCache::store_code_blob(CodeBlob& blob, AOTCodeEntry::Kind entry_kind, BlobId id, AOTStubData* stub_data, CodeBuffer* code_buffer) { + assert(AOTCodeEntry::is_multi_stub_blob(entry_kind), + "wrong entry kind for multi stub blob id %s", StubInfo::name(id)); + return store_code_blob(blob, entry_kind, (uint)id, StubInfo::name(id), stub_data, code_buffer); +} + +bool AOTCodeCache::write_stub_data(CodeBlob &blob, AOTStubData *stub_data) { + BlobId blob_id = stub_data->blob_id(); + StubId stub_id = StubInfo::stub_base(blob_id); + address blob_base = blob.code_begin(); + int stub_cnt = StubInfo::stub_count(blob_id); + int n; + + LogStreamHandle(Trace, aot, codecache, stubs) log; + + if (log.is_enabled()) { + log.print_cr("======== Stub data starts at offset %d", _write_position); + } + + for (int i = 0; i < stub_cnt; i++, stub_id = StubInfo::next_in_blob(blob_id, stub_id)) { + // for each stub we find in the ranges list we write an int + // sequence where + // + // - start_pos is the stub start address encoded as a code section offset + // + // - end is the stub end address encoded as an offset from start + // + // - N counts the number of stub-local entries/extras + // + // - offseti is a stub-local entry/extra address encoded as len for + // a null address otherwise as an offset in range [1,len-1] + + StubAddrRange& range = stub_data->get_range(i); + GrowableArray
& addresses = stub_data->address_array(); + int base = range.start_index(); + if (base >= 0) { + n = write_bytes(&stub_id, sizeof(StubId)); + if (n != sizeof(StubId)) { + return false; + } + address start = addresses.at(base); + assert (blob_base <= start, "sanity"); + uint offset = (uint)(start - blob_base); + n = write_bytes(&offset, sizeof(uint)); + if (n != sizeof(int)) { + return false; + } + address end = addresses.at(base + 1); + assert (start < end, "sanity"); + offset = (uint)(end - start); + n = write_bytes(&offset, sizeof(uint)); + if (n != sizeof(int)) { + return false; + } + // write number of secondary and extra entries + int count = range.count() - 2; + n = write_bytes(&count, sizeof(int)); + if (n != sizeof(int)) { + return false; + } + for (int j = 0; j < count; j++) { + address next = addresses.at(base + 2 + j); + if (next != nullptr) { + // n.b. This maps next == end to the stub length which + // means we will reconstitute the address as nullptr. That + // happens when we have a handler range covers the end of + // a stub and needs to be handled specially by the client + // that restores the extras. + assert(start <= next && next <= end, "sanity"); + offset = (uint)(next - start); + } else { + // this can happen when a stub is not generated or an + // extra is the common handler target + offset = NULL_ADDRESS_MARKER; + } + n = write_bytes(&offset, sizeof(uint)); + if (n != sizeof(int)) { + return false; + } + } + if (log.is_enabled()) { + log.print_cr("======== wrote stub %s and %d addresses up to offset %d", + StubInfo::name(stub_id), range.count(), _write_position); + } + } + } + // we should have exhausted all stub ids in the blob + assert(stub_id == StubId::NO_STUBID, "sanity"); + // write NO_STUBID as an end marker + n = write_bytes(&stub_id, sizeof(StubId)); + if (n != sizeof(StubId)) { + return false; + } + + if (log.is_enabled()) { + log.print_cr("======== Stub data ends at offset %d", _write_position); + } + + return true; +} + +CodeBlob* AOTCodeCache::load_code_blob(AOTCodeEntry::Kind entry_kind, uint id, const char* name, AOTStubData* stub_data) { AOTCodeCache* cache = open_for_use(); if (cache == nullptr) { return nullptr; } assert(AOTCodeEntry::is_valid_entry_kind(entry_kind), "invalid entry_kind %d", entry_kind); + assert(AOTCodeEntry::is_multi_stub_blob(entry_kind) == (stub_data != nullptr), + "entry_kind %d does not match stub_data pointer %p", + entry_kind, stub_data); + if (AOTCodeEntry::is_adapter(entry_kind) && !is_using_adapter()) { return nullptr; } if (AOTCodeEntry::is_blob(entry_kind) && !is_using_stub()) { return nullptr; } + // we do not currently load C2 stubs because we are seeing weird + // memory errors when loading them -- see JDK-8357593 + if (entry_kind == AOTCodeEntry::C2Blob) { + return nullptr; + } log_debug(aot, codecache, stubs)("Reading blob '%s' (id=%u, kind=%s) from AOT Code Cache", name, id, aot_code_entry_kind_name[entry_kind]); AOTCodeEntry* entry = cache->find_entry(entry_kind, encode_id(entry_kind, id)); @@ -1000,20 +1272,32 @@ CodeBlob* AOTCodeCache::load_code_blob(AOTCodeEntry::Kind entry_kind, uint id, c return nullptr; } AOTCodeReader reader(cache, entry); - CodeBlob* blob = reader.compile_code_blob(name); + CodeBlob* blob = reader.compile_code_blob(name, entry_kind, id, stub_data); log_debug(aot, codecache, stubs)("%sRead blob '%s' (id=%u, kind=%s) from AOT Code Cache", (blob == nullptr? "Failed to " : ""), name, id, aot_code_entry_kind_name[entry_kind]); return blob; } -CodeBlob* AOTCodeCache::load_code_blob(AOTCodeEntry::Kind entry_kind, BlobId id) { - assert(AOTCodeEntry::is_blob(entry_kind), - "wrong entry kind for blob id %s", StubInfo::name(id)); - return load_code_blob(entry_kind, (uint)id, StubInfo::name(id)); +CodeBlob* AOTCodeCache::load_code_blob(AOTCodeEntry::Kind entry_kind, uint id, const char* name) { + assert(!AOTCodeEntry::is_blob(entry_kind), + "wrong entry kind for numeric id %d", id); + return load_code_blob(entry_kind, (uint)id, name, nullptr); } -CodeBlob* AOTCodeReader::compile_code_blob(const char* name) { +CodeBlob* AOTCodeCache::load_code_blob(AOTCodeEntry::Kind entry_kind, BlobId id) { + assert(AOTCodeEntry::is_single_stub_blob(entry_kind), + "wrong entry kind for blob id %s", StubInfo::name(id)); + return load_code_blob(entry_kind, (uint)id, StubInfo::name(id), nullptr); +} + +CodeBlob* AOTCodeCache::load_code_blob(AOTCodeEntry::Kind entry_kind, BlobId id, AOTStubData* stub_data) { + assert(AOTCodeEntry::is_multi_stub_blob(entry_kind), + "wrong entry kind for blob id %s", StubInfo::name(id)); + return load_code_blob(entry_kind, (uint)id, StubInfo::name(id), stub_data); +} + +CodeBlob* AOTCodeReader::compile_code_blob(const char* name, AOTCodeEntry::Kind entry_kind, int id, AOTStubData* stub_data) { uint entry_position = _entry->offset(); // Read name @@ -1029,20 +1313,32 @@ CodeBlob* AOTCodeReader::compile_code_blob(const char* name) { } _name = stored_name; - // Read archived code blob + // Read archived code blob and related info uint offset = entry_position + _entry->blob_offset(); CodeBlob* archived_blob = (CodeBlob*)addr(offset); offset += archived_blob->size(); + _reloc_count = *(int*)addr(offset); offset += sizeof(int); + if (AOTCodeEntry::is_multi_stub_blob(entry_kind)) { + // position of relocs will have been aligned to heap word size so + // we can install them into a code buffer + offset = align_up(offset, DATA_ALIGNMENT); + } _reloc_data = (address)addr(offset); - offset += archived_blob->relocation_size(); + offset += _reloc_count * sizeof(relocInfo); set_read_position(offset); if (_entry->has_oop_maps()) { _oop_maps = read_oop_map_set(); } + // record current context for use by that callback + _stub_data = stub_data; + _entry_kind = entry_kind; + _id = id; + // CodeBlob::restore() calls AOTCodeReader::restore() + CodeBlob* code_blob = CodeBlob::create(archived_blob, this); if (code_blob == nullptr) { // no space left in CodeCache @@ -1065,10 +1361,60 @@ void AOTCodeReader::restore(CodeBlob* code_blob) { precond(_reloc_data != nullptr); code_blob->set_name(_name); - code_blob->restore_mutable_data(_reloc_data); + // Saved relocations need restoring except for the case of a + // multi-stub blob which has no runtime relocations. However, we may + // still have saved some (re-)load time relocs that were attached to + // the generator's code buffer. We don't attach them to the blob but + // they get processed below by fix_relocations. + if (!AOTCodeEntry::is_multi_stub_blob(_entry_kind)) { + code_blob->restore_mutable_data(_reloc_data); + } code_blob->set_oop_maps(_oop_maps); - fix_relocations(code_blob); + // if this is a multi stub blob load its entries + if (AOTCodeEntry::is_blob(_entry_kind)) { + BlobId blob_id = static_cast(_id); + if (StubInfo::is_stubgen(blob_id)) { + assert(_stub_data != nullptr, "sanity"); + read_stub_data(code_blob, _stub_data); + } + // publish entries found either in stub_data or as offsets in blob + AOTCodeCache::publish_stub_addresses(*code_blob, blob_id, _stub_data); + } + + // Now that all the entry points are in the address table we can + // read all the extra reloc info and fix up any addresses that need + // patching to adjust for a new location in a new JVM. We can be + // sure to correctly update all runtime references, including + // cross-linked stubs that are internally daisy-chained. If + // relocation fails and we have to re-generate any of the stubs then + // the entry points for newly generated stubs will get updated, + // ensuring that any other stubs or nmethods we need to relocate + // will use the correct address. + + // if we have a relocatable code blob then the relocs are already + // attached to the blob and we can iterate over it to find the ones + // we need to patch. With a non-relocatable code blob we need to + // wrap it with a CodeBuffer and then reattach the relocs to the + // code buffer. + + if (AOTCodeEntry::is_multi_stub_blob(_entry_kind)) { + // the blob doesn't have any proper runtime relocs but we can + // reinstate the AOT-load time relocs we saved from the code + // buffer that generated this blob in a new code buffer and use + // the latter to iterate over them + CodeBuffer code_buffer(code_blob); + relocInfo* locs = (relocInfo*)_reloc_data; + code_buffer.insts()->initialize_shared_locs(locs, _reloc_count); + code_buffer.insts()->set_locs_end(locs + _reloc_count); + CodeSection *cs = code_buffer.code_section(CodeBuffer::SECT_INSTS); + RelocIterator reloc_iter(cs); + fix_relocations(code_blob, reloc_iter); + } else { + // the AOT-load time relocs will be in the blob's restored relocs + RelocIterator reloc_iter(code_blob); + fix_relocations(code_blob, reloc_iter); + } #ifndef PRODUCT code_blob->asm_remarks().init(); @@ -1078,15 +1424,150 @@ void AOTCodeReader::restore(CodeBlob* code_blob) { #endif // PRODUCT } +void AOTCodeReader::read_stub_data(CodeBlob* code_blob, AOTStubData* stub_data) { + GrowableArray
& addresses = stub_data->address_array(); + // Read the list of stub ids and associated start, end, secondary + // and extra addresses and install them in the stub data. + // + // Also insert all start and secondary addresses into the AOTCache + // address table so we correctly relocate this blob and any followng + // blobs/nmethods. + // + // n.b. if an error occurs and we need to regenerate any of these + // stubs the address table will be updated as a side-effect of + // regeneration. + + address blob_base = code_blob->code_begin(); + uint blob_size = (uint)(code_blob->code_end() - blob_base); + int offset = read_position(); + LogStreamHandle(Trace, aot, codecache, stubs) log; + if (log.is_enabled()) { + log.print_cr("======== Stub data starts at offset %d", offset); + } + // read stub and entries until we see NO_STUBID + StubId stub_id = *(StubId*)addr(offset); offset += sizeof(StubId); + // we ought to have at least one saved stub in the blob + assert(stub_id != StubId::NO_STUBID, "blob %s contains no stubs!", StubInfo::name(stub_data->blob_id())); + while (stub_id != StubId::NO_STUBID) { + assert(StubInfo::blob(stub_id) == stub_data->blob_id(), "sanity"); + int idx = StubInfo::stubgen_offset_in_blob(stub_data->blob_id(), stub_id); + StubAddrRange& range = stub_data->get_range(idx); + // we should only see a stub once + assert(range.start_index() < 0, "repeated entry for stub %s", StubInfo::name(stub_id)); + int address_base = addresses.length(); + // start is an offset from the blob base + uint start = *(uint*)addr(offset); offset += sizeof(uint); + assert(start < blob_size, "stub %s start offset %d exceeds buffer length %d", StubInfo::name(stub_id), start, blob_size); + address stub_start = blob_base + start; + addresses.append(stub_start); + // end is an offset from the stub start + uint end = *(uint*)addr(offset); offset += sizeof(uint); + assert(start + end <= blob_size, "stub %s end offset %d exceeds remaining buffer length %d", StubInfo::name(stub_id), end, blob_size - start); + addresses.append(stub_start + end); + // read count of secondary entries plus extras + int entries_count = *(int*)addr(offset); offset += sizeof(int); + assert(entries_count >= (StubInfo::entry_count(stub_id) - 1), "not enough entries for %s", StubInfo::name(stub_id)); + for (int i = 0; i < entries_count; i++) { + // entry offset is an offset from the stub start less than or + // equal to end + uint entry = *(uint*)addr(offset); offset += sizeof(uint); + if (entry <= end) { + // entry addresses may not address end but extras can + assert(entry < end || i >= StubInfo::entry_count(stub_id), + "entry offset 0x%x exceeds stub length 0x%x for stub %s", + entry, end, StubInfo::name(stub_id)); + addresses.append(stub_start + entry); + } else { + // special case: entry encodes a nullptr + assert(entry == AOTCodeCache::NULL_ADDRESS_MARKER, "stub %s entry offset %d lies beyond stub end %d and does not equal NULL_ADDRESS_MARKER", StubInfo::name(stub_id), entry, end); + addresses.append(nullptr); + } + } + if (log.is_enabled()) { + log.print_cr("======== read stub %s and %d addresses up to offset %d", + StubInfo::name(stub_id), 2 + entries_count, offset); + } + range.init_entry(address_base, 2 + entries_count); + // move on to next stub or NO_STUBID + stub_id = *(StubId*)addr(offset); offset += sizeof(StubId); + } + if (log.is_enabled()) { + log.print_cr("======== Stub data ends at offset %d", offset); + } + + set_read_position(offset); +} + +void AOTCodeCache::publish_external_addresses(GrowableArray
& addresses) { + DEBUG_ONLY( _passed_init2 = true; ) + if (opened_cache == nullptr) { + return; + } + + cache()->_table->add_external_addresses(addresses); +} + +void AOTCodeCache::publish_stub_addresses(CodeBlob &code_blob, BlobId blob_id, AOTStubData *stub_data) { + if (stub_data != nullptr) { + // register all entries in stub + assert(StubInfo::stub_count(blob_id) > 1, + "multiple stub data provided for single stub blob %s", + StubInfo::name(blob_id)); + assert(blob_id == stub_data->blob_id(), + "blob id %s does not match id in stub data %s", + StubInfo::name(blob_id), + StubInfo::name(stub_data->blob_id())); + // iterate over all stubs in the blob + StubId stub_id = StubInfo::stub_base(blob_id); + int stub_cnt = StubInfo::stub_count(blob_id); + GrowableArray
& addresses = stub_data->address_array(); + for (int i = 0; i < stub_cnt; i++) { + assert(stub_id != StubId::NO_STUBID, "sanity"); + StubAddrRange& range = stub_data->get_range(i); + int base = range.start_index(); + if (base >= 0) { + cache()->add_stub_entries(stub_id, addresses.at(base), &addresses, base + 2); + } + stub_id = StubInfo::next_in_blob(blob_id, stub_id); + } + // we should have exhausted all stub ids in the blob + assert(stub_id == StubId::NO_STUBID, "sanity"); + } else { + // register entry or entries for a single stub blob + StubId stub_id = StubInfo::stub_base(blob_id); + assert(StubInfo::stub_count(blob_id) == 1, + "multiple stub blob %s provided without stub data", + StubInfo::name(blob_id)); + address start = code_blob.code_begin(); + if (StubInfo::entry_count(stub_id) == 1) { + assert(!code_blob.is_deoptimization_stub(), "expecting multiple entries for stub %s", StubInfo::name(stub_id)); + // register the blob base address as the only entry + cache()->add_stub_entries(stub_id, start); + } else { + assert(code_blob.is_deoptimization_stub(), "only expecting one entry for stub %s", StubInfo::name(stub_id)); + DeoptimizationBlob *deopt_blob = code_blob.as_deoptimization_blob(); + assert(deopt_blob->unpack() == start, "unexpected offset 0x%x for deopt stub entry", (int)(deopt_blob->unpack() - start)); + GrowableArray
addresses; + addresses.append(deopt_blob->unpack_with_exception()); + addresses.append(deopt_blob->unpack_with_reexecution()); + addresses.append(deopt_blob->unpack_with_exception_in_tls()); +#if INCLUDE_JVMCI + addresses.append(deopt_blob->uncommon_trap()); + addresses.append(deopt_blob->implicit_exception_uncommon_trap()); +#endif // INCLUDE_JVMCI + cache()->add_stub_entries(stub_id, start, &addresses, 0); + } + } +} + // ------------ process code and data -------------- // Can't use -1. It is valid value for jump to iteself destination // used by static call stub: see NativeJump::jump_destination(). #define BAD_ADDRESS_ID -2 -bool AOTCodeCache::write_relocations(CodeBlob& code_blob) { +bool AOTCodeCache::write_relocations(CodeBlob& code_blob, RelocIterator& iter) { GrowableArray reloc_data; - RelocIterator iter(&code_blob); LogStreamHandle(Trace, aot, codecache, reloc) log; while (iter.next()) { int idx = reloc_data.append(0); // default value @@ -1140,6 +1621,11 @@ bool AOTCodeCache::write_relocations(CodeBlob& code_blob) { // Write the count first int count = reloc_data.length(); write_bytes(&count, sizeof(int)); + if (log.is_enabled()) { + log.print_cr("======== extra relocations count=%d", count); + log.print( " {"); + } + bool first = true; for (GrowableArrayIterator iter = reloc_data.begin(); iter != reloc_data.end(); ++iter) { uint value = *iter; @@ -1147,23 +1633,43 @@ bool AOTCodeCache::write_relocations(CodeBlob& code_blob) { if (n != sizeof(uint)) { return false; } + if (log.is_enabled()) { + if (first) { + first = false; + log.print("%d", value); + } else { + log.print(", %d", value); + } + } + } + if (log.is_enabled()) { + log.print_cr("}"); } return true; } -void AOTCodeReader::fix_relocations(CodeBlob* code_blob) { - LogStreamHandle(Trace, aot, reloc) log; +void AOTCodeReader::fix_relocations(CodeBlob *code_blob, RelocIterator& iter) { uint offset = read_position(); - int count = *(int*)addr(offset); + int reloc_count = *(int*)addr(offset); offset += sizeof(int); - if (log.is_enabled()) { - log.print_cr("======== extra relocations count=%d", count); - } uint* reloc_data = (uint*)addr(offset); - offset += (count * sizeof(uint)); + offset += (reloc_count * sizeof(uint)); set_read_position(offset); - RelocIterator iter(code_blob); + LogStreamHandle(Trace, aot, codecache, reloc) log; + if (log.is_enabled()) { + log.print_cr("======== extra relocations count=%d", reloc_count); + log.print(" {"); + for(int i = 0; i < reloc_count; i++) { + if (i == 0) { + log.print("%d", reloc_data[i]); + } else { + log.print(", %d", reloc_data[i]); + } + } + log.print_cr("}"); + } + int j = 0; while (iter.next()) { switch (iter.type()) { @@ -1212,7 +1718,7 @@ void AOTCodeReader::fix_relocations(CodeBlob* code_blob) { } j++; } - assert(j == count, "sanity"); + assert(j == reloc_count, "sanity"); } bool AOTCodeCache::write_oop_map_set(CodeBlob& cb) { @@ -1322,249 +1828,360 @@ void AOTCodeReader::read_dbg_strings(DbgStrings& dbg_strings) { //======================= AOTCodeAddressTable =============== -// address table ids for generated routines, external addresses and C -// string addresses are partitioned into positive integer ranges -// defined by the following positive base and max values -// i.e. [_extrs_base, _extrs_base + _extrs_max -1], -// [_blobs_base, _blobs_base + _blobs_max -1], -// ... -// [_c_str_base, _c_str_base + _c_str_max -1], +// address table ids for generated routine entry adresses, external +// addresses and C string addresses are partitioned into positive +// integer ranges defined by the following positive base and max +// values i.e. [_extrs_base, _extrs_base + _extrs_max -1], +// [_stubs_base, _stubs_base + _stubs_max -1], [_c_str_base, +// _c_str_base + _c_str_max -1], -#define _extrs_max 100 -#define _stubs_max 3 - -#define _shared_blobs_max 20 -#define _C1_blobs_max 10 -#define _blobs_max (_shared_blobs_max+_C1_blobs_max) -#define _all_max (_extrs_max+_stubs_max+_blobs_max) +#define _extrs_max 380 +#define _stubs_max static_cast(EntryId::NUM_ENTRYIDS) #define _extrs_base 0 #define _stubs_base (_extrs_base + _extrs_max) -#define _shared_blobs_base (_stubs_base + _stubs_max) -#define _C1_blobs_base (_shared_blobs_base + _shared_blobs_max) -#define _blobs_end (_shared_blobs_base + _blobs_max) +#define _all_max (_stubs_base + _stubs_max) -#define SET_ADDRESS(type, addr) \ - { \ - type##_addr[type##_length++] = (address) (addr); \ - assert(type##_length <= type##_max, "increase size"); \ +// setter for external addresses and string addresses inserts new +// addresses in the order they are encountered them which must remain +// the same across an assembly run and subsequent production run + +#define ADD_EXTERNAL_ADDRESS(addr) \ + { \ + hash_address((address) addr, _extrs_base + _extrs_length); \ + _extrs_addr[_extrs_length++] = (address) (addr); \ + assert(_extrs_length <= _extrs_max, "increase size"); \ } +// insert into to the address hash table the index of an external +// address or a stub address in the list of external or stub +// addresses, respectively, keyed by the relevant address + +void AOTCodeAddressTable::hash_address(address addr, int idx) { + // only do this if we are caching stubs and we have a non-null + // address to record + if (!AOTStubCaching) { + return; + } + if (addr == nullptr) { + return; + } + // check opened_cache because this can be called before the cache is + // properly initialized and only continue when dumping is enabled + if (opened_cache != nullptr && opened_cache->for_dump()) { + if (_hash_table == nullptr) { + _hash_table = new (mtCode) AOTCodeAddressHashTable(); + } + assert(_hash_table->get(addr) == nullptr, "repeated insert of address " INTPTR_FORMAT, p2i(addr)); + _hash_table->put(addr, idx); + log_trace(aot, codecache)("Address " INTPTR_FORMAT " inserted into AOT Code Cache address hash table with index '%d'", + p2i(addr), idx); + } +} + static bool initializing_extrs = false; void AOTCodeAddressTable::init_extrs() { if (_extrs_complete || initializing_extrs) return; // Done already - assert(_blobs_end <= _all_max, "AOTCodeAddress table ranges need adjusting"); - initializing_extrs = true; _extrs_addr = NEW_C_HEAP_ARRAY(address, _extrs_max, mtCode); _extrs_length = 0; + { + // Required by initial stubs + ADD_EXTERNAL_ADDRESS(SharedRuntime::exception_handler_for_return_address); // used by forward_exception + ADD_EXTERNAL_ADDRESS(CompressedOops::base_addr()); // used by call_stub + ADD_EXTERNAL_ADDRESS(Thread::current); // used by call_stub + ADD_EXTERNAL_ADDRESS(SharedRuntime::throw_StackOverflowError); + ADD_EXTERNAL_ADDRESS(SharedRuntime::throw_delayed_StackOverflowError); + } + // Record addresses of VM runtime methods - SET_ADDRESS(_extrs, SharedRuntime::fixup_callers_callsite); - SET_ADDRESS(_extrs, SharedRuntime::handle_wrong_method); - SET_ADDRESS(_extrs, SharedRuntime::handle_wrong_method_abstract); - SET_ADDRESS(_extrs, SharedRuntime::handle_wrong_method_ic_miss); + ADD_EXTERNAL_ADDRESS(SharedRuntime::fixup_callers_callsite); + ADD_EXTERNAL_ADDRESS(SharedRuntime::handle_wrong_method); + ADD_EXTERNAL_ADDRESS(SharedRuntime::handle_wrong_method_abstract); + ADD_EXTERNAL_ADDRESS(SharedRuntime::handle_wrong_method_ic_miss); #if defined(AARCH64) && !defined(ZERO) - SET_ADDRESS(_extrs, JavaThread::aarch64_get_thread_helper); + ADD_EXTERNAL_ADDRESS(JavaThread::aarch64_get_thread_helper); #endif + +#if defined(AARCH64) + ADD_EXTERNAL_ADDRESS(BarrierSetAssembler::patching_epoch_addr()); +#endif + +#ifndef PRODUCT + ADD_EXTERNAL_ADDRESS(&SharedRuntime::_jbyte_array_copy_ctr); // used by arraycopy stub on arm32 and x86_64 + ADD_EXTERNAL_ADDRESS(&SharedRuntime::_jshort_array_copy_ctr); // used by arraycopy stub + ADD_EXTERNAL_ADDRESS(&SharedRuntime::_jint_array_copy_ctr); // used by arraycopy stub + ADD_EXTERNAL_ADDRESS(&SharedRuntime::_jlong_array_copy_ctr); // used by arraycopy stub + ADD_EXTERNAL_ADDRESS(&SharedRuntime::_oop_array_copy_ctr); // used by arraycopy stub + ADD_EXTERNAL_ADDRESS(&SharedRuntime::_checkcast_array_copy_ctr); // used by arraycopy stub + ADD_EXTERNAL_ADDRESS(&SharedRuntime::_unsafe_array_copy_ctr); // used by arraycopy stub + ADD_EXTERNAL_ADDRESS(&SharedRuntime::_generic_array_copy_ctr); // used by arraycopy stub + ADD_EXTERNAL_ADDRESS(&SharedRuntime::_unsafe_set_memory_ctr); // used by arraycopy stub +#endif /* PRODUCT */ + + ADD_EXTERNAL_ADDRESS(SharedRuntime::enable_stack_reserved_zone); + +#if defined(AMD64) && !defined(ZERO) + ADD_EXTERNAL_ADDRESS(SharedRuntime::montgomery_multiply); + ADD_EXTERNAL_ADDRESS(SharedRuntime::montgomery_square); +#endif // defined(AMD64) && !defined(ZERO) + + ADD_EXTERNAL_ADDRESS(SharedRuntime::d2f); + ADD_EXTERNAL_ADDRESS(SharedRuntime::d2i); + ADD_EXTERNAL_ADDRESS(SharedRuntime::d2l); + ADD_EXTERNAL_ADDRESS(SharedRuntime::dcos); + ADD_EXTERNAL_ADDRESS(SharedRuntime::dexp); + ADD_EXTERNAL_ADDRESS(SharedRuntime::dlog); + ADD_EXTERNAL_ADDRESS(SharedRuntime::dlog10); + ADD_EXTERNAL_ADDRESS(SharedRuntime::dpow); +#ifndef ZERO + ADD_EXTERNAL_ADDRESS(SharedRuntime::drem); +#endif + ADD_EXTERNAL_ADDRESS(SharedRuntime::dsin); + ADD_EXTERNAL_ADDRESS(SharedRuntime::dtan); + ADD_EXTERNAL_ADDRESS(SharedRuntime::f2i); + ADD_EXTERNAL_ADDRESS(SharedRuntime::f2l); +#ifndef ZERO + ADD_EXTERNAL_ADDRESS(SharedRuntime::frem); +#endif + ADD_EXTERNAL_ADDRESS(SharedRuntime::l2d); + ADD_EXTERNAL_ADDRESS(SharedRuntime::l2f); + ADD_EXTERNAL_ADDRESS(SharedRuntime::ldiv); + ADD_EXTERNAL_ADDRESS(SharedRuntime::lmul); + ADD_EXTERNAL_ADDRESS(SharedRuntime::lrem); + +#if INCLUDE_JVMTI + ADD_EXTERNAL_ADDRESS(&JvmtiExport::_should_notify_object_alloc); +#endif /* INCLUDE_JVMTI */ + + ADD_EXTERNAL_ADDRESS(ThreadIdentifier::unsafe_offset()); + // already added + // ADD_EXTERNAL_ADDRESS(Thread::current); + + ADD_EXTERNAL_ADDRESS(os::javaTimeMillis); + ADD_EXTERNAL_ADDRESS(os::javaTimeNanos); +#ifndef PRODUCT + ADD_EXTERNAL_ADDRESS(os::breakpoint); +#endif + + ADD_EXTERNAL_ADDRESS(StubRoutines::crc_table_addr()); +#ifndef PRODUCT + ADD_EXTERNAL_ADDRESS(&SharedRuntime::_partial_subtype_ctr); +#endif + +#if INCLUDE_JFR + ADD_EXTERNAL_ADDRESS(JfrIntrinsicSupport::write_checkpoint); + ADD_EXTERNAL_ADDRESS(JfrIntrinsicSupport::return_lease); +#endif + + ADD_EXTERNAL_ADDRESS(UpcallLinker::handle_uncaught_exception); // used by upcall_stub_exception_handler + { // Required by Shared blobs - SET_ADDRESS(_extrs, Deoptimization::fetch_unroll_info); - SET_ADDRESS(_extrs, Deoptimization::unpack_frames); - SET_ADDRESS(_extrs, SafepointSynchronize::handle_polling_page_exception); - SET_ADDRESS(_extrs, SharedRuntime::resolve_opt_virtual_call_C); - SET_ADDRESS(_extrs, SharedRuntime::resolve_virtual_call_C); - SET_ADDRESS(_extrs, SharedRuntime::resolve_static_call_C); - SET_ADDRESS(_extrs, SharedRuntime::throw_StackOverflowError); - SET_ADDRESS(_extrs, SharedRuntime::throw_delayed_StackOverflowError); - SET_ADDRESS(_extrs, SharedRuntime::throw_AbstractMethodError); - SET_ADDRESS(_extrs, SharedRuntime::throw_IncompatibleClassChangeError); - SET_ADDRESS(_extrs, SharedRuntime::throw_NullPointerException_at_call); + ADD_EXTERNAL_ADDRESS(Deoptimization::fetch_unroll_info); + ADD_EXTERNAL_ADDRESS(Deoptimization::unpack_frames); + ADD_EXTERNAL_ADDRESS(SafepointSynchronize::handle_polling_page_exception); + ADD_EXTERNAL_ADDRESS(SharedRuntime::resolve_opt_virtual_call_C); + ADD_EXTERNAL_ADDRESS(SharedRuntime::resolve_virtual_call_C); + ADD_EXTERNAL_ADDRESS(SharedRuntime::resolve_static_call_C); + // already added + // ADD_EXTERNAL_ADDRESS(SharedRuntime::throw_delayed_StackOverflowError); + ADD_EXTERNAL_ADDRESS(SharedRuntime::throw_AbstractMethodError); + ADD_EXTERNAL_ADDRESS(SharedRuntime::throw_IncompatibleClassChangeError); + ADD_EXTERNAL_ADDRESS(SharedRuntime::throw_NullPointerException_at_call); } #ifdef COMPILER1 { // Required by C1 blobs - SET_ADDRESS(_extrs, static_cast(SharedRuntime::dtrace_object_alloc)); - SET_ADDRESS(_extrs, SharedRuntime::exception_handler_for_return_address); - SET_ADDRESS(_extrs, SharedRuntime::register_finalizer); - SET_ADDRESS(_extrs, Runtime1::is_instance_of); - SET_ADDRESS(_extrs, Runtime1::exception_handler_for_pc); - SET_ADDRESS(_extrs, Runtime1::check_abort_on_vm_exception); - SET_ADDRESS(_extrs, Runtime1::new_instance); - SET_ADDRESS(_extrs, Runtime1::counter_overflow); - SET_ADDRESS(_extrs, Runtime1::new_type_array); - SET_ADDRESS(_extrs, Runtime1::new_object_array); - SET_ADDRESS(_extrs, Runtime1::new_multi_array); - SET_ADDRESS(_extrs, Runtime1::throw_range_check_exception); - SET_ADDRESS(_extrs, Runtime1::throw_index_exception); - SET_ADDRESS(_extrs, Runtime1::throw_div0_exception); - SET_ADDRESS(_extrs, Runtime1::throw_null_pointer_exception); - SET_ADDRESS(_extrs, Runtime1::throw_array_store_exception); - SET_ADDRESS(_extrs, Runtime1::throw_class_cast_exception); - SET_ADDRESS(_extrs, Runtime1::throw_incompatible_class_change_error); - SET_ADDRESS(_extrs, Runtime1::is_instance_of); - SET_ADDRESS(_extrs, Runtime1::monitorenter); - SET_ADDRESS(_extrs, Runtime1::monitorexit); - SET_ADDRESS(_extrs, Runtime1::deoptimize); - SET_ADDRESS(_extrs, Runtime1::access_field_patching); - SET_ADDRESS(_extrs, Runtime1::move_klass_patching); - SET_ADDRESS(_extrs, Runtime1::move_mirror_patching); - SET_ADDRESS(_extrs, Runtime1::move_appendix_patching); - SET_ADDRESS(_extrs, Runtime1::predicate_failed_trap); - SET_ADDRESS(_extrs, Runtime1::unimplemented_entry); - SET_ADDRESS(_extrs, Thread::current); - SET_ADDRESS(_extrs, CompressedKlassPointers::base_addr()); -#ifndef PRODUCT - SET_ADDRESS(_extrs, os::breakpoint); -#endif + ADD_EXTERNAL_ADDRESS(static_cast(SharedRuntime::dtrace_object_alloc)); + ADD_EXTERNAL_ADDRESS(SharedRuntime::register_finalizer); + ADD_EXTERNAL_ADDRESS(Runtime1::is_instance_of); + ADD_EXTERNAL_ADDRESS(Runtime1::exception_handler_for_pc); + ADD_EXTERNAL_ADDRESS(Runtime1::check_abort_on_vm_exception); + ADD_EXTERNAL_ADDRESS(Runtime1::new_instance); + ADD_EXTERNAL_ADDRESS(Runtime1::counter_overflow); + ADD_EXTERNAL_ADDRESS(Runtime1::new_type_array); + ADD_EXTERNAL_ADDRESS(Runtime1::new_object_array); + ADD_EXTERNAL_ADDRESS(Runtime1::new_multi_array); + ADD_EXTERNAL_ADDRESS(Runtime1::throw_range_check_exception); + ADD_EXTERNAL_ADDRESS(Runtime1::throw_index_exception); + ADD_EXTERNAL_ADDRESS(Runtime1::throw_div0_exception); + ADD_EXTERNAL_ADDRESS(Runtime1::throw_null_pointer_exception); + ADD_EXTERNAL_ADDRESS(Runtime1::throw_array_store_exception); + ADD_EXTERNAL_ADDRESS(Runtime1::throw_class_cast_exception); + ADD_EXTERNAL_ADDRESS(Runtime1::throw_incompatible_class_change_error); + ADD_EXTERNAL_ADDRESS(Runtime1::monitorenter); + ADD_EXTERNAL_ADDRESS(Runtime1::monitorexit); + ADD_EXTERNAL_ADDRESS(Runtime1::deoptimize); + ADD_EXTERNAL_ADDRESS(Runtime1::access_field_patching); + ADD_EXTERNAL_ADDRESS(Runtime1::move_klass_patching); + ADD_EXTERNAL_ADDRESS(Runtime1::move_mirror_patching); + ADD_EXTERNAL_ADDRESS(Runtime1::move_appendix_patching); + ADD_EXTERNAL_ADDRESS(Runtime1::predicate_failed_trap); + ADD_EXTERNAL_ADDRESS(Runtime1::unimplemented_entry); + // already added + // ADD_EXTERNAL_ADDRESS(Thread::current); + ADD_EXTERNAL_ADDRESS(CompressedKlassPointers::base_addr()); } #endif #ifdef COMPILER2 { // Required by C2 blobs - SET_ADDRESS(_extrs, Deoptimization::uncommon_trap); - SET_ADDRESS(_extrs, OptoRuntime::handle_exception_C); - SET_ADDRESS(_extrs, OptoRuntime::new_instance_C); - SET_ADDRESS(_extrs, OptoRuntime::new_array_C); - SET_ADDRESS(_extrs, OptoRuntime::new_array_nozero_C); - SET_ADDRESS(_extrs, OptoRuntime::multianewarray2_C); - SET_ADDRESS(_extrs, OptoRuntime::multianewarray3_C); - SET_ADDRESS(_extrs, OptoRuntime::multianewarray4_C); - SET_ADDRESS(_extrs, OptoRuntime::multianewarray5_C); - SET_ADDRESS(_extrs, OptoRuntime::multianewarrayN_C); - SET_ADDRESS(_extrs, OptoRuntime::complete_monitor_locking_C); - SET_ADDRESS(_extrs, OptoRuntime::monitor_notify_C); - SET_ADDRESS(_extrs, OptoRuntime::monitor_notifyAll_C); - SET_ADDRESS(_extrs, OptoRuntime::rethrow_C); - SET_ADDRESS(_extrs, OptoRuntime::slow_arraycopy_C); - SET_ADDRESS(_extrs, OptoRuntime::register_finalizer_C); - SET_ADDRESS(_extrs, OptoRuntime::vthread_end_first_transition_C); - SET_ADDRESS(_extrs, OptoRuntime::vthread_start_final_transition_C); - SET_ADDRESS(_extrs, OptoRuntime::vthread_start_transition_C); - SET_ADDRESS(_extrs, OptoRuntime::vthread_end_transition_C); -#if defined(AARCH64) - SET_ADDRESS(_extrs, JavaThread::verify_cross_modify_fence_failure); -#endif // AARCH64 + ADD_EXTERNAL_ADDRESS(Deoptimization::uncommon_trap); + ADD_EXTERNAL_ADDRESS(OptoRuntime::handle_exception_C); + ADD_EXTERNAL_ADDRESS(OptoRuntime::new_instance_C); + ADD_EXTERNAL_ADDRESS(OptoRuntime::new_array_C); + ADD_EXTERNAL_ADDRESS(OptoRuntime::new_array_nozero_C); + ADD_EXTERNAL_ADDRESS(OptoRuntime::multianewarray2_C); + ADD_EXTERNAL_ADDRESS(OptoRuntime::multianewarray3_C); + ADD_EXTERNAL_ADDRESS(OptoRuntime::multianewarray4_C); + ADD_EXTERNAL_ADDRESS(OptoRuntime::multianewarray5_C); + ADD_EXTERNAL_ADDRESS(OptoRuntime::multianewarrayN_C); + ADD_EXTERNAL_ADDRESS(OptoRuntime::complete_monitor_locking_C); + ADD_EXTERNAL_ADDRESS(OptoRuntime::monitor_notify_C); + ADD_EXTERNAL_ADDRESS(OptoRuntime::monitor_notifyAll_C); + ADD_EXTERNAL_ADDRESS(OptoRuntime::rethrow_C); + ADD_EXTERNAL_ADDRESS(OptoRuntime::slow_arraycopy_C); + ADD_EXTERNAL_ADDRESS(OptoRuntime::register_finalizer_C); + ADD_EXTERNAL_ADDRESS(OptoRuntime::vthread_end_first_transition_C); + ADD_EXTERNAL_ADDRESS(OptoRuntime::vthread_start_final_transition_C); + ADD_EXTERNAL_ADDRESS(OptoRuntime::vthread_start_transition_C); + ADD_EXTERNAL_ADDRESS(OptoRuntime::vthread_end_transition_C); + // already added for +#if defined(AARCH64) && ! defined(PRODUCT) + ADD_EXTERNAL_ADDRESS(JavaThread::verify_cross_modify_fence_failure); +#endif // AARCH64 && !PRODUCT } #endif // COMPILER2 #if INCLUDE_G1GC - SET_ADDRESS(_extrs, G1BarrierSetRuntime::write_ref_field_pre_entry); + ADD_EXTERNAL_ADDRESS(G1BarrierSetRuntime::write_ref_field_pre_entry); + ADD_EXTERNAL_ADDRESS(G1BarrierSetRuntime::write_ref_array_pre_narrow_oop_entry); // used by arraycopy stubs + ADD_EXTERNAL_ADDRESS(G1BarrierSetRuntime::write_ref_array_pre_oop_entry); // used by arraycopy stubs + ADD_EXTERNAL_ADDRESS(G1BarrierSetRuntime::write_ref_array_post_entry); // used by arraycopy stubs + ADD_EXTERNAL_ADDRESS(BarrierSetNMethod::nmethod_stub_entry_barrier); // used by method_entry_barrier + #endif #if INCLUDE_SHENANDOAHGC - SET_ADDRESS(_extrs, ShenandoahRuntime::write_barrier_pre); - SET_ADDRESS(_extrs, ShenandoahRuntime::load_reference_barrier_phantom); - SET_ADDRESS(_extrs, ShenandoahRuntime::load_reference_barrier_phantom_narrow); + ADD_EXTERNAL_ADDRESS(ShenandoahRuntime::write_barrier_pre); + ADD_EXTERNAL_ADDRESS(ShenandoahRuntime::load_reference_barrier_strong); + ADD_EXTERNAL_ADDRESS(ShenandoahRuntime::load_reference_barrier_strong_narrow); + ADD_EXTERNAL_ADDRESS(ShenandoahRuntime::load_reference_barrier_weak); + ADD_EXTERNAL_ADDRESS(ShenandoahRuntime::load_reference_barrier_weak_narrow); + ADD_EXTERNAL_ADDRESS(ShenandoahRuntime::load_reference_barrier_phantom); + ADD_EXTERNAL_ADDRESS(ShenandoahRuntime::load_reference_barrier_phantom_narrow); + ADD_EXTERNAL_ADDRESS(ShenandoahRuntime::arraycopy_barrier_oop); + ADD_EXTERNAL_ADDRESS(ShenandoahRuntime::arraycopy_barrier_narrow_oop); #endif #if INCLUDE_ZGC - SET_ADDRESS(_extrs, ZBarrierSetRuntime::load_barrier_on_oop_field_preloaded_addr()); - SET_ADDRESS(_extrs, ZBarrierSetRuntime::load_barrier_on_phantom_oop_field_preloaded_addr()); + ADD_EXTERNAL_ADDRESS(ZBarrierSetRuntime::load_barrier_on_oop_field_preloaded_addr()); + ADD_EXTERNAL_ADDRESS(ZBarrierSetRuntime::load_barrier_on_oop_field_preloaded_store_good_addr()); + ADD_EXTERNAL_ADDRESS(ZBarrierSetRuntime::load_barrier_on_weak_oop_field_preloaded_addr()); + ADD_EXTERNAL_ADDRESS(ZBarrierSetRuntime::load_barrier_on_phantom_oop_field_preloaded_addr()); + ADD_EXTERNAL_ADDRESS(ZBarrierSetRuntime::no_keepalive_load_barrier_on_weak_oop_field_preloaded_addr()); + ADD_EXTERNAL_ADDRESS(ZBarrierSetRuntime::no_keepalive_load_barrier_on_phantom_oop_field_preloaded_addr()); + ADD_EXTERNAL_ADDRESS(ZBarrierSetRuntime::store_barrier_on_oop_field_with_healing_addr()); + ADD_EXTERNAL_ADDRESS(ZBarrierSetRuntime::store_barrier_on_oop_field_without_healing_addr()); + ADD_EXTERNAL_ADDRESS(ZBarrierSetRuntime::no_keepalive_store_barrier_on_oop_field_without_healing_addr()); + ADD_EXTERNAL_ADDRESS(ZBarrierSetRuntime::store_barrier_on_native_oop_field_without_healing_addr()); + ADD_EXTERNAL_ADDRESS(ZBarrierSetRuntime::load_barrier_on_oop_array_addr()); + + ADD_EXTERNAL_ADDRESS(ZPointerVectorLoadBadMask); + ADD_EXTERNAL_ADDRESS(ZPointerVectorStoreBadMask); + ADD_EXTERNAL_ADDRESS(ZPointerVectorStoreGoodMask); #if defined(AMD64) - SET_ADDRESS(_extrs, &ZPointerLoadShift); + ADD_EXTERNAL_ADDRESS(&ZPointerLoadShift); + ADD_EXTERNAL_ADDRESS(&ZPointerLoadShiftTable); #endif #endif #ifndef ZERO #if defined(AMD64) || defined(AARCH64) || defined(RISCV64) - SET_ADDRESS(_extrs, MacroAssembler::debug64); -#endif + ADD_EXTERNAL_ADDRESS(MacroAssembler::debug64); +#endif // defined(AMD64) || defined(AARCH64) || defined(RISCV64) +#if defined(AMD64) + ADD_EXTERNAL_ADDRESS(warning); +#endif // defined(AMD64) #endif // ZERO // addresses of fields in AOT runtime constants area address* p = AOTRuntimeConstants::field_addresses_list(); while (*p != nullptr) { - SET_ADDRESS(_extrs, *p++); + address to_add = (address)*p++; + ADD_EXTERNAL_ADDRESS(to_add); } - _extrs_complete = true; - log_debug(aot, codecache, init)("External addresses recorded"); + log_debug(aot, codecache, init)("External addresses opened and recorded"); + // allocate storage for stub entries + _stubs_addr = NEW_C_HEAP_ARRAY(address, _stubs_max, mtCode); + log_debug(aot, codecache, init)("Stub addresses opened"); } -static bool initializing_early_stubs = false; - -void AOTCodeAddressTable::init_early_stubs() { - if (_complete || initializing_early_stubs) return; // Done already - initializing_early_stubs = true; - _stubs_addr = NEW_C_HEAP_ARRAY(address, _stubs_max, mtCode); - _stubs_length = 0; - SET_ADDRESS(_stubs, StubRoutines::forward_exception_entry()); +void AOTCodeAddressTable::init_extrs2() { + assert(initializing_extrs && !_extrs_complete, + "invalid sequence for init_extrs2"); { - // Required by C1 blobs -#if defined(AMD64) && !defined(ZERO) - SET_ADDRESS(_stubs, StubRoutines::x86::double_sign_flip()); - SET_ADDRESS(_stubs, StubRoutines::x86::d2l_fixup()); -#endif // AMD64 + ADD_EXTERNAL_ADDRESS(Continuation::prepare_thaw); // used by cont_thaw + ADD_EXTERNAL_ADDRESS(Continuation::thaw_entry()); // used by cont_thaw + ADD_EXTERNAL_ADDRESS(ContinuationEntry::thaw_call_pc_address()); // used by cont_preempt_stub } - - _early_stubs_complete = true; - log_info(aot, codecache, init)("Early stubs recorded"); + _extrs_complete = true; + initializing_extrs = false; + log_debug(aot, codecache, init)("External addresses recorded and closed"); } -static bool initializing_shared_blobs = false; - -void AOTCodeAddressTable::init_shared_blobs() { - if (_complete || initializing_shared_blobs) return; // Done already - initializing_shared_blobs = true; - address* blobs_addr = NEW_C_HEAP_ARRAY(address, _blobs_max, mtCode); - - // Divide _shared_blobs_addr array to chunks because they could be initialized in parrallel - _shared_blobs_addr = blobs_addr; - _C1_blobs_addr = _shared_blobs_addr + _shared_blobs_max; - - _shared_blobs_length = 0; - _C1_blobs_length = 0; - - // clear the address table - memset(blobs_addr, 0, sizeof(address)* _blobs_max); - - // Record addresses of generated code blobs - SET_ADDRESS(_shared_blobs, SharedRuntime::get_handle_wrong_method_stub()); - SET_ADDRESS(_shared_blobs, SharedRuntime::get_ic_miss_stub()); - SET_ADDRESS(_shared_blobs, SharedRuntime::deopt_blob()->unpack()); - SET_ADDRESS(_shared_blobs, SharedRuntime::deopt_blob()->unpack_with_exception()); - SET_ADDRESS(_shared_blobs, SharedRuntime::deopt_blob()->unpack_with_reexecution()); - SET_ADDRESS(_shared_blobs, SharedRuntime::deopt_blob()->unpack_with_exception_in_tls()); -#if INCLUDE_JVMCI - if (EnableJVMCI) { - SET_ADDRESS(_shared_blobs, SharedRuntime::deopt_blob()->uncommon_trap()); - SET_ADDRESS(_shared_blobs, SharedRuntime::deopt_blob()->implicit_exception_uncommon_trap()); +void AOTCodeAddressTable::add_external_addresses(GrowableArray
& addresses) { + assert(initializing_extrs && !_extrs_complete, + "invalid sequence for add_external_addresses"); + for (int i = 0; i < addresses.length(); i++) { + ADD_EXTERNAL_ADDRESS(addresses.at(i)); } -#endif - - _shared_blobs_complete = true; - log_debug(aot, codecache, init)("Early shared blobs recorded"); - _complete = true; + log_debug(aot, codecache, init)("Recorded %d additional external addresses", + addresses.length()); } -void AOTCodeAddressTable::init_early_c1() { -#ifdef COMPILER1 - // Runtime1 Blobs - StubId id = StubInfo::stub_base(StubGroup::C1); - // include forward_exception in range we publish - StubId limit = StubInfo::next(StubId::c1_forward_exception_id); - for (; id != limit; id = StubInfo::next(id)) { - if (Runtime1::blob_for(id) == nullptr) { - log_info(aot, codecache, init)("C1 blob %s is missing", Runtime1::name_for(id)); - continue; - } - if (Runtime1::entry_for(id) == nullptr) { - log_info(aot, codecache, init)("C1 blob %s is missing entry", Runtime1::name_for(id)); - continue; - } - address entry = Runtime1::entry_for(id); - SET_ADDRESS(_C1_blobs, entry); - } -#endif // COMPILER1 - assert(_C1_blobs_length <= _C1_blobs_max, "increase _C1_blobs_max to %d", _C1_blobs_length); - _early_c1_complete = true; +void AOTCodeAddressTable::add_stub_entry(EntryId entry_id, address a) { + assert(_extrs_complete || initializing_extrs, + "recording stub entry address before external addresses complete"); + assert(!(StubInfo::is_shared(StubInfo::stub(entry_id)) && _shared_stubs_complete), "too late to add shared entry"); + assert(!(StubInfo::is_stubgen(StubInfo::stub(entry_id)) && _stubgen_stubs_complete), "too late to add stubgen entry"); + assert(!(StubInfo::is_c1(StubInfo::stub(entry_id)) && _c1_stubs_complete), "too late to add c1 entry"); + assert(!(StubInfo::is_c2(StubInfo::stub(entry_id)) && _c2_stubs_complete), "too late to add c2 entry"); + log_debug(aot, stubs)("Recording address 0x%p for %s entry %s", a, StubInfo::name(StubInfo::stubgroup(entry_id)), StubInfo::name(entry_id)); + int idx = static_cast(entry_id); + hash_address(a, _stubs_base + idx); + _stubs_addr[idx] = a; } -#undef SET_ADDRESS +void AOTCodeAddressTable::set_shared_stubs_complete() { + assert(!_shared_stubs_complete, "repeated close for shared stubs!"); + _shared_stubs_complete = true; + log_debug(aot, codecache, init)("Shared stubs closed"); +} + +void AOTCodeAddressTable::set_c1_stubs_complete() { + assert(!_c1_stubs_complete, "repeated close for c1 stubs!"); + _c1_stubs_complete = true; + log_debug(aot, codecache, init)("C1 stubs closed"); +} + +void AOTCodeAddressTable::set_c2_stubs_complete() { + assert(!_c2_stubs_complete, "repeated close for c2 stubs!"); + _c2_stubs_complete = true; + log_debug(aot, codecache, init)("C2 stubs closed"); +} + +void AOTCodeAddressTable::set_stubgen_stubs_complete() { + assert(!_stubgen_stubs_complete, "repeated close for stubgen stubs!"); + _stubgen_stubs_complete = true; + log_debug(aot, codecache, init)("StubGen stubs closed"); +} #ifdef PRODUCT #define MAX_STR_COUNT 200 @@ -1602,6 +2219,7 @@ void AOTCodeCache::load_strings() { uint len = string_lengths[i]; _C_strings_s[i] = i; _C_strings_id[i] = i; + log_trace(aot, codecache, stringtable)("load_strings: _C_strings[%d] " INTPTR_FORMAT " '%s'", i, p2i(p), p); p += len; } assert((uint)(p - _C_strings_buf) <= strings_size, "(" INTPTR_FORMAT " - " INTPTR_FORMAT ") = %d > %d ", p2i(p), p2i(_C_strings_buf), (uint)(p - _C_strings_buf), strings_size); @@ -1621,6 +2239,7 @@ int AOTCodeCache::store_strings() { } for (int i = 0; i < _C_strings_used; i++) { const char* str = _C_strings[_C_strings_s[i]]; + log_trace(aot, codecache, stringtable)("store_strings: _C_strings[%d] " INTPTR_FORMAT " '%s'", i, p2i(str), str); uint len = (uint)strlen(str) + 1; length += len; assert(len < 1000, "big string: %s", str); @@ -1648,7 +2267,7 @@ const char* AOTCodeCache::add_C_string(const char* str) { } const char* AOTCodeAddressTable::add_C_string(const char* str) { - if (_extrs_complete) { + if (_extrs_complete || initializing_extrs) { // Check previous strings address for (int i = 0; i < _C_strings_count; i++) { if (_C_strings_in[i] == str) { @@ -1686,6 +2305,7 @@ int AOTCodeAddressTable::id_for_C_string(address str) { assert(id < _C_strings_used, "%d >= %d", id , _C_strings_used); return id; // Found recorded } + log_trace(aot, codecache, stringtable)("id_for_C_string: _C_strings[%d ==> %d] " INTPTR_FORMAT " '%s'", i, _C_strings_used, p2i(str), str); // Not found in recorded, add new id = _C_strings_used++; _C_strings_s[id] = i; @@ -1711,7 +2331,7 @@ static int search_address(address addr, address* table, uint length) { } address AOTCodeAddressTable::address_for_id(int idx) { - assert(_extrs_complete, "AOT Code Cache VM runtime addresses table is not complete"); + assert(_extrs_complete || initializing_extrs, "AOT Code Cache VM runtime addresses table is not complete"); if (idx == -1) { return (address)-1; } @@ -1728,15 +2348,9 @@ address AOTCodeAddressTable::address_for_id(int idx) { if (/* id >= _extrs_base && */ id < _extrs_length) { return _extrs_addr[id - _extrs_base]; } - if (id >= _stubs_base && id < _stubs_base + _stubs_length) { + if (id >= _stubs_base && id < _c_str_base) { return _stubs_addr[id - _stubs_base]; } - if (id >= _shared_blobs_base && id < _shared_blobs_base + _shared_blobs_length) { - return _shared_blobs_addr[id - _shared_blobs_base]; - } - if (id >= _C1_blobs_base && id < _C1_blobs_base + _C1_blobs_length) { - return _C1_blobs_addr[id - _C1_blobs_base]; - } if (id >= _c_str_base && id < (_c_str_base + (uint)_C_strings_count)) { return address_for_C_string(id - _c_str_base); } @@ -1745,7 +2359,7 @@ address AOTCodeAddressTable::address_for_id(int idx) { } int AOTCodeAddressTable::id_for_address(address addr, RelocIterator reloc, CodeBlob* code_blob) { - assert(_extrs_complete, "AOT Code Cache VM runtime addresses table is not complete"); + assert(_extrs_complete || initializing_extrs, "AOT Code Cache VM runtime addresses table is not complete"); int id = -1; if (addr == (address)-1) { // Static call stub has jump to itself return id; @@ -1754,15 +2368,24 @@ int AOTCodeAddressTable::id_for_address(address addr, RelocIterator reloc, CodeB BarrierSet* bs = BarrierSet::barrier_set(); bool is_const_card_table_base = !UseG1GC && !UseShenandoahGC && bs->is_a(BarrierSet::CardTableBarrierSet); guarantee(!is_const_card_table_base || addr != ci_card_table_address_const(), "sanity"); - + // fast path for stubs and external addresses + if (_hash_table != nullptr) { + int *result = _hash_table->get(addr); + if (result != nullptr) { + id = *result; + log_trace(aot, codecache)("Address " INTPTR_FORMAT " retrieved from AOT Code Cache address hash table with index '%d'", + p2i(addr), id); + return id; + } + } // Seach for C string id = id_for_C_string(addr); if (id >= 0) { return id + _c_str_base; } - if (StubRoutines::contains(addr)) { - // Search in stubs - id = search_address(addr, _stubs_addr, _stubs_length); + if (StubRoutines::contains(addr) || CodeCache::find_blob(addr) != nullptr) { + // Search for a matching stub entry + id = search_address(addr, _stubs_addr, _stubs_max); if (id < 0) { StubCodeDesc* desc = StubCodeDesc::desc_for(addr); if (desc == nullptr) { @@ -1774,51 +2397,39 @@ int AOTCodeAddressTable::id_for_address(address addr, RelocIterator reloc, CodeB return id + _stubs_base; } } else { - CodeBlob* cb = CodeCache::find_blob(addr); - if (cb != nullptr) { - // Search in code blobs - int id_base = _shared_blobs_base; - id = search_address(addr, _shared_blobs_addr, _blobs_max); - if (id < 0) { - assert(false, "Address " INTPTR_FORMAT " for Blob:%s is missing in AOT Code Cache addresses table", p2i(addr), cb->name()); + // Search in runtime functions + id = search_address(addr, _extrs_addr, _extrs_length); + if (id < 0) { + ResourceMark rm; + const int buflen = 1024; + char* func_name = NEW_RESOURCE_ARRAY(char, buflen); + int offset = 0; + if (os::dll_address_to_function_name(addr, func_name, buflen, &offset)) { + if (offset > 0) { + // Could be address of C string + uint dist = (uint)pointer_delta(addr, (address)os::init, 1); + log_debug(aot, codecache)("Address " INTPTR_FORMAT " (offset %d) for runtime target '%s' is missing in AOT Code Cache addresses table", + p2i(addr), dist, (const char*)addr); + assert(dist > (uint)(_all_max + MAX_STR_COUNT), "change encoding of distance"); + return dist; + } +#ifdef ASSERT + reloc.print_current_on(tty); + code_blob->print_on(tty); + code_blob->print_code_on(tty); + assert(false, "Address " INTPTR_FORMAT " for runtime target '%s+%d' is missing in AOT Code Cache addresses table", p2i(addr), func_name, offset); +#endif } else { - return id_base + id; +#ifdef ASSERT + reloc.print_current_on(tty); + code_blob->print_on(tty); + code_blob->print_code_on(tty); + os::find(addr, tty); + assert(false, "Address " INTPTR_FORMAT " for /('%s') is missing in AOT Code Cache addresses table", p2i(addr), (const char*)addr); +#endif } } else { - // Search in runtime functions - id = search_address(addr, _extrs_addr, _extrs_length); - if (id < 0) { - ResourceMark rm; - const int buflen = 1024; - char* func_name = NEW_RESOURCE_ARRAY(char, buflen); - int offset = 0; - if (os::dll_address_to_function_name(addr, func_name, buflen, &offset)) { - if (offset > 0) { - // Could be address of C string - uint dist = (uint)pointer_delta(addr, (address)os::init, 1); - log_debug(aot, codecache)("Address " INTPTR_FORMAT " (offset %d) for runtime target '%s' is missing in AOT Code Cache addresses table", - p2i(addr), dist, (const char*)addr); - assert(dist > (uint)(_all_max + MAX_STR_COUNT), "change encoding of distance"); - return dist; - } -#ifdef ASSERT - reloc.print_current_on(tty); - code_blob->print_on(tty); - code_blob->print_code_on(tty); - assert(false, "Address " INTPTR_FORMAT " for runtime target '%s+%d' is missing in AOT Code Cache addresses table", p2i(addr), func_name, offset); -#endif - } else { -#ifdef ASSERT - reloc.print_current_on(tty); - code_blob->print_on(tty); - code_blob->print_code_on(tty); - os::find(addr, tty); - assert(false, "Address " INTPTR_FORMAT " for /('%s') is missing in AOT Code Cache addresses table", p2i(addr), (const char*)addr); -#endif - } - } else { - return _extrs_base + id; - } + return _extrs_base + id; } } return id; @@ -1885,3 +2496,161 @@ void AOTCodeCache::print_on(outputStream* st) { } } } + +// methods for managing entries in multi-stub blobs + + +AOTStubData::AOTStubData(BlobId blob_id) : + _blob_id(blob_id), + _cached_blob(nullptr), + _stub_cnt(0), + _ranges(nullptr), + _flags(0) { + assert(StubInfo::is_stubgen(blob_id), + "AOTStubData expects a multi-stub blob not %s", + StubInfo::name(blob_id)); + + // we cannot save or restore preuniversestubs because the cache + // cannot be accessed before initialising the universe + if (blob_id == BlobId::stubgen_preuniverse_id) { + // invalidate any attempt to use this + _flags |= INVALID; + return; + } + if (AOTCodeCache::is_on()) { + // allow update of stub entry addresses + if (AOTCodeCache::is_using_stub()) { + // allow stub loading + _flags |= USING; + } + if (AOTCodeCache::is_dumping_stub()) { + // allow stub saving + _flags |= DUMPING; + } + // we need to track all the blob's entries + _stub_cnt = StubInfo::stub_count(_blob_id); + _ranges = NEW_C_HEAP_ARRAY(StubAddrRange, _stub_cnt, mtCode); + for (int i = 0; i < _stub_cnt; i++) { + _ranges[i].default_init(); + } + } +} + +bool AOTStubData::load_code_blob() { + assert(is_using(), "should not call"); + assert(!is_invalid() && _cached_blob == nullptr, "repeated init"); + _cached_blob = AOTCodeCache::load_code_blob(AOTCodeEntry::StubGenBlob, + _blob_id, + this); + if (_cached_blob == nullptr) { + set_invalid(); + return false; + } else { + return true; + } +} + +bool AOTStubData::store_code_blob(CodeBlob& new_blob, CodeBuffer *code_buffer) { + assert(is_dumping(), "should not call"); + assert(_cached_blob == nullptr, "should not be loading and storing!"); + if (!AOTCodeCache::store_code_blob(new_blob, + AOTCodeEntry::StubGenBlob, + _blob_id, this, code_buffer)) { + set_invalid(); + return false; + } else { + return true; + } +} + +address AOTStubData::load_archive_data(StubId stub_id, address& end, GrowableArray
* entries, GrowableArray
* extras) { + assert(StubInfo::blob(stub_id) == _blob_id, "sanity check"); + if (is_invalid()) { + return nullptr; + } + int idx = StubInfo::stubgen_offset_in_blob(_blob_id, stub_id); + assert(idx >= 0 && idx < _stub_cnt, "invalid index %d for stub count %d", idx, _stub_cnt); + // ensure we have a valid associated range + StubAddrRange &range = _ranges[idx]; + int base = range.start_index(); + if (base < 0) { +#ifdef DEBUG + // reset index so we can idenitfy which ones we failed to find + range.init_entry(-2, 0); +#endif + return nullptr; + } + int count = range.count(); + assert(base >= 0, "sanity"); + assert(count >= 2, "sanity"); + // first two saved addresses are start and end + address start = _address_array.at(base); + end = _address_array.at(base + 1); + assert(start != nullptr, "failed to load start address of stub %s", StubInfo::name(stub_id)); + assert(end != nullptr, "failed to load end address of stub %s", StubInfo::name(stub_id)); + assert(start < end, "start address %p should be less than end %p address for stub %s", start, end, StubInfo::name(stub_id)); + + int entry_count = StubInfo::entry_count(stub_id); + // the address count must at least include the stub start, end + // and secondary addresses + assert(count >= entry_count + 1, "stub %s requires %d saved addresses but only has %d", StubInfo::name(stub_id), entry_count + 1, count); + + // caller must retrieve secondary entries if and only if they exist + assert((entry_count == 1) == (entries == nullptr), "trying to retrieve wrong number of entries for stub %s", StubInfo::name(stub_id)); + int index = 2; + if (entries != nullptr) { + assert(entries->length() == 0, "non-empty array when retrieving entries for stub %s!", StubInfo::name(stub_id)); + while (index < entry_count + 1) { + address entry = _address_array.at(base + index++); + assert(entry == nullptr || (start < entry && entry < end), "entry address %p not in range (%p, %p) for stub %s", entry, start, end, StubInfo::name(stub_id)); + entries->append(entry); + } + } + // caller must retrieve extras if and only if they exist + assert((index < count) == (extras != nullptr), "trying to retrieve wrong number of extras for stub %s", StubInfo::name(stub_id)); + if (extras != nullptr) { + assert(extras->length() == 0, "non-empty array when retrieving extras for stub %s!", StubInfo::name(stub_id)); + while (index < count) { + address extra = _address_array.at(base + index++); + assert(extra == nullptr || (start <= extra && extra <= end), "extra address %p not in range (%p, %p) for stub %s", extra, start, end, StubInfo::name(stub_id)); + extras->append(extra); + } + } + + return start; +} + +void AOTStubData::store_archive_data(StubId stub_id, address start, address end, GrowableArray
* entries, GrowableArray
* extras) { + assert(StubInfo::blob(stub_id) == _blob_id, "sanity check"); + assert(start != nullptr, "start address cannot be null"); + assert(end != nullptr, "end address cannot be null"); + assert(start < end, "start address %p should be less than end %p address for stub %s", start, end, StubInfo::name(stub_id)); + int idx = StubInfo::stubgen_offset_in_blob(_blob_id, stub_id); + StubAddrRange& range = _ranges[idx]; + assert(range.start_index() == -1, "sanity"); + int base = _address_array.length(); + assert(base >= 0, "sanity"); + // first two saved addresses are start and end + _address_array.append(start); + _address_array.append(end); + // caller must save secondary entries if and only if they exist + assert((StubInfo::entry_count(stub_id) == 1) == (entries == nullptr), "trying to save wrong number of entries for stub %s", StubInfo::name(stub_id)); + if (entries != nullptr) { + assert(entries->length() == StubInfo::entry_count(stub_id) - 1, "incorrect entry count %d when saving entries for stub %s!", entries->length(), StubInfo::name(stub_id)); + for (int i = 0; i < entries->length(); i++) { + address entry = entries->at(i); + assert(entry == nullptr || (start < entry && entry < end), "entry address %p not in range (%p, %p) for stub %s", entry, start, end, StubInfo::name(stub_id)); + _address_array.append(entry); + } + } + // caller may wish to save extra addresses + if (extras != nullptr) { + for (int i = 0; i < extras->length(); i++) { + address extra = extras->at(i); + // handler range end may be end -- it gets restored as nullptr + assert(extra == nullptr || (start <= extra && extra <= end), "extra address %p not in range (%p, %p) for stub %s", extra, start, end, StubInfo::name(stub_id)); + _address_array.append(extra); + } + } + range.init_entry(base, _address_array.length() - base); +} diff --git a/src/hotspot/share/code/aotCodeCache.hpp b/src/hotspot/share/code/aotCodeCache.hpp index 179f131c639..c4ebe271767 100644 --- a/src/hotspot/share/code/aotCodeCache.hpp +++ b/src/hotspot/share/code/aotCodeCache.hpp @@ -28,6 +28,7 @@ #include "gc/shared/collectedHeap.hpp" #include "gc/shared/gc_globals.hpp" #include "runtime/stubInfo.hpp" +#include "utilities/hashTable.hpp" /* * AOT Code Cache collects code from Code Cache and corresponding metadata @@ -39,6 +40,7 @@ class CodeBuffer; class RelocIterator; class AOTCodeCache; +class AOTCodeReader; class AdapterBlob; class ExceptionBlob; class ImmutableOopMapSet; @@ -54,6 +56,7 @@ enum CompLevel : signed char; Fn(SharedBlob) \ Fn(C1Blob) \ Fn(C2Blob) \ + Fn(StubGenBlob) \ // Descriptor of AOT Code Cache's entry class AOTCodeEntry { @@ -115,48 +118,57 @@ public: address dumptime_content_start_addr() const { return _dumptime_content_start_addr; } static bool is_valid_entry_kind(Kind kind) { return kind > None && kind < Kind_count; } - static bool is_blob(Kind kind) { return kind == SharedBlob || kind == C1Blob || kind == C2Blob; } + static bool is_blob(Kind kind) { return kind == SharedBlob || kind == C1Blob || kind == C2Blob || kind == StubGenBlob; } + static bool is_single_stub_blob(Kind kind) { return kind == SharedBlob || kind == C1Blob || kind == C2Blob; } + static bool is_multi_stub_blob(Kind kind) { return kind == StubGenBlob; } static bool is_adapter(Kind kind) { return kind == Adapter; } }; +// we use a hash table to speed up translation of external addresses +// or stub addresses to their corresponding indexes when dumping stubs +// or nmethods to the AOT code cache. +class AOTCodeAddressHashTable : public HashTable< + address, + int, + 36137, // prime number + AnyObj::C_HEAP, + mtCode> {}; + // Addresses of stubs, blobs and runtime finctions called from compiled code. class AOTCodeAddressTable : public CHeapObj { private: address* _extrs_addr; address* _stubs_addr; - address* _shared_blobs_addr; - address* _C1_blobs_addr; uint _extrs_length; - uint _stubs_length; - uint _shared_blobs_length; - uint _C1_blobs_length; bool _extrs_complete; - bool _early_stubs_complete; - bool _shared_blobs_complete; - bool _early_c1_complete; - bool _complete; + bool _shared_stubs_complete; + bool _c1_stubs_complete; + bool _c2_stubs_complete; + bool _stubgen_stubs_complete; + AOTCodeAddressHashTable* _hash_table; + void hash_address(address addr, int idx); public: AOTCodeAddressTable() : _extrs_addr(nullptr), _stubs_addr(nullptr), - _shared_blobs_addr(nullptr), - _C1_blobs_addr(nullptr), _extrs_length(0), - _stubs_length(0), - _shared_blobs_length(0), - _C1_blobs_length(0), _extrs_complete(false), - _early_stubs_complete(false), - _shared_blobs_complete(false), - _early_c1_complete(false), - _complete(false) + _shared_stubs_complete(false), + _c1_stubs_complete(false), + _c2_stubs_complete(false), + _stubgen_stubs_complete(false), + _hash_table(nullptr) { } void init_extrs(); - void init_early_stubs(); - void init_shared_blobs(); - void init_early_c1(); + void init_extrs2(); + void add_stub_entry(EntryId entry_id, address entry); + void add_external_addresses(GrowableArray
& addresses) NOT_CDS_RETURN; + void set_shared_stubs_complete(); + void set_c1_stubs_complete(); + void set_c2_stubs_complete(); + void set_stubgen_stubs_complete(); const char* add_C_string(const char* str); int id_for_C_string(address str); address address_for_C_string(int idx); @@ -164,7 +176,98 @@ public: address address_for_id(int id); }; -#define AOTCODECACHE_CONFIGS_GENERIC_DO(do_var, do_fun) \ +// Auxiliary class used by AOTStubData to locate addresses owned by a +// stub in the _address_array. + +class StubAddrRange { +private: + // Index of the first address owned by a stub or -1 if none present + int _start_index; + // Total number of addresses owned by a stub, including in order: + // start address for stub code and first entry, (exclusive) end + // address for stub code, all secondary entry addresses, any + // auxiliary addresses + uint _naddr; + public: + StubAddrRange() : _start_index(-1), _naddr(0) {} + int start_index() { return _start_index; } + int count() { return _naddr; } + + void default_init() { + _start_index = -1; + _naddr = 0; + } + + void init_entry(int start_index, int naddr) { + _start_index = start_index; + _naddr = naddr; + } +}; + +// class used to save and restore details of stubs embedded in a +// multi-stub (StubGen) blob + +class AOTStubData : public StackObj { + friend class AOTCodeCache; + friend class AOTCodeReader; +private: + BlobId _blob_id; // must be a stubgen blob id + // whatever buffer blob was successfully loaded from the AOT cache + // following a call to load_code_blob or nullptr + CodeBlob *_cached_blob; + // Array of addresses owned by stubs. Each stub appends addresses to + // this array as a block, whether at the end of generation or at the + // end of restoration from the cache. The first two addresses in + // each block are the "start" and "end2 address of the stub. Any + // other visible addresses located within the range [start,end) + // follow, either extra entries, data addresses or SEGV-protected + // subrange start, end and handler addresses. In the special case + // that the SEGV handler address is the (external) common address + // handler the array will hold value nullptr. + GrowableArray
_address_array; + // count of how many stubs exist in the current blob (not all of + // which may actually be generated) + int _stub_cnt; + // array identifying range of entries in _address_array for each stub + // indexed by offset of stub in blob + StubAddrRange* _ranges; + + // flags indicating whether the AOT code cache is open and, if so, + // whether we are loading or storing stubs or have encountered any + // invalid stubs. + enum Flags { + USING = 1 << 0, // open and loading stubs + DUMPING = 1 << 1, // open and storing stubs + INVALID = 1 << 2, // found invalid stub when loading + }; + + uint32_t _flags; + + void set_invalid() { _flags |= INVALID; } + + StubAddrRange& get_range(int idx) const { return _ranges[idx]; } + GrowableArray
& address_array() { return _address_array; } + // accessor for entry/auxiliary addresses defaults to start entry +public: + AOTStubData(BlobId blob_id) NOT_CDS({}); + + ~AOTStubData() CDS_ONLY({FREE_C_HEAP_ARRAY(StubAddrRange, _ranges);}) NOT_CDS({}) + + bool is_using() CDS_ONLY({ return (_flags & USING) != 0; }) NOT_CDS_RETURN_(false); + bool is_dumping() CDS_ONLY({ return (_flags & DUMPING) != 0; }) NOT_CDS_RETURN_(false); + bool is_invalid() CDS_ONLY({ return (_flags & INVALID) != 0; }) NOT_CDS_RETURN_(false); + + BlobId blob_id() { return _blob_id; } + bool load_code_blob() NOT_CDS_RETURN_(true); + bool store_code_blob(CodeBlob& new_blob, CodeBuffer *code_buffer) NOT_CDS_RETURN_(true); + + address load_archive_data(StubId stub_id, address &end, GrowableArray
* entries = nullptr, GrowableArray
* extras = nullptr) NOT_CDS_RETURN_(nullptr); + void store_archive_data(StubId stub_id, address start, address end, GrowableArray
* entries = nullptr, GrowableArray
* extras = nullptr) NOT_CDS_RETURN; + + const AOTStubData* as_const() { return (const AOTStubData*)this; } +}; + +#define AOTCODECACHE_CONFIGS_GENERIC_DO(do_var, do_fun) \ do_var(int, AllocateInstancePrefetchLines) /* stubs and nmethods */ \ do_var(int, AllocatePrefetchDistance) /* stubs and nmethods */ \ do_var(int, AllocatePrefetchLines) /* stubs and nmethods */ \ @@ -301,17 +404,18 @@ protected: uint _entries_offset; // offset of AOTCodeEntry array describing entries uint _adapters_count; uint _shared_blobs_count; + uint _stubgen_blobs_count; uint _C1_blobs_count; uint _C2_blobs_count; Config _config; // must be the last element as there is trailing data stored immediately after Config public: void init(uint cache_size, - uint strings_count, uint strings_offset, - uint entries_count, uint entries_offset, - uint adapters_count, uint shared_blobs_count, - uint C1_blobs_count, uint C2_blobs_count, - uint cpu_features_offset) { + uint strings_count, uint strings_offset, + uint entries_count, uint entries_offset, + uint adapters_count, uint shared_blobs_count, + uint stubgen_blobs_count, uint C1_blobs_count, + uint C2_blobs_count, uint cpu_features_offset) { _version = AOT_CODE_VERSION; _cache_size = cache_size; _strings_count = strings_count; @@ -320,6 +424,7 @@ protected: _entries_offset = entries_offset; _adapters_count = adapters_count; _shared_blobs_count = shared_blobs_count; + _stubgen_blobs_count = stubgen_blobs_count; _C1_blobs_count = C1_blobs_count; _C2_blobs_count = C2_blobs_count; _config.record(cpu_features_offset); @@ -332,6 +437,7 @@ protected: uint entries_count() const { return _entries_count; } uint entries_offset() const { return _entries_offset; } uint adapters_count() const { return _adapters_count; } + uint stubgen_blobs_count() const { return _stubgen_blobs_count; } uint shared_blobs_count() const { return _shared_blobs_count; } uint C1_blobs_count() const { return _C1_blobs_count; } uint C2_blobs_count() const { return _C2_blobs_count; } @@ -381,6 +487,7 @@ private: void clear_lookup_failed() { _lookup_failed = false; } bool lookup_failed() const { return _lookup_failed; } + void add_stub_entry(EntryId entry_id, address entry) NOT_CDS_RETURN; public: AOTCodeCache(bool is_dumping, bool is_using); @@ -396,9 +503,12 @@ public: void load_strings(); int store_strings(); - static void init_early_stubs_table() NOT_CDS_RETURN; - static void init_shared_blobs_table() NOT_CDS_RETURN; - static void init_early_c1_table() NOT_CDS_RETURN; + static void set_shared_stubs_complete() NOT_CDS_RETURN; + static void set_c1_stubs_complete() NOT_CDS_RETURN ; + static void set_c2_stubs_complete() NOT_CDS_RETURN; + static void set_stubgen_stubs_complete() NOT_CDS_RETURN; + + void add_stub_entries(StubId stub_id, address start, GrowableArray
*entries = nullptr, int offset = -1) NOT_CDS_RETURN; address address_for_C_string(int idx) const { return _table->address_for_C_string(idx); } address address_for_id(int id) const { return _table->address_for_id(id); } @@ -418,22 +528,41 @@ public: bool finish_write(); - bool write_relocations(CodeBlob& code_blob); + bool write_relocations(CodeBlob& code_blob, RelocIterator& iter); bool write_oop_map_set(CodeBlob& cb); + bool write_stub_data(CodeBlob& blob, AOTStubData *stub_data); #ifndef PRODUCT bool write_asm_remarks(CodeBlob& cb); bool write_dbg_strings(CodeBlob& cb); #endif // PRODUCT +private: + // internal private API to save and restore blobs + static bool store_code_blob(CodeBlob& blob, + AOTCodeEntry::Kind entry_kind, + uint id, + const char* name, + AOTStubData* stub_data, + CodeBuffer* code_buffer) NOT_CDS_RETURN_(false); + + static CodeBlob* load_code_blob(AOTCodeEntry::Kind kind, + uint id, + const char* name, + AOTStubData* stub_data) NOT_CDS_RETURN_(nullptr); + +public: // save and restore API for non-enumerable code blobs static bool store_code_blob(CodeBlob& blob, AOTCodeEntry::Kind entry_kind, - uint id, const char* name) NOT_CDS_RETURN_(false); + uint id, + const char* name) NOT_CDS_RETURN_(false); static CodeBlob* load_code_blob(AOTCodeEntry::Kind kind, uint id, const char* name) NOT_CDS_RETURN_(nullptr); // save and restore API for enumerable code blobs + + // API for single-stub blobs static bool store_code_blob(CodeBlob& blob, AOTCodeEntry::Kind entry_kind, BlobId id) NOT_CDS_RETURN_(false); @@ -441,6 +570,22 @@ public: static CodeBlob* load_code_blob(AOTCodeEntry::Kind kind, BlobId id) NOT_CDS_RETURN_(nullptr); + // API for multi-stub blobs -- for use by class StubGenerator. + + static bool store_code_blob(CodeBlob& blob, + AOTCodeEntry::Kind kind, + BlobId id, + AOTStubData* stub_data, + CodeBuffer *code_buffer) NOT_CDS_RETURN_(false); + + static CodeBlob* load_code_blob(AOTCodeEntry::Kind kind, + BlobId id, + AOTStubData* stub_data) NOT_CDS_RETURN_(nullptr); + + static void publish_external_addresses(GrowableArray
& addresses) NOT_CDS_RETURN; + // publish all entries for a code blob in code cache address table + static void publish_stub_addresses(CodeBlob &code_blob, BlobId id, AOTStubData *stub_data) NOT_CDS_RETURN; + static uint store_entries_cnt() { if (is_on_for_dump()) { return cache()->_store_entries_cnt; @@ -462,9 +607,14 @@ private: return true; } public: + // marker used where an address offset needs to be stored for later + // retrieval and the address turns out to be null + static const uint NULL_ADDRESS_MARKER = UINT_MAX; + static AOTCodeCache* cache() { assert(_passed_init2, "Too early to ask"); return _cache; } static void initialize() NOT_CDS_RETURN; static void init2() NOT_CDS_RETURN; + static void init3() NOT_CDS_RETURN; static void dump() NOT_CDS_RETURN; static bool is_on() CDS_ONLY({ return cache() != nullptr; }) NOT_CDS_RETURN_(false); static bool is_on_for_use() CDS_ONLY({ return is_on() && _cache->for_use(); }) NOT_CDS_RETURN_(false); @@ -485,7 +635,7 @@ public: // Concurent AOT code reader class AOTCodeReader { private: - const AOTCodeCache* _cache; + AOTCodeCache* _cache; const AOTCodeEntry* _entry; const char* _load_buffer; // Loaded cached code buffer uint _read_position; // Position in _load_buffer @@ -502,13 +652,18 @@ private: // They should be set before calling it. const char* _name; address _reloc_data; + int _reloc_count; ImmutableOopMapSet* _oop_maps; + AOTCodeEntry::Kind _entry_kind; + int _id; + AOTStubData* _stub_data; AOTCodeEntry* aot_code_entry() { return (AOTCodeEntry*)_entry; } ImmutableOopMapSet* read_oop_map_set(); + void read_stub_data(CodeBlob* code_blob, AOTStubData *stub_data); - void fix_relocations(CodeBlob* code_blob); + void fix_relocations(CodeBlob* code_blob, RelocIterator& iter); #ifndef PRODUCT void read_asm_remarks(AsmRemarks& asm_remarks); void read_dbg_strings(DbgStrings& dbg_strings); @@ -517,7 +672,7 @@ private: public: AOTCodeReader(AOTCodeCache* cache, AOTCodeEntry* entry); - CodeBlob* compile_code_blob(const char* name); + CodeBlob* compile_code_blob(const char* name, AOTCodeEntry::Kind entry_kind, int id, AOTStubData* stub_data = nullptr); void restore(CodeBlob* code_blob); }; diff --git a/src/hotspot/share/gc/z/zBarrierSetAssembler.hpp b/src/hotspot/share/gc/z/zBarrierSetAssembler.hpp index bcc757d6132..7b15813678a 100644 --- a/src/hotspot/share/gc/z/zBarrierSetAssembler.hpp +++ b/src/hotspot/share/gc/z/zBarrierSetAssembler.hpp @@ -34,6 +34,9 @@ public: static Address load_bad_mask_from_jni_env(Register env); static Address mark_bad_mask_from_jni_env(Register env); + + virtual void register_reloc_addresses(GrowableArray
&entries, int begin, int count) { } + virtual void retrieve_reloc_addresses(address start, address end, GrowableArray
&entries) { } }; // Needs to be included after definition of ZBarrierSetAssemblerBase diff --git a/src/hotspot/share/opto/runtime.cpp b/src/hotspot/share/opto/runtime.cpp index 0d2dbb813bd..c01e8578e43 100644 --- a/src/hotspot/share/opto/runtime.cpp +++ b/src/hotspot/share/opto/runtime.cpp @@ -24,6 +24,7 @@ #include "classfile/vmClasses.hpp" #include "classfile/vmSymbols.hpp" +#include "code/aotCodeCache.hpp" #include "code/codeCache.hpp" #include "code/compiledIC.hpp" #include "code/nmethod.hpp" @@ -154,7 +155,8 @@ static bool check_compiled_frame(JavaThread* thread) { bool OptoRuntime::generate(ciEnv* env) { C2_STUBS_DO(GEN_C2_BLOB, GEN_C2_STUB) - + // disallow any further c2 stub generation + AOTCodeCache::set_c2_stubs_complete(); return true; } diff --git a/src/hotspot/share/prims/downcallLinker.hpp b/src/hotspot/share/prims/downcallLinker.hpp index 2c2cf053033..519e84281ce 100644 --- a/src/hotspot/share/prims/downcallLinker.hpp +++ b/src/hotspot/share/prims/downcallLinker.hpp @@ -72,7 +72,7 @@ public: bool needs_return_buffer, int captured_state_mask, bool needs_transition) - : StubCodeGenerator(buffer, PrintMethodHandleStubs), + : StubCodeGenerator(buffer, PrintMethodHandleStubs), _signature(signature), _num_args(num_args), _ret_bt(ret_bt), diff --git a/src/hotspot/share/runtime/init.cpp b/src/hotspot/share/runtime/init.cpp index adc49f84358..d820968495e 100644 --- a/src/hotspot/share/runtime/init.cpp +++ b/src/hotspot/share/runtime/init.cpp @@ -70,6 +70,10 @@ void VM_Version_init(); void icache_init2(); void initialize_stub_info(); // must precede all blob/stub generation void preuniverse_stubs_init(); + +#if INCLUDE_CDS +void stubs_AOTAddressTable_init(); +#endif // INCLUDE_CDS void initial_stubs_init(); jint universe_init(); // depends on codeCache_init and preuniverse_stubs_init @@ -149,13 +153,19 @@ jint init_globals() { AOTCodeCache::init2(); // depends on universe_init, must be before initial_stubs_init AsyncLogWriter::initialize(); +#if INCLUDE_CDS + stubs_AOTAddressTable_init(); // publish external addresses used by stubs + // depends on AOTCodeCache::init2 +#endif // INCLUDE_CDS initial_stubs_init(); // stubgen initial stub routines // stack overflow exception blob is referenced by the interpreter - AOTCodeCache::init_early_stubs_table(); // need this after stubgen initial stubs and before shared runtime initial stubs SharedRuntime::generate_initial_stubs(); gc_barrier_stubs_init(); // depends on universe_init, must be before interpreter_init continuations_init(); // must precede continuation stub generation - continuation_stubs_init(); // depends on continuations_init + AOTCodeCache::init3(); // depends on stubs_AOTAddressTable_init + // and continuations_init and must + // precede continuation stub generation + continuation_stubs_init(); // depends on continuations_init and AOTCodeCache::init3 #if INCLUDE_JFR SharedRuntime::generate_jfr_stubs(); #endif @@ -164,7 +174,6 @@ jint init_globals() { InterfaceSupport_init(); VMRegImpl::set_regName(); // need this before generate_stubs (for printing oop maps). SharedRuntime::generate_stubs(); - AOTCodeCache::init_shared_blobs_table(); // need this after generate_stubs SharedRuntime::init_adapter_library(); // do this after AOTCodeCache::init_shared_blobs_table return JNI_OK; } diff --git a/src/hotspot/share/runtime/sharedRuntime.cpp b/src/hotspot/share/runtime/sharedRuntime.cpp index 917ff5b4545..352c90f913b 100644 --- a/src/hotspot/share/runtime/sharedRuntime.cpp +++ b/src/hotspot/share/runtime/sharedRuntime.cpp @@ -177,6 +177,11 @@ void SharedRuntime::generate_stubs() { CAST_FROM_FN_PTR(address, SafepointSynchronize::handle_polling_page_exception)); generate_deopt_blob(); + +#if INCLUDE_CDS + // disallow any further generation of runtime stubs + AOTCodeCache::set_shared_stubs_complete(); +#endif // INCLUDE_CDS } void SharedRuntime::init_adapter_library() { diff --git a/src/hotspot/share/runtime/stubCodeGenerator.cpp b/src/hotspot/share/runtime/stubCodeGenerator.cpp index 43250c004ca..45e40f4a754 100644 --- a/src/hotspot/share/runtime/stubCodeGenerator.cpp +++ b/src/hotspot/share/runtime/stubCodeGenerator.cpp @@ -23,6 +23,7 @@ */ #include "asm/macroAssembler.inline.hpp" +#include "code/aotCodeCache.hpp" #include "code/codeCache.hpp" #include "compiler/disassembler.hpp" #include "oops/oop.inline.hpp" @@ -30,7 +31,9 @@ #include "prims/jvmtiExport.hpp" #include "runtime/stubCodeGenerator.hpp" #include "runtime/stubRoutines.hpp" - +#if INCLUDE_ZGC +#include "gc/z/zBarrierSetAssembler.hpp" +#endif // INCLUDE_ZGC // Implementation of StubCodeDesc @@ -69,14 +72,16 @@ void StubCodeDesc::print() const { print_on(tty); } StubCodeGenerator::StubCodeGenerator(CodeBuffer* code, bool print_code) { _masm = new MacroAssembler(code); _blob_id = BlobId::NO_BLOBID; + _stub_data = nullptr; _print_code = PrintStubCode || print_code; } -StubCodeGenerator::StubCodeGenerator(CodeBuffer* code, BlobId blob_id, bool print_code) { +StubCodeGenerator::StubCodeGenerator(CodeBuffer* code, BlobId blob_id, AOTStubData* stub_data, bool print_code) { assert(StubInfo::is_stubgen(blob_id), "not a stubgen blob %s", StubInfo::name(blob_id)); _masm = new MacroAssembler(code); _blob_id = blob_id; + _stub_data = stub_data; _print_code = PrintStubCode || print_code; } @@ -91,11 +96,92 @@ StubCodeGenerator::~StubCodeGenerator() { #endif } +void StubCodeGenerator::setup_code_desc(const char* name, address start, address end, bool loaded_from_cache) { + StubCodeDesc* cdesc = new StubCodeDesc("StubRoutines", name, start, end); + cdesc->set_disp(uint(start - _masm->code_section()->outer()->insts_begin())); + if (loaded_from_cache) { + cdesc->set_loaded_from_cache(); + } + print_stub_code_desc(cdesc); + // copied from ~StubCodeMark() + Forte::register_stub(cdesc->name(), cdesc->begin(), cdesc->end()); + if (JvmtiExport::should_post_dynamic_code_generated()) { + JvmtiExport::post_dynamic_code_generated(cdesc->name(), cdesc->begin(), cdesc->end()); + } +} + +// Helper used to restore ranges and handler addresses restored from +// AOT cache. Expects entries to contain 3 * count addresses beginning +// at offset begin which identify start of range, end of range and +// address of handler pc. start and end of range may not be null. +// handler pc may be null in which case it defaults to the +// default_handler. + +void StubCodeGenerator::register_unsafe_access_handlers(GrowableArray
&entries, int begin, int count) { + for (int i = 0; i < count; i++) { + int offset = begin + 3 * i; + address start = entries.at(offset); + address end = entries.at(offset + 1); + address handler = entries.at(offset + 2); + assert(start != nullptr, "sanity"); + assert(end != nullptr, "sanity"); + if (handler == nullptr) { + assert(UnsafeMemoryAccess::common_exit_stub_pc() != nullptr, + "default unsafe handler must be set before registering unsafe rgeionwiht no handler!"); + handler = UnsafeMemoryAccess::common_exit_stub_pc(); + } + UnsafeMemoryAccess::add_to_table(start, end, handler); + } +} + +// Helper used to retrieve ranges and handler addresses registered +// during generation of the stub which spans [start, end) in order to +// allow them to be saved to an AOT cache. +void StubCodeGenerator::retrieve_unsafe_access_handlers(address start, address end, GrowableArray
&entries) { + UnsafeMemoryAccess::collect_entries(start, end, entries); +} + +#if INCLUDE_ZGC +// Helper used to restore ZGC pointer colouring relocation addresses +// retrieved from the AOT cache. +void StubCodeGenerator::register_reloc_addresses(GrowableArray
&entries, int begin, int count) { + LogTarget(Trace, aot, codecache, stubs) lt; + if (lt.is_enabled()) { + LogStream ls(lt); + for (int i = begin; i < count; i++) { + ls.print_cr("Registered reloc address " INTPTR_FORMAT, p2i(entries.at(i))); + } + } + ZBarrierSetAssembler *zbs = (ZBarrierSetAssembler*)BarrierSet::barrier_set()->barrier_set_assembler(); + zbs->register_reloc_addresses(entries, begin, count); +} + +// Helper used to retrieve ranges and handler addresses registered +// during generation of the stub which spans [start, end) in order to +// allow them to be saved to an AOT cache. +void StubCodeGenerator::retrieve_reloc_addresses(address start, address end, GrowableArray
&entries) { + int l = entries.length(); + ZBarrierSetAssembler *zbs = (ZBarrierSetAssembler*)BarrierSet::barrier_set()->barrier_set_assembler(); + zbs->retrieve_reloc_addresses(start, end, entries); + LogTarget(Trace, aot, codecache, stubs) lt; + if (lt.is_enabled()) { + LogStream ls(lt); + for (int i = l; i < entries.length(); i++) { + ls.print_cr("retrieved reloc address " INTPTR_FORMAT, p2i(entries.at(i))); + } + } +} +#endif // INCLUDE_ZGC + void StubCodeGenerator::stub_prolog(StubCodeDesc* cdesc) { // default implementation - do nothing } void StubCodeGenerator::stub_epilog(StubCodeDesc* cdesc) { + print_stub_code_desc(cdesc); +} + +void StubCodeGenerator::print_stub_code_desc(StubCodeDesc* cdesc) { LogTarget(Debug, stubs) lt; if (lt.is_enabled()) { LogStream ls(lt); @@ -119,6 +205,52 @@ void StubCodeGenerator::stub_epilog(StubCodeDesc* cdesc) { } } +address StubCodeGenerator::load_archive_data(StubId stub_id, GrowableArray
*entries, GrowableArray
* extras) { + // punt to stub data if it exists and is not for dumping + if (_stub_data == nullptr || _stub_data->is_dumping()) { + return nullptr; + } + // punt to stub data + address start, end; + start = _stub_data->load_archive_data(stub_id, end, entries, extras); + + if (start != nullptr) { + setup_code_desc(StubInfo::name(stub_id), start, end, true); + } + + return start; +} + +void StubCodeGenerator::store_archive_data(StubId stub_id, address start, address end, GrowableArray
* entries, GrowableArray
* extras) { + // punt to stub data if we have any + if (_stub_data != nullptr) { + _stub_data->store_archive_data(stub_id, start, end, entries, extras); + } +} + +void StubCodeGenerator::print_statistics_on(outputStream* st) { + st->print_cr("StubRoutines Stubs:"); + st->print_cr(" Initial stubs: %d", StubInfo::stub_count(BlobId::stubgen_initial_id)); + st->print_cr(" Continuation stubs: %d", StubInfo::stub_count(BlobId::stubgen_continuation_id)); + st->print_cr(" Compiler stubs: %d", StubInfo::stub_count(BlobId::stubgen_compiler_id)); + st->print_cr(" Final stubs: %d", StubInfo::stub_count(BlobId::stubgen_final_id)); + + int emitted = 0; + int loaded_from_cache = 0; + + StubCodeDesc* scd = StubCodeDesc::first(); + while (scd != nullptr) { + if (!strcmp(scd->group(), "StubRoutines")) { + emitted += 1; + if (scd->loaded_from_cache()) { + loaded_from_cache += 1; + } + } + scd = StubCodeDesc::next(scd); + } + st->print_cr("Total stubroutines stubs emitted: %d (generated=%d, loaded from cache=%d)", emitted, emitted - loaded_from_cache, loaded_from_cache); +} + #ifdef ASSERT void StubCodeGenerator::verify_stub(StubId stub_id) { assert(StubRoutines::stub_to_blob(stub_id) == blob_id(), "wrong blob %s for generation of stub %s", StubRoutines::get_blob_name(blob_id()), StubRoutines::get_stub_name(stub_id)); diff --git a/src/hotspot/share/runtime/stubCodeGenerator.hpp b/src/hotspot/share/runtime/stubCodeGenerator.hpp index 7d8944c85ea..958fa76543b 100644 --- a/src/hotspot/share/runtime/stubCodeGenerator.hpp +++ b/src/hotspot/share/runtime/stubCodeGenerator.hpp @@ -26,6 +26,7 @@ #define SHARE_RUNTIME_STUBCODEGENERATOR_HPP #include "asm/assembler.hpp" +#include "code/aotCodeCache.hpp" #include "memory/allocation.hpp" #include "runtime/stubInfo.hpp" @@ -48,6 +49,7 @@ class StubCodeDesc: public CHeapObj { address _begin; // points to the first byte of the stub code (included) address _end; // points to the first byte after the stub code (excluded) uint _disp; // Displacement relative base address in buffer. + bool _loaded_from_cache; friend class StubCodeMark; friend class StubCodeGenerator; @@ -65,6 +67,8 @@ class StubCodeDesc: public CHeapObj { void set_disp(uint disp) { _disp = disp; } + void set_loaded_from_cache() { _loaded_from_cache = true; } + public: static StubCodeDesc* first() { return _list; } static StubCodeDesc* next(StubCodeDesc* desc) { return desc->_next; } @@ -81,6 +85,7 @@ class StubCodeDesc: public CHeapObj { _end = end; _disp = 0; _list = this; + _loaded_from_cache = false; }; static void freeze(); @@ -93,12 +98,11 @@ class StubCodeDesc: public CHeapObj { uint disp() const { return _disp; } int size_in_bytes() const { return pointer_delta_as_int(_end, _begin); } bool contains(address pc) const { return _begin <= pc && pc < _end; } + bool loaded_from_cache() const { return _loaded_from_cache; } void print_on(outputStream* st) const; void print() const; }; -// forward declare blob and stub id enums - // The base class for all stub-generating code generators. // Provides utility functions. @@ -108,10 +112,20 @@ class StubCodeGenerator: public StackObj { BlobId _blob_id; protected: MacroAssembler* _masm; + AOTStubData* _stub_data; - public: + void setup_code_desc(const char* name, address start, address end, bool loaded_from_cache); + // unsafe handler management + void register_unsafe_access_handlers(GrowableArray
&entries, int begin, int count); + void retrieve_unsafe_access_handlers(address start, address end, GrowableArray
&entries); +#if INCLUDE_ZGC + void register_reloc_addresses(GrowableArray
&entries, int begin, int count); + void retrieve_reloc_addresses(address start, address end, GrowableArray
&entries); +#endif // INCLUDE_ZGC + +public: StubCodeGenerator(CodeBuffer* code, bool print_code = false); - StubCodeGenerator(CodeBuffer* code, BlobId blob_id, bool print_code = false); + StubCodeGenerator(CodeBuffer* code, BlobId blob_id, AOTStubData* stub_data = nullptr, bool print_code = false); ~StubCodeGenerator(); MacroAssembler* assembler() const { return _masm; } @@ -120,9 +134,59 @@ class StubCodeGenerator: public StackObj { virtual void stub_prolog(StubCodeDesc* cdesc); // called by StubCodeMark constructor virtual void stub_epilog(StubCodeDesc* cdesc); // called by StubCodeMark destructor + void print_stub_code_desc(StubCodeDesc* cdesc); + + static void print_statistics_on(outputStream* st); + + // load_archive_data should be called before generating the stub + // identified by stub_id. If AOT caching of stubs is enabled and the + // stubis found then the address of the stub's first and, possibly, + // only entry is returned and the caller should use it instead of + // generating thestub. Otherwise a null address is returned and the + // caller should proceed to generate the stub. + // + // store_archive_data should be called when a stub has been + // successfully generated into the current blob irrespctive of + // whether the current JVM is generating or consuming an AOT archive + // (the caller should not check for either case). When generating an + // archive the stub entry and end addresses are recorded for storage + // along with the current blob and also to allow rences to the stub + // from other stubs or from compiled Java methods can be detected + // and marked as requiring relocation. When consuming an archive the + // stub entry address is still inorer to identify it as a relocation + // target. When no archive is in use the call has no side effects. + // + // start and end identify the inclusive start and exclusive end + // address for stub code and must lie in the current blob's code + // range. Stubs presented via this interface must declare at least + // one entry and start is always taken to be the first entry. + // + // Optional arrays entries and extras store other addresses of + // interest all of which must either lie in the interval (start, + // end) or be nullptr (verified by load and store methods). + // + // entries lists secondary entries for the stub each of which must + // match a corresponding entry declaration for the stub (entry count + // verified by load and store methods). Null entry addresses are + // allowed when an architecture does not require a specific entry + // but may not vary from one run to the next. If the cache is in use + // at a store (for loading or saving code) then non-null entry + // addresses are entered into the AOT cache stub address table + // allowing references to them from other stubs or nmethods to be + // relocated. + // + // extras lists other non-entry stub addresses of interest such as + // memory protection ranges and associated handler addresses + // (potentially including a null address). These do do not need to + // be declared as entries and their number and meaning may vary + // according to the architecture. + + address load_archive_data(StubId stub_id, GrowableArray
*entries = nullptr, GrowableArray
* extras = nullptr); + void store_archive_data(StubId stub_id, address start, address end, GrowableArray
*entries = nullptr, GrowableArray
* extras = nullptr); #ifdef ASSERT void verify_stub(StubId stub_id); #endif + }; // Stack-allocated helper class used to associate a stub code with a name. diff --git a/src/hotspot/share/runtime/stubDeclarations.hpp b/src/hotspot/share/runtime/stubDeclarations.hpp index 7dc0f2d2bed..d1ce378ee20 100644 --- a/src/hotspot/share/runtime/stubDeclarations.hpp +++ b/src/hotspot/share/runtime/stubDeclarations.hpp @@ -952,9 +952,15 @@ do_entry_init(final, arrayof_jlong_arraycopy, \ arrayof_jlong_arraycopy, arrayof_jlong_arraycopy, \ StubRoutines::arrayof_jlong_copy) \ + do_entry(final, arrayof_jlong_arraycopy, \ + arrayof_jlong_arraycopy_nopush, \ + arrayof_jlong_arraycopy_nopush) \ do_stub(final, arrayof_oop_arraycopy) \ do_entry_init(final, arrayof_oop_arraycopy, arrayof_oop_arraycopy, \ arrayof_oop_arraycopy, StubRoutines::arrayof_oop_copy) \ + do_entry(final, arrayof_oop_arraycopy, \ + arrayof_oop_arraycopy_nopush, \ + arrayof_oop_arraycopy_nopush) \ do_stub(final, arrayof_oop_arraycopy_uninit) \ do_entry_init(final, arrayof_oop_arraycopy_uninit, \ arrayof_oop_arraycopy_uninit, \ diff --git a/src/hotspot/share/runtime/stubInfo.cpp b/src/hotspot/share/runtime/stubInfo.cpp index ee90631145a..c07c0298f2b 100644 --- a/src/hotspot/share/runtime/stubInfo.cpp +++ b/src/hotspot/share/runtime/stubInfo.cpp @@ -1087,6 +1087,15 @@ int StubInfo::stubgen_offset(StubId id) { return local_offset(StubGroup::STUBGEN, id); } +int StubInfo::stubgen_offset_in_blob(BlobId blob_id, StubId id) { + assert(blob(id) == blob_id, "sanity!"); + StubGroup group = StubGroup::STUBGEN; + assert(stubgroup(blob_id) == group, "sanity"); + StubId base_id = stub_base(blob_id); + assert(base_id != StubId::NO_STUBID, "sanity"); + return local_offset(group, id) - local_offset(group, base_id); +} + // initialization function called to populate blob. stub and entry // tables. this must be called before any stubs are generated void initialize_stub_info() { diff --git a/src/hotspot/share/runtime/stubInfo.hpp b/src/hotspot/share/runtime/stubInfo.hpp index 9ed6e0cb9f9..447f7d3a582 100644 --- a/src/hotspot/share/runtime/stubInfo.hpp +++ b/src/hotspot/share/runtime/stubInfo.hpp @@ -669,6 +669,11 @@ public: static int c1_offset(StubId id); static int c2_offset(StubId id); static int stubgen_offset(StubId id); + + // Convert a stub id to a unique, zero-based offset in the range of + // stub ids for a given blob in the stubgen stub group. + + static int stubgen_offset_in_blob(BlobId blob_id, StubId id); }; diff --git a/src/hotspot/share/runtime/stubRoutines.cpp b/src/hotspot/share/runtime/stubRoutines.cpp index 56d832d3fef..0bc71c65471 100644 --- a/src/hotspot/share/runtime/stubRoutines.cpp +++ b/src/hotspot/share/runtime/stubRoutines.cpp @@ -102,8 +102,7 @@ BlobId StubRoutines::stub_to_blob(StubId id) { // Initialization -extern void StubGenerator_generate(CodeBuffer* code, BlobId blob_id); // only interface to generators - +extern void StubGenerator_generate(CodeBuffer* code, BlobId blob_id, AOTStubData* stub_data); // only interface to generators void UnsafeMemoryAccess::create_table(int max_size) { UnsafeMemoryAccess::_table = new UnsafeMemoryAccess[max_size]; UnsafeMemoryAccess::_table_max_length = max_size; @@ -154,7 +153,8 @@ void UnsafeMemoryAccess::collect_entries(address range_start, address range_end, if (e._error_exit_pc != _common_exit_stub_pc) { entries.append(e._error_exit_pc); } else { - // an address outside the stub must be the common exit stub address + // an address outside the stub must be the common exit stub + // address which is marked with a null address entries.append(nullptr); } } @@ -169,6 +169,33 @@ static BufferBlob* initialize_stubs(BlobId blob_id, assert(StubInfo::is_stubgen(blob_id), "not a stubgen blob %s", StubInfo::name(blob_id)); ResourceMark rm; TraceTime timer(timer_msg, TRACETIME_LOG(Info, startuptime)); + // If we are loading stubs we need to check if we can retrieve a + // blob and/or an associated archived stub descriptor from the + // AOTCodeCache. If we are storing stubs we need to create a blob + // but we still need a stub data descriptor to fill in during + // generation. + AOTStubData stub_data(blob_id); + AOTStubData* stub_data_p = nullptr; + LogTarget(Info, stubs) lt; + + if (code_size > 0 && stub_data.is_using()) { + // AOTCodeEntry tracks and logs status of any cached blob + bool loaded = stub_data.load_code_blob(); + if (loaded) { + if (lt.is_enabled()) { + LogStream ls(lt); + ls.print_cr("Found blob %s in AOT cache", StubInfo::name(blob_id)); + } + stub_data_p = &stub_data; + } + } else if (stub_data.is_dumping()) { + stub_data_p = &stub_data; + } + + // Even if we managed to load a blob from the AOT cache we still + // need to allocate a code blob and associated buffer. The AOT blob + // may not include all the stubs we need for this runtime. + // Add extra space for large CodeEntryAlignment int size = code_size + CodeEntryAlignment * max_aligned_stubs; BufferBlob* stubs_code = BufferBlob::create(buffer_name, size); @@ -178,6 +205,10 @@ static BufferBlob* initialize_stubs(BlobId blob_id, // In that case we can tolerate an allocation failure because the // compiler will have been shut down and we have no need of the // blob. + // TODO: Ideally we would still like to try to use any AOT cached + // blob here but we don't have a fallback if we find that it is + // missing stubs we need so for now we exit. This should only + // happen in cases where we have a very small code cache. if (Thread::current()->is_Compiler_thread()) { assert(blob_id == BlobId::stubgen_compiler_id, "sanity"); assert(DelayCompilerStubsGeneration, "sanity"); @@ -187,10 +218,12 @@ static BufferBlob* initialize_stubs(BlobId blob_id, vm_exit_out_of_memory(code_size, OOM_MALLOC_ERROR, "CodeCache: no room for %s", buffer_name); } CodeBuffer buffer(stubs_code); - StubGenerator_generate(&buffer, blob_id); + short buffer_locs[20]; + buffer.insts()->initialize_shared_locs((relocInfo*)buffer_locs, + sizeof(buffer_locs)/sizeof(relocInfo)); + StubGenerator_generate(&buffer, blob_id, stub_data_p); if (code_size == 0) { assert(buffer.insts_size() == 0, "should not write into buffer when bob size declared as 0"); - LogTarget(Info, stubs) lt; if (lt.is_enabled()) { LogStream ls(lt); ls.print_cr("%s\t not generated", buffer_name); @@ -203,7 +236,35 @@ static BufferBlob* initialize_stubs(BlobId blob_id, "increase %s, code_size: %d, used: %d, free: %d", assert_msg, code_size, buffer.total_content_size(), buffer.insts_remaining()); - LogTarget(Info, stubs) lt; + if (stub_data.is_using()) { + // we generated some new entries so republish all entries TODO - + // ensure we publish collect and publish the preuniverse stubs but + // don't try to save them + AOTCodeCache::publish_stub_addresses(*stubs_code, blob_id, &stub_data); + if (lt.is_enabled()) { + LogStream ls(lt); + ls.print_cr("Republished entries for blob '%s'", buffer_name); + } + } else if (stub_data.is_dumping()) { + // save the blob and publihs the entry addresses + if (stub_data.store_code_blob(*stubs_code, &buffer)) { + if (lt.is_enabled()) { + LogStream ls(lt); + ls.print_cr("Stored blob '%s' to Startup Code Cache", buffer_name); + } + } else { + if (lt.is_enabled()) { + LogStream ls(lt); + ls.print_cr("Failed to store blob '%s' to Startup Code Cache", buffer_name); + } + } + } + + // close off recording of any further stubgen generation + if (blob_id == BlobId::stubgen_final_id) { + AOTCodeCache::set_stubgen_stubs_complete(); + } + if (lt.is_enabled()) { LogStream ls(lt); ls.print_cr("%s\t [" INTPTR_FORMAT ", " INTPTR_FORMAT "] used: %d, free: %d", @@ -214,6 +275,8 @@ static BufferBlob* initialize_stubs(BlobId blob_id, return stubs_code; } +// per blob initializer methods StubRoutines::initialize_xxx_stubs() + #define DEFINE_BLOB_INIT_METHOD(blob_name) \ void StubRoutines::initialize_ ## blob_name ## _stubs() { \ if (STUBGEN_BLOB_FIELD_NAME(blob_name) == nullptr) { \ @@ -234,6 +297,7 @@ STUBGEN_BLOBS_DO(DEFINE_BLOB_INIT_METHOD) #undef DEFINE_BLOB_INIT_METHOD +// external driver API functions for per blob init: xxx_stubs_init() #define DEFINE_BLOB_INIT_FUNCTION(blob_name) \ void blob_name ## _stubs_init() { \ @@ -244,11 +308,18 @@ STUBGEN_BLOBS_DO(DEFINE_BLOB_INIT_FUNCTION) #undef DEFINE_BLOB_INIT_FUNCTION + +#if INCLUDE_CDS +// non-generated external API init driver function + +void stubs_AOTAddressTable_init() { StubRoutines::init_AOTAddressTable(); } +#endif // INCLUDE_CDS + /* - * we generate the underlying driver method but this wrapper is needed - * to perform special handling depending on where the compiler init - * gets called from. it ought to be possible to remove this at some - * point and have a determinate ordered init. + * we generate the underlying driver function compiler_stubs_init() + * but this wrapper is needed to perform special handling depending on + * where the compiler init gets called from. it ought to be possible + * to remove this at some point and have a determinate ordered init. */ void compiler_stubs_init(bool in_compiler_thread) { diff --git a/src/hotspot/share/runtime/stubRoutines.hpp b/src/hotspot/share/runtime/stubRoutines.hpp index 97e3e46b870..894bd47faab 100644 --- a/src/hotspot/share/runtime/stubRoutines.hpp +++ b/src/hotspot/share/runtime/stubRoutines.hpp @@ -112,6 +112,8 @@ class UnsafeMemoryAccess : public CHeapObj { address _end_pc; address _error_exit_pc; public: + // each table entry requires 3 addresses + static const int COLUMN_COUNT = 3; static address _common_exit_stub_pc; static UnsafeMemoryAccess* _table; static int _table_length; @@ -130,6 +132,7 @@ class UnsafeMemoryAccess : public CHeapObj { static UnsafeMemoryAccess* add_to_table(address start_pc, address end_pc, address error_exit_pc) { guarantee(_table_length < _table_max_length, "Incorrect UnsafeMemoryAccess::_table_max_length"); UnsafeMemoryAccess* entry = &_table[_table_length]; + assert(start_pc != nullptr, "invalid start address"); entry->set_start_pc(start_pc); entry->set_end_pc(end_pc); entry->set_error_exit_pc(error_exit_pc); @@ -283,6 +286,11 @@ public: static BlobId stub_to_blob(StubId id); #endif +#if INCLUDE_CDS + // AOT Initalization -- implementation is arch-specific + static void init_AOTAddressTable(); +#endif // INCLUDE_CDS + // Debugging static jint verify_oop_count() { return _verify_oop_count; } static jint* verify_oop_count_addr() { return &_verify_oop_count; } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeFlags.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeFlags.java index 761c2c5382d..d3c6a23efa0 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeFlags.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeFlags.java @@ -23,7 +23,8 @@ */ /** - * @test + * @test id=default_gc + * @requires vm.gc != "Z" * @summary Sanity test of combinations of the AOT Code Caching diagnostic flags * @requires vm.cds.supports.aot.code.caching * @requires vm.compiler1.enabled & vm.compiler2.enabled @@ -38,7 +39,64 @@ * JavacBenchApp$ClassFile * JavacBenchApp$FileManager * JavacBenchApp$SourceFile - * @run driver AOTCodeFlags + * @run driver/timeout=1500 AOTCodeFlags + */ +/** + * @test id=Z + * @requires vm.gc.Z + * @summary Sanity test of combinations of the AOT Code Caching diagnostic flags + * @requires vm.cds.supports.aot.code.caching + * @requires vm.compiler1.enabled & vm.compiler2.enabled + * @comment Both C1 and C2 JIT compilers are required because the test verifies + * compiler's runtime blobs generation. + * @requires vm.opt.VerifyOops == null | vm.opt.VerifyOops == false + * @comment VerifyOops flag switch off AOT code generation. Skip it. + * @library /test/lib /test/setup_aot + * @build AOTCodeFlags JavacBenchApp + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app.jar + * JavacBenchApp + * JavacBenchApp$ClassFile + * JavacBenchApp$FileManager + * JavacBenchApp$SourceFile + * @run driver/timeout=1500 AOTCodeFlags Z + */ +/** + * @test id=shenandoah + * @requires vm.gc.Shenandoah + * @summary Sanity test of combinations of the AOT Code Caching diagnostic flags + * @requires vm.cds.supports.aot.code.caching + * @requires vm.compiler1.enabled & vm.compiler2.enabled + * @comment Both C1 and C2 JIT compilers are required because the test verifies + * compiler's runtime blobs generation. + * @requires vm.opt.VerifyOops == null | vm.opt.VerifyOops == false + * @comment VerifyOops flag switch off AOT code generation. Skip it. + * @library /test/lib /test/setup_aot + * @build AOTCodeFlags JavacBenchApp + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app.jar + * JavacBenchApp + * JavacBenchApp$ClassFile + * JavacBenchApp$FileManager + * JavacBenchApp$SourceFile + * @run driver/timeout=1500 AOTCodeFlags Shenandoah + */ +/** + * @test id=parallel + * @requires vm.gc.Parallel + * @summary Sanity test of combinations of the AOT Code Caching diagnostic flags + * @requires vm.cds.supports.aot.code.caching + * @requires vm.compiler1.enabled & vm.compiler2.enabled + * @comment Both C1 and C2 JIT compilers are required because the test verifies + * compiler's runtime blobs generation. + * @requires vm.opt.VerifyOops == null | vm.opt.VerifyOops == false + * @comment VerifyOops flag switch off AOT code generation. Skip it. + * @library /test/lib /test/setup_aot + * @build AOTCodeFlags JavacBenchApp + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app.jar + * JavacBenchApp + * JavacBenchApp$ClassFile + * JavacBenchApp$FileManager + * JavacBenchApp$SourceFile + * @run driver/timeout=1500 AOTCodeFlags Parallel */ import java.util.ArrayList; @@ -48,20 +106,23 @@ import jdk.test.lib.cds.CDSAppTester; import jdk.test.lib.process.OutputAnalyzer; public class AOTCodeFlags { + private static String gcName = null; public static void main(String... args) throws Exception { - Tester t = new Tester(); + Tester t = new Tester(args.length == 0 ? null : args[0]); // Run only 2 modes (0 - no AOT code, 1 - AOT adapters) until JDK-8357398 is fixed - for (int mode = 0; mode < 2; mode++) { + for (int mode = 0; mode < 4; mode++) { t.setTestMode(mode); t.run(new String[] {"AOT", "--two-step-training"}); } } static class Tester extends CDSAppTester { private int testMode; + private String gcName; - public Tester() { + public Tester(String name) { super("AOTCodeFlags"); testMode = 0; + gcName = name; } boolean isAdapterCachingOn() { @@ -84,6 +145,24 @@ public class AOTCodeFlags { return list; } + public List getGCArgs() { + List args = new ArrayList(); + args.add("-Xmx100M"); + if (gcName == null) { + return args; + } + switch (gcName) { + case "G1": + case "Z": + case "Shenandoah": + case "Parallel": + args.add("-XX:+Use" + gcName + "GC"); + return args; + default: + throw new RuntimeException("Unexpected GC name " + gcName); + } + } + @Override public String classpath(RunMode runMode) { return "app.jar"; @@ -97,10 +176,12 @@ public class AOTCodeFlags { List args = getVMArgsForTestMode(); args.addAll(List.of("-Xlog:aot+codecache+init=debug", "-Xlog:aot+codecache+exit=debug")); + args.addAll(getGCArgs()); return args.toArray(new String[0]); } } - return new String[] {}; + List args = getGCArgs(); + return args.toArray(new String[args.size()]); } @Override @@ -147,7 +228,10 @@ public class AOTCodeFlags { // AOTStubCaching is on, non-zero stubs should be stored/loaded out.shouldMatch("Shared Blobs:\\s+total=[1-9][0-9]+"); out.shouldMatch("C1 Blobs:\\s+total=[1-9][0-9]+"); - out.shouldMatch("C2 Blobs:\\s+total=[1-9][0-9]+"); + // we do not currently load or store C2 stubs + // because we are seeing weird memory errors + // when loading them -- see JDK-8357593 + out.shouldMatch("C2 Blobs:\\s+total=0"); break; } } else { From 1e2aa616c9bfeaf09e3df7226e693d23d92d818a Mon Sep 17 00:00:00 2001 From: Evgeny Astigeevich Date: Wed, 8 Apr 2026 15:47:50 +0000 Subject: [PATCH 211/359] 8381770: Revert some shared changes done by JDK-8381003 Reviewed-by: kvn --- src/hotspot/share/code/nmethod.cpp | 2 -- src/hotspot/share/code/relocInfo.cpp | 9 +++++++++ src/hotspot/share/code/relocInfo.hpp | 2 ++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index de2c826667f..a302df418d7 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1332,7 +1332,6 @@ nmethod::nmethod( code_buffer->copy_values_to(this); post_init(); - ICache::invalidate_range(code_begin(), code_size()); } if (PrintNativeNMethods || PrintDebugInfo || PrintRelocations || PrintDependencies) { @@ -1812,7 +1811,6 @@ nmethod::nmethod( init_immutable_data_ref_count(); post_init(); - ICache::invalidate_range(code_begin(), code_size()); // we use the information of entry points to find out if a method is // static or non static diff --git a/src/hotspot/share/code/relocInfo.cpp b/src/hotspot/share/code/relocInfo.cpp index 25d91edc20f..73e4b6de7b4 100644 --- a/src/hotspot/share/code/relocInfo.cpp +++ b/src/hotspot/share/code/relocInfo.cpp @@ -590,6 +590,15 @@ oop oop_Relocation::oop_value() { return *oop_addr(); } +void oop_Relocation::fix_oop_relocation() { + // TODO: we need to add some assert here that ICache::invalidate_range is called in the code + // which uses this function. + if (!oop_is_immediate()) { + // get the oop from the pool, and re-insert it into the instruction: + set_value(value()); + } +} + void oop_Relocation::verify_oop_relocation() { if (!oop_is_immediate()) { // get the oop from the pool, and re-insert it into the instruction: diff --git a/src/hotspot/share/code/relocInfo.hpp b/src/hotspot/share/code/relocInfo.hpp index bb2b2b5693f..6f1778ef479 100644 --- a/src/hotspot/share/code/relocInfo.hpp +++ b/src/hotspot/share/code/relocInfo.hpp @@ -988,6 +988,8 @@ class oop_Relocation : public DataRelocation { void pack_data_to(CodeSection* dest) override; void unpack_data() override; + void fix_oop_relocation(); // reasserts oop value + void verify_oop_relocation(); address value() override { return *reinterpret_cast(oop_addr()); } From 67f590d8ba580d5cebbd041a30fef85c13d21e3b Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Wed, 8 Apr 2026 16:08:02 +0000 Subject: [PATCH 212/359] 8381681: Clarify locale usage in Javadoc for the Locale display methods Reviewed-by: naoto --- .../share/classes/java/util/Locale.java | 59 ++++++++++--------- 1 file changed, 31 insertions(+), 28 deletions(-) diff --git a/src/java.base/share/classes/java/util/Locale.java b/src/java.base/share/classes/java/util/Locale.java index 682476d8082..6b071cd15b2 100644 --- a/src/java.base/share/classes/java/util/Locale.java +++ b/src/java.base/share/classes/java/util/Locale.java @@ -1932,7 +1932,7 @@ public final class Locale implements Cloneable, Serializable { } /** - * Returns a name for the locale's language that is appropriate for display to the + * Returns a name for {@code this} locale's language that is appropriate for display to the * user. * If possible, the name returned will be localized for the default * {@link Locale.Category#DISPLAY DISPLAY} locale. @@ -1946,14 +1946,15 @@ public final class Locale implements Cloneable, Serializable { * this function falls back on the English name, and uses the ISO code as a last-resort * value. If the locale doesn't specify a language, this function returns the empty string. * - * @return The name of the display language. + * @return The name of the display language appropriate to the default + * {@link Locale.Category#DISPLAY DISPLAY} locale. */ - public final String getDisplayLanguage() { + public String getDisplayLanguage() { return getDisplayLanguage(getDefault(Category.DISPLAY)); } /** - * Returns a name for the locale's language that is appropriate for display to the + * Returns a name for {@code this} locale's language that is appropriate for display to the * user. * If possible, the name returned will be localized according to inLocale. * For example, if the locale is fr_FR and inLocale @@ -1964,7 +1965,7 @@ public final class Locale implements Cloneable, Serializable { * on the ISO code as a last-resort value. If the locale doesn't specify a language, * this function returns the empty string. * - * @param inLocale The locale for which to retrieve the display language. + * @param inLocale The locale in which to localize the display language. * @return The name of the display language appropriate to the given locale. * @throws NullPointerException if {@code inLocale} is {@code null} */ @@ -1973,13 +1974,13 @@ public final class Locale implements Cloneable, Serializable { } /** - * Returns a name for the locale's script that is appropriate for display to + * Returns a name for {@code this} locale's script that is appropriate for display to * the user. If possible, the name will be localized for the default * {@link Locale.Category#DISPLAY DISPLAY} locale. Returns * the empty string if this locale doesn't specify a script code. * - * @return the display name of the script code for the current default - * {@link Locale.Category#DISPLAY DISPLAY} locale + * @return The display name of the script code appropriate to the default + * {@link Locale.Category#DISPLAY DISPLAY} locale. * @since 1.7 */ public String getDisplayScript() { @@ -1987,14 +1988,13 @@ public final class Locale implements Cloneable, Serializable { } /** - * Returns a name for the locale's script that is appropriate + * Returns a name for {@code this} locale's script that is appropriate * for display to the user. If possible, the name will be * localized for the given locale. Returns the empty string if * this locale doesn't specify a script code. * - * @param inLocale The locale for which to retrieve the display script. - * @return the display name of the script code for the current default - * {@link Locale.Category#DISPLAY DISPLAY} locale + * @param inLocale The locale in which to localize the display script. + * @return The display name of the script code appropriate to the given locale. * @throws NullPointerException if {@code inLocale} is {@code null} * @since 1.7 */ @@ -2003,7 +2003,7 @@ public final class Locale implements Cloneable, Serializable { } /** - * Returns a name for the locale's country that is appropriate for display to the + * Returns a name for {@code this} locale's country that is appropriate for display to the * user. * If possible, the name returned will be localized for the default * {@link Locale.Category#DISPLAY DISPLAY} locale. @@ -2017,14 +2017,15 @@ public final class Locale implements Cloneable, Serializable { * this function falls back on the English name, and uses the ISO code as a last-resort * value. If the locale doesn't specify a country, this function returns the empty string. * - * @return The name of the country appropriate to the locale. + * @return The name of the country appropriate to the default + * {@link Locale.Category#DISPLAY DISPLAY} locale. */ - public final String getDisplayCountry() { + public String getDisplayCountry() { return getDisplayCountry(getDefault(Category.DISPLAY)); } /** - * Returns a name for the locale's country that is appropriate for display to the + * Returns a name for {@code this} locale's country that is appropriate for display to the * user. * If possible, the name returned will be localized according to inLocale. * For example, if the locale is fr_FR and inLocale @@ -2035,7 +2036,7 @@ public final class Locale implements Cloneable, Serializable { * on the ISO code as a last-resort value. If the locale doesn't specify a country, * this function returns the empty string. * - * @param inLocale The locale for which to retrieve the display country. + * @param inLocale The locale in which to localize the display country. * @return The name of the country appropriate to the given locale. * @throws NullPointerException if {@code inLocale} is {@code null} */ @@ -2061,23 +2062,24 @@ public final class Locale implements Cloneable, Serializable { } /** - * Returns a name for the locale's variant code that is appropriate for display to the + * Returns a name for {@code this} locale's variant code that is appropriate for display to the * user. If possible, the name will be localized for the default * {@link Locale.Category#DISPLAY DISPLAY} locale. If the locale * doesn't specify a variant code, this function returns the empty string. * - * @return The name of the display variant code appropriate to the locale. + * @return The name of the display variant code appropriate to the default + * {@link Locale.Category#DISPLAY DISPLAY} locale. */ - public final String getDisplayVariant() { + public String getDisplayVariant() { return getDisplayVariant(getDefault(Category.DISPLAY)); } /** - * Returns a name for the locale's variant code that is appropriate for display to the + * Returns a name for {@code this} locale's variant code that is appropriate for display to the * user. If possible, the name will be localized for inLocale. If the locale * doesn't specify a variant code, this function returns the empty string. * - * @param inLocale The locale for which to retrieve the display variant code. + * @param inLocale The locale in which to localize the display variant code. * @return The name of the display variant code appropriate to the given locale. * @throws NullPointerException if {@code inLocale} is {@code null} */ @@ -2098,7 +2100,7 @@ public final class Locale implements Cloneable, Serializable { } /** - * Returns a name for the locale that is appropriate for display to the + * Returns a name for {@code this} locale that is appropriate for display to the * user. This will be the values returned by getDisplayLanguage(), * getDisplayScript(), getDisplayCountry(), getDisplayVariant() and * optional {@linkplain ##def_locale_extension Unicode extensions} @@ -2116,14 +2118,15 @@ public final class Locale implements Cloneable, Serializable { * be localized depending on the locale. If the language, script, country, * and variant fields are all empty, this function returns the empty string. * - * @return The name of the locale appropriate to display. + * @return The display name appropriate to the default + * {@link Locale.Category#DISPLAY DISPLAY} locale. */ - public final String getDisplayName() { + public String getDisplayName() { return getDisplayName(getDefault(Category.DISPLAY)); } /** - * Returns a name for the locale that is appropriate for display + * Returns a name for {@code this} locale that is appropriate for display * to the user. This will be the values returned by * getDisplayLanguage(), getDisplayScript(), getDisplayCountry(), * getDisplayVariant(), and optional {@linkplain ##def_locale_extension @@ -2142,8 +2145,8 @@ public final class Locale implements Cloneable, Serializable { * be localized depending on the locale. If the language, script, country, * and variant fields are all empty, this function returns the empty string. * - * @param inLocale The locale for which to retrieve the display name. - * @return The name of the locale appropriate to display. + * @param inLocale The locale in which to localize the display name. + * @return The display name appropriate to the given locale. * @throws NullPointerException if {@code inLocale} is {@code null} */ public String getDisplayName(Locale inLocale) { From 13633c0825cc44e7a40b652b3c70334d1cfa621e Mon Sep 17 00:00:00 2001 From: Naoto Sato Date: Wed, 8 Apr 2026 18:35:40 +0000 Subject: [PATCH 213/359] 8381379: Support std/dstOffset attributes in CLDR's metazone definitions Reviewed-by: jlu --- .../tools/cldrconverter/CLDRConverter.java | 12 +++++++ .../cldrconverter/MetaZonesParseHandler.java | 10 +++++- .../ResourceBundleGenerator.java | 5 +-- .../classes/java/text/SimpleDateFormat.java | 27 ++++++++------ .../time/format/DateTimeFormatterBuilder.java | 8 +++-- .../util/locale/provider/LocaleResources.java | 9 +++-- .../locale/provider/TimeZoneNameUtility.java | 16 +++++++-- .../util/resources/TimeZoneNamesBundle.java | 4 +-- .../resources/cldr/TimeZoneNamesTest.java | 35 ++++++++++++++++++- 9 files changed, 103 insertions(+), 23 deletions(-) diff --git a/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java b/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java index ab878a4d2a5..de496b3f606 100644 --- a/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java +++ b/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java @@ -87,6 +87,7 @@ public class CLDRConverter { static final String EXEMPLAR_CITY_PREFIX = "timezone.excity."; static final String ZONE_NAME_PREFIX = "timezone.displayname."; static final String METAZONE_ID_PREFIX = "metazone.id."; + static final String METAZONE_DSTOFFSET_PREFIX = "metazone.dstoffset."; static final String PARENT_LOCALE_PREFIX = "parentLocale."; static final String LIKELY_SCRIPT_PREFIX = "likelyScript."; static final String META_EMPTY_ZONE_NAME = "EMPTY_ZONE"; @@ -139,6 +140,11 @@ public class CLDRConverter { private static final Map tzdbSubstLetters = HashMap.newHashMap(512); private static final Map tzdbLinks = HashMap.newHashMap(512); + // Map of explicit dst offsets for metazones + // key: time zone ID + // value: explicit dstOffset for the corresponding metazone name + static final Map explicitDstOffsets = HashMap.newHashMap(32); + static enum DraftType { UNCONFIRMED, PROVISIONAL, @@ -867,6 +873,12 @@ public class CLDRConverter { .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); names.putAll(exCities); + // Explicit metazone offsets + if (id.equals("root")) { + explicitDstOffsets.forEach((k, v) -> + names.put(METAZONE_DSTOFFSET_PREFIX + k, v)); + } + // If there's no UTC entry at this point, add an empty one if (!names.isEmpty() && !names.containsKey("UTC")) { names.putIfAbsent(METAZONE_ID_PREFIX + META_EMPTY_ZONE_NAME, EMPTY_ZONE); diff --git a/make/jdk/src/classes/build/tools/cldrconverter/MetaZonesParseHandler.java b/make/jdk/src/classes/build/tools/cldrconverter/MetaZonesParseHandler.java index 2c3757b7a47..45de46d2476 100644 --- a/make/jdk/src/classes/build/tools/cldrconverter/MetaZonesParseHandler.java +++ b/make/jdk/src/classes/build/tools/cldrconverter/MetaZonesParseHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2026, Oracle and/or its affiliates. All rights reserved. * 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,15 @@ class MetaZonesParseHandler extends AbstractLDMLHandler { if (fromLDT.isBefore(now) && toLDT.isAfter(now)) { metazone = attributes.getValue("mzone"); + + // Explicit metazone DST offsets. Only the "dst" offset is needed, + // as "std" is used by default when it doesn't match. + String dstOffset = attributes.getValue("dstOffset"); + if (dstOffset != null) { + CLDRConverter.explicitDstOffsets.put(tzid, dstOffset); + } } + pushIgnoredContainer(qName); break; diff --git a/make/jdk/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java b/make/jdk/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java index 3953f38f653..8278bf6bcfa 100644 --- a/make/jdk/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java +++ b/make/jdk/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2026, Oracle and/or its affiliates. All rights reserved. * 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,8 @@ class ResourceBundleGenerator implements BundleGenerator { } else if (value instanceof String) { String valStr = (String)value; if (type == BundleType.TIMEZONE && - !key.startsWith(CLDRConverter.EXEMPLAR_CITY_PREFIX) || + !(key.startsWith(CLDRConverter.EXEMPLAR_CITY_PREFIX) || + key.startsWith(CLDRConverter.METAZONE_DSTOFFSET_PREFIX)) || valStr.startsWith(META_VALUE_PREFIX)) { out.printf(" { \"%s\", %s },\n", key, CLDRConverter.saveConvert(valStr, useJava)); } else { diff --git a/src/java.base/share/classes/java/text/SimpleDateFormat.java b/src/java.base/share/classes/java/text/SimpleDateFormat.java index ba73e5b5a86..4c57214dbba 100644 --- a/src/java.base/share/classes/java/text/SimpleDateFormat.java +++ b/src/java.base/share/classes/java/text/SimpleDateFormat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ package java.text; import java.io.IOException; import java.io.InvalidObjectException; import java.io.ObjectInputStream; -import static java.text.DateFormatSymbols.*; +import java.time.ZoneOffset; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; @@ -57,6 +57,8 @@ import sun.util.calendar.ZoneInfoFile; import sun.util.locale.provider.LocaleProviderAdapter; import sun.util.locale.provider.TimeZoneNameUtility; +import static java.text.DateFormatSymbols.*; + /** * {@code SimpleDateFormat} is a concrete class for formatting and * parsing dates in a locale-sensitive manner. It allows for formatting @@ -1293,15 +1295,22 @@ public class SimpleDateFormat extends DateFormat { case PATTERN_ZONE_NAME: // 'z' if (current == null) { + TimeZone tz = calendar.getTimeZone(); + String tzid = tz.getID(); + int zoneOffset = calendar.get(Calendar.ZONE_OFFSET); + int dstOffset = calendar.get(Calendar.DST_OFFSET) + zoneOffset; + + // Check if an explicit metazone DST offset exists + String explicitDstOffset = TimeZoneNameUtility.explicitDstOffset(tzid); + boolean daylight = explicitDstOffset != null ? + dstOffset == ZoneOffset.of(explicitDstOffset).getTotalSeconds() * 1_000 : + dstOffset != zoneOffset; if (formatData.locale == null || formatData.isZoneStringsSet) { - int zoneIndex = - formatData.getZoneIndex(calendar.getTimeZone().getID()); + int zoneIndex = formatData.getZoneIndex(tzid); if (zoneIndex == -1) { - value = calendar.get(Calendar.ZONE_OFFSET) + - calendar.get(Calendar.DST_OFFSET); - buffer.append(ZoneInfoFile.toCustomID(value)); + buffer.append(ZoneInfoFile.toCustomID(dstOffset)); } else { - int index = (calendar.get(Calendar.DST_OFFSET) == 0) ? 1: 3; + int index = daylight ? 3 : 1; if (count < 4) { // Use the short name index++; @@ -1310,8 +1319,6 @@ public class SimpleDateFormat extends DateFormat { buffer.append(zoneStrings[zoneIndex][index]); } } else { - TimeZone tz = calendar.getTimeZone(); - boolean daylight = (calendar.get(Calendar.DST_OFFSET) != 0); int tzstyle = (count < 4 ? TimeZone.SHORT : TimeZone.LONG); buffer.append(tz.getDisplayName(daylight, tzstyle, formatData.locale)); } diff --git a/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java b/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java index 4708094effb..4594dc6f1dc 100644 --- a/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java +++ b/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2025, Alibaba Group Holding Limited. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -4513,7 +4513,11 @@ public final class DateTimeFormatterBuilder { TemporalAccessor dt = context.getTemporal(); int type = GENERIC; if (!isGeneric) { - if (dt.isSupported(ChronoField.INSTANT_SECONDS)) { + // Check if an explicit metazone DST offset exists + String dstOffset = TimeZoneNameUtility.explicitDstOffset(zname); + if (dt.isSupported(OFFSET_SECONDS) && dstOffset != null) { + type = ZoneOffset.from(dt).equals(ZoneOffset.of(dstOffset)) ? DST : STD; + } else if (dt.isSupported(ChronoField.INSTANT_SECONDS)) { type = zone.getRules().isDaylightSavings(Instant.from(dt)) ? DST : STD; } else if (dt.isSupported(ChronoField.EPOCH_DAY) && dt.isSupported(ChronoField.NANO_OF_DAY)) { diff --git a/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java b/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java index ac43b22a3bd..76b383c03e1 100644 --- a/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java +++ b/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java @@ -105,6 +105,9 @@ public class LocaleResources { // TimeZoneNamesBundle exemplar city prefix private static final String TZNB_EXCITY_PREFIX = "timezone.excity."; + // TimeZoneNamesBundle explicit metazone dst offset prefix + private static final String TZNB_METAZONE_DSTOFFSET_PREFIX = "metazone.dstoffset."; + // null singleton cache value private static final Object NULLOBJECT = new Object(); @@ -321,7 +324,8 @@ public class LocaleResources { if (Objects.isNull(data) || Objects.isNull(val = data.get())) { TimeZoneNamesBundle tznb = localeData.getTimeZoneNames(locale); - if (key.startsWith(TZNB_EXCITY_PREFIX)) { + if (key.startsWith(TZNB_EXCITY_PREFIX) || + key.startsWith(TZNB_METAZONE_DSTOFFSET_PREFIX)) { if (tznb.containsKey(key)) { val = tznb.getString(key); assert val instanceof String; @@ -378,7 +382,8 @@ public class LocaleResources { Set value = new LinkedHashSet<>(); Set tzIds = new HashSet<>(Arrays.asList(TimeZone.getAvailableIDs())); for (String key : keyset) { - if (!key.startsWith(TZNB_EXCITY_PREFIX)) { + if (!key.startsWith(TZNB_EXCITY_PREFIX) && + !key.startsWith(TZNB_METAZONE_DSTOFFSET_PREFIX)) { value.add(rb.getStringArray(key)); tzIds.remove(key); } diff --git a/src/java.base/share/classes/sun/util/locale/provider/TimeZoneNameUtility.java b/src/java.base/share/classes/sun/util/locale/provider/TimeZoneNameUtility.java index fd3d4965db3..6c684e176c8 100644 --- a/src/java.base/share/classes/sun/util/locale/provider/TimeZoneNameUtility.java +++ b/src/java.base/share/classes/sun/util/locale/provider/TimeZoneNameUtility.java @@ -37,7 +37,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.spi.TimeZoneNameProvider; import sun.util.calendar.ZoneInfo; import sun.util.cldr.CLDRLocaleProviderAdapter; -import static sun.util.locale.provider.LocaleProviderAdapter.Type; +import static sun.util.locale.provider.LocaleProviderAdapter.Type.CLDR; /** * Utility class that deals with the localized time zone names @@ -169,10 +169,22 @@ public final class TimeZoneNameUtility { * Returns the canonical ID for the given ID */ public static Optional canonicalTZID(String id) { - return ((CLDRLocaleProviderAdapter)LocaleProviderAdapter.forType(Type.CLDR)) + return ((CLDRLocaleProviderAdapter)LocaleProviderAdapter.forType(CLDR)) .canonicalTZID(id); } + /** + * {@return the explicit metazone DST offset for the specified time zone ID, if exists} + * @param tzid the time zone ID + */ + public static String explicitDstOffset(String tzid) { + return (String) (LocaleProviderAdapter.forType(CLDR) instanceof CLDRLocaleProviderAdapter ca ? + ca.getLocaleResources(Locale.ROOT) + .getTimeZoneNames("metazone.dstoffset." + + ca.canonicalTZID(tzid).orElse(tzid)) : + null); + } + private static String[] retrieveDisplayNamesImpl(String id, Locale locale) { LocaleServiceProviderPool pool = LocaleServiceProviderPool.getPool(TimeZoneNameProvider.class); diff --git a/src/java.base/share/classes/sun/util/resources/TimeZoneNamesBundle.java b/src/java.base/share/classes/sun/util/resources/TimeZoneNamesBundle.java index a30b84c6872..c5e95c8a404 100644 --- a/src/java.base/share/classes/sun/util/resources/TimeZoneNamesBundle.java +++ b/src/java.base/share/classes/sun/util/resources/TimeZoneNamesBundle.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2026, Oracle and/or its affiliates. All rights reserved. * 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,8 +43,6 @@ package sun.util.resources; import java.util.Map; import java.util.LinkedHashMap; import java.util.LinkedHashSet; -import java.util.MissingResourceException; -import java.util.Objects; import java.util.Set; /** diff --git a/test/jdk/sun/util/resources/cldr/TimeZoneNamesTest.java b/test/jdk/sun/util/resources/cldr/TimeZoneNamesTest.java index 6d21cd5613a..4d9b7500d87 100644 --- a/test/jdk/sun/util/resources/cldr/TimeZoneNamesTest.java +++ b/test/jdk/sun/util/resources/cldr/TimeZoneNamesTest.java @@ -24,7 +24,7 @@ /* * @test * @bug 8181157 8202537 8234347 8236548 8261279 8322647 8174269 8346948 - * 8354548 + * 8354548 8381379 * @modules jdk.localedata * @summary Checks CLDR time zone names are generated correctly at * either build or runtime @@ -32,15 +32,21 @@ */ import java.text.DateFormatSymbols; +import java.text.SimpleDateFormat; import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; import java.time.format.TextStyle; import java.util.Arrays; +import java.util.Date; import java.util.Locale; import java.util.Objects; import java.util.TimeZone; +import java.util.stream.Stream; 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 static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -217,6 +223,18 @@ public class TimeZoneNamesTest { }; } + private static Stream explicitDstOffsets() { + return Stream.of( + Arguments.of(ZonedDateTime.of(2026, 4, 5, 0, 0, 0, 0, ZoneId.of("Europe/Dublin")), "Irish Standard Time"), + Arguments.of(ZonedDateTime.of(2026, 12, 5, 0, 0, 0, 0, ZoneId.of("Europe/Dublin")), "Greenwich Mean Time"), + Arguments.of(ZonedDateTime.of(2026, 4, 5, 0, 0, 0, 0, ZoneId.of("Eire")), "Irish Standard Time"), + Arguments.of(ZonedDateTime.of(2026, 12, 5, 0, 0, 0, 0, ZoneId.of("Eire")), "Greenwich Mean Time"), + Arguments.of(ZonedDateTime.of(2026, 4, 5, 0, 0, 0, 0, ZoneId.of("America/Vancouver")), "Pacific Daylight Time"), + // This needs to change once TZDB adopts -7 offset year round, and CLDR uses explicit dst offset + // namely, "Pacific Standard Time" -> "Pacific Daylight Time" + Arguments.of(ZonedDateTime.of(2026, 12, 5, 0, 0, 0, 0, ZoneId.of("America/Vancouver")), "Pacific Standard Time") + ); + } @ParameterizedTest @MethodSource("sampleTZs") @@ -248,4 +266,19 @@ public class TimeZoneNamesTest { .anyMatch(name -> Objects.isNull(name) || name.isEmpty()), "getZoneStrings() returned array containing non-empty string element(s)"); } + + // Explicit metazone dst offset test. As of CLDR v48, only Europe/Dublin utilizes + // this attribute, but will be used for America/Vancouver once CLDR adopts the + // explicit offset for that zone, which warrants the test data modification. + @ParameterizedTest + @MethodSource("explicitDstOffsets") + public void test_ExplicitMetazoneOffsets(ZonedDateTime zdt, String expected) { + // java.time + assertEquals(expected, DateTimeFormatter.ofPattern("zzzz").format(zdt)); + + // java.text/util + var sdf = new SimpleDateFormat("zzzz"); + sdf.setTimeZone(TimeZone.getTimeZone(zdt.getZone())); + assertEquals(expected, sdf.format(Date.from(zdt.toInstant()))); + } } From 67a71249a17b3fb9f9263df239fc25b0df22757c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eirik=20Bj=C3=B8rsn=C3=B8s?= Date: Wed, 8 Apr 2026 19:06:40 +0000 Subject: [PATCH 214/359] 8381772: Remove mention of "mutable strings" in java.lang.String Javadocs Reviewed-by: alanb, liach --- src/java.base/share/classes/java/lang/String.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/java.base/share/classes/java/lang/String.java b/src/java.base/share/classes/java/lang/String.java index c6c08ed4473..760f3ebc255 100644 --- a/src/java.base/share/classes/java/lang/String.java +++ b/src/java.base/share/classes/java/lang/String.java @@ -70,9 +70,9 @@ import sun.nio.cs.UTF_8; * string literals in Java programs, such as {@code "abc"}, are * implemented as instances of this class. *

- * Strings are constant; their values cannot be changed after they - * are created. String buffers support mutable strings. - * Because String objects are immutable they can be shared. For example: + * Strings are immutable; their values cannot be changed after they + * are created. Because String objects are immutable they can be shared. + * For example: *

  *     String str = "abc";
  * 

From d3afc857698c3c79d1eca48d5b47061f4b472081 Mon Sep 17 00:00:00 2001 From: Dean Long Date: Wed, 8 Apr 2026 20:04:20 +0000 Subject: [PATCH 215/359] 8381662: New test compiler/exceptions/TestDebugDuringExceptionCatching.java failing with C1-only Reviewed-by: kvn, mhaessig --- .../exceptions/TestDebugDuringExceptionCatching.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/hotspot/jtreg/compiler/exceptions/TestDebugDuringExceptionCatching.java b/test/hotspot/jtreg/compiler/exceptions/TestDebugDuringExceptionCatching.java index 999c73fb73a..9be192d1f55 100644 --- a/test/hotspot/jtreg/compiler/exceptions/TestDebugDuringExceptionCatching.java +++ b/test/hotspot/jtreg/compiler/exceptions/TestDebugDuringExceptionCatching.java @@ -22,6 +22,7 @@ */ package compiler.exceptions; +import compiler.lib.ir_framework.CompLevel; import compiler.lib.ir_framework.Run; import compiler.lib.ir_framework.Test; import compiler.lib.ir_framework.TestFramework; @@ -38,7 +39,7 @@ import test.java.lang.invoke.lib.InstructionHelper; /** * @test * @bug 8350208 - * @summary Safepoints added during the processing of exception handlers should never reexecute + * @summary Safepoints added during the processing of exception handlers need correct stack state * @library /test/lib /test/jdk/java/lang/invoke/common / * @build test.java.lang.invoke.lib.InstructionHelper * @@ -110,7 +111,7 @@ public class TestDebugDuringExceptionCatching { }); } - @Test + @Test(compLevel = CompLevel.C2) // see JDK-8381786 private static int testBackwardHandler(V v) throws Throwable { return (int) SNIPPET_HANDLE.invokeExact(v); } From dc8163052ce6350e419641467a37089697e49aa6 Mon Sep 17 00:00:00 2001 From: Srinivas Vamsi Parasa Date: Wed, 8 Apr 2026 20:52:28 +0000 Subject: [PATCH 216/359] 8381865: Fix debug build failure caused by not clearing CPU_APX_F feature after JDK-8364584 Reviewed-by: sviswanathan, kvn, asmehra --- src/hotspot/cpu/x86/vm_version_x86.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hotspot/cpu/x86/vm_version_x86.cpp b/src/hotspot/cpu/x86/vm_version_x86.cpp index 7899a2f7e51..d8f998520d1 100644 --- a/src/hotspot/cpu/x86/vm_version_x86.cpp +++ b/src/hotspot/cpu/x86/vm_version_x86.cpp @@ -1098,6 +1098,7 @@ void VM_Version::get_processor_features() { if (supports_apx_f() && os_supports_apx_egprs() && supports_avx512vl()) { if (FLAG_IS_DEFAULT(UseAPX)) { UseAPX = false; // by default UseAPX is false + _features.clear_feature(CPU_APX_F); } else if (!UseAPX) { _features.clear_feature(CPU_APX_F); } From 78580f1e4ea86eda0f8f737fa679f0b730075d54 Mon Sep 17 00:00:00 2001 From: Jaikiran Pai Date: Thu, 9 Apr 2026 04:56:30 +0000 Subject: [PATCH 217/359] 8378291: Test vector in test/jdk/java/util/jar/JarEntry/GetMethodsReturnClones.java is effectively unsigned Reviewed-by: eirbjo, lancea --- .../jar/JarEntry/GetMethodsReturnClones.java | 151 ++++++++++++++---- test/jdk/java/util/jar/JarEntry/test.jar | Bin 3022 -> 0 bytes 2 files changed, 121 insertions(+), 30 deletions(-) delete mode 100644 test/jdk/java/util/jar/JarEntry/test.jar diff --git a/test/jdk/java/util/jar/JarEntry/GetMethodsReturnClones.java b/test/jdk/java/util/jar/JarEntry/GetMethodsReturnClones.java index a9b35220de3..d2ab41cb831 100644 --- a/test/jdk/java/util/jar/JarEntry/GetMethodsReturnClones.java +++ b/test/jdk/java/util/jar/JarEntry/GetMethodsReturnClones.java @@ -21,72 +21,163 @@ * questions. */ +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.security.CodeSigner; +import java.security.KeyStore; +import java.security.cert.Certificate; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Enumeration; +import java.util.List; +import java.util.concurrent.TimeUnit; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.jar.JarOutputStream; +import java.util.zip.ZipFile; + +import jdk.security.jarsigner.JarSigner; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import sun.security.tools.keytool.CertAndKeyGen; +import sun.security.x509.X500Name; +import static java.nio.charset.StandardCharsets.US_ASCII; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; + /* * @test * @bug 6337925 * @summary Ensure that callers cannot modify the internal JarEntry cert and * codesigner arrays. + * @modules java.base/sun.security.tools.keytool + * java.base/sun.security.x509 * @run junit GetMethodsReturnClones */ -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; +class GetMethodsReturnClones { -import java.io.IOException; -import java.io.InputStream; -import java.security.CodeSigner; -import java.security.cert.Certificate; -import java.util.*; -import java.util.jar.*; -import static org.junit.jupiter.api.Assertions.assertNotNull; + private static final String ENTRY_NAME = "foobar.txt"; + private static final String SIGNER_NAME = "DUMMY"; + private static final String DIGEST_ALGORITHM = "SHA-256"; + private static final String SIGNATURE_ALGORITHM = "SHA256withRSA"; + private static final String KEY_TYPE = "RSA"; -public class GetMethodsReturnClones { - - private static final String BASE = System.getProperty("test.src", ".") + - System.getProperty("file.separator"); private static List jarEntries; + /* + * Creates a signed JAR file and initializes the "jarEntries" + */ @BeforeAll() - static void setupEntries() throws IOException { + static void setupJarEntries() throws Exception { + Path unsigned = createJar(); + Path signed = signJar(unsigned); + System.err.println("created signed JAR file at " + signed.toAbsolutePath()); List entries = new ArrayList<>(); - try (JarFile jf = new JarFile(BASE + "test.jar", true)) { - byte[] buffer = new byte[8192]; + try (JarFile jf = new JarFile(signed.toFile(), true)) { Enumeration e = jf.entries(); while (e.hasMoreElements()) { JarEntry je = e.nextElement(); entries.add(je); try (InputStream is = jf.getInputStream(je)) { - while (is.read(buffer, 0, buffer.length) != -1) { - // we just read. this will throw a SecurityException - // if a signature/digest check fails. - } + // we just read. this will throw a SecurityException + // if a signature/digest check fails. + var _ = is.readAllBytes(); } } } jarEntries = entries; } + /* + * For entries in the signed JAR file, this test verifies that if a non-null + * array is returned by the JarEntry.getCertificates() method, then any subsequent + * updates to that returned array do not propagate back to the original array. + */ @Test - void certsTest() { + void testCertificatesArray() { for (JarEntry je : jarEntries) { Certificate[] certs = je.getCertificates(); - if (certs != null) { - certs[0] = null; - certs = je.getCertificates(); - assertNotNull(certs[0], "Modified internal certs array"); + System.err.println("Certificates for " + je.getName() + " " + Arrays.toString(certs)); + if (isSignatureRelated(je)) { + // we don't expect this entry to be signed + assertNull(certs, "JarEntry.getCertificates() returned non-null for " + je.getName()); + continue; } + assertNotNull(certs, "JarEntry.getCertificates() returned null for " + je.getName()); + assertNotNull(certs[0], "Certificate is null"); + + certs[0] = null; // intentionally update the returned array + certs = je.getCertificates(); // now get the certs again + assertNotNull(certs, "JarEntry.getCertificates() returned null for " + je.getName()); + // verify that the newly returned array doesn't have the overwritten value + assertNotNull(certs[0], "Internal certificates array was modified"); } } + /* + * For entries in the signed JAR file, this test verifies that if a non-null + * array is returned by the JarEntry.getCodeSigners() method, then any subsequent + * updates to that returned array do not propagate back to the original array. + */ @Test - void signersTest() { + void testCodeSignersArray() { for (JarEntry je : jarEntries) { CodeSigner[] signers = je.getCodeSigners(); - if (signers != null) { - signers[0] = null; - signers = je.getCodeSigners(); - assertNotNull(signers[0], "Modified internal codesigners array"); + System.err.println("CodeSigners for " + je.getName() + " " + Arrays.toString(signers)); + if (isSignatureRelated(je)) { + // we don't expect this entry to be signed + assertNull(signers, "JarEntry.getCodeSigners() returned non-null for " + je.getName()); + continue; } + assertNotNull(signers, "JarEntry.getCodeSigners() returned null for " + je.getName()); + assertNotNull(signers[0], "CodeSigner is null"); + + signers[0] = null; // intentionally update the array + signers = je.getCodeSigners(); // now get the codesigners again + assertNotNull(signers, "JarEntry.getCodeSigners() returned null for " + je.getName()); + // verify that the newly returned array doesn't have the overwritten value + assertNotNull(signers[0], "CodeSigner is null"); } } + + private static Path createJar() throws IOException { + final Path unsigned = Path.of("unsigned.jar"); + try (JarOutputStream out = new JarOutputStream(Files.newOutputStream(unsigned))) { + out.putNextEntry(new JarEntry(ENTRY_NAME)); + out.write("hello world".getBytes(US_ASCII)); + } + return unsigned; + } + + private static Path signJar(final Path unsigned) throws Exception { + final Path signed = Path.of("signed.jar"); + final JarSigner signer = new JarSigner.Builder(privateKeyEntry()) + .signerName(SIGNER_NAME) + .digestAlgorithm(DIGEST_ALGORITHM) + .signatureAlgorithm(SIGNATURE_ALGORITHM) + .build(); + try (ZipFile zip = new ZipFile(unsigned.toFile()); + OutputStream out = Files.newOutputStream(signed)) { + signer.sign(zip, out); + } + return signed; + } + + private static KeyStore.PrivateKeyEntry privateKeyEntry() throws Exception { + final CertAndKeyGen gen = new CertAndKeyGen(KEY_TYPE, SIGNATURE_ALGORITHM); + gen.generate(4096); + final long oneDayInSecs = TimeUnit.SECONDS.convert(1, TimeUnit.DAYS); + Certificate cert = gen.getSelfCertificate(new X500Name("cn=duke"), oneDayInSecs); + return new KeyStore.PrivateKeyEntry(gen.getPrivateKey(), new Certificate[] {cert}); + } + + private static boolean isSignatureRelated(final JarEntry entry) { + final String entryName = entry.getName(); + return entryName.equals("META-INF/" + SIGNER_NAME + ".SF") + || entryName.equals("META-INF/" + SIGNER_NAME + ".RSA"); + } } diff --git a/test/jdk/java/util/jar/JarEntry/test.jar b/test/jdk/java/util/jar/JarEntry/test.jar deleted file mode 100644 index fb9e4c1734966f2a72279b65426359002e48c81a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3022 zcmaKuXH-+!0)<2Gf&!s~g5c1J2!ervcdc{Rx%=F+?~m_pV+aK$8-SKHMv`=70H?%8nj2`E zgC%thwWJNehPqmsX68}`TI~IG^c^xRfMMk{7_LJ7PBpD*UdXiBfV zlWjHuqtfJ`O0!n_NYq<^TZj6?x)yvgSR03sGiC^{U&c7kM#YOW*qFpc6V+$hga(x$R=H`bD}y#2pv z&;D0hQ!}uvr?afb+?e;4=iy)%gpL4Pe%}bgF)Rl)k=1Sa0|^*Luf$nR>trSI!`wzGGra;_}2gnsWpN}^K-g-ABemkK7d!RL5U2=9A>rU?dv=$7BV7wL#$Ih zp14O>*s)6z+@^o4G+UQ_>YHf4JrOgo%mg&Gxy)n!4CzVbGcE9Gxus<4gF~I?aruCL zKZ+5B6lUyX)R1Ua z2)pu`!75`{KC=pPbeJiR@kGDet1Wg~Z?Y>*@_CN`c;u^C|2cNj@<<_Mcl(21jhf<@ z5j}Hq*!$;^lCONvv(V_$WQKTsnDZ8~50x?BG zLXewVkdS;n6SKT@MLj)=AY#tKMrjih!*NVOoxUp8_S$N1XF=1N5o^7!A}bFxVB$`w z(;E&c`w0TCM|w*vboTo|q9RPJO)r`d^KENEdo77SLL7kzJ<5a~&OFLk5uPrDL-=EV z$!WIh4oH1NXOgS5xO0n7)}9w?Drd4beyiq-Gok=*Y4|#{7NJrdG3!>H;zbo85>91x zAhxSE@-QV1IKJIYdxpl^iKPI0n@I-*y6mWXH^u0RI?_#LTWZ)!bY&mQf1Y;@JJ6zp zGr#H#*Gg~`CkWExJSFAOxc# zSZ%`ER=X%X%G|6<`d?V>JY1=Y*(;iq8+S-d(fyj+wpI|hb%@@S<}-2_R1&dou*I1> zFOoe_5n$Ho)A2AEnFPT$U$p7J;Mld`!#oMy$|sI7@1`b6MV6Y_zw;lO>A*KM1rO{K zIDp|-@qIh?pSCrZg-F<>q0LT^aNwo{0F(S@RzY4NZdzWxZsu;mAyO{BPQk&+7JgzPoW!#B+RIwR@tpu5_N=vQ>0 z1|llAS227I{b2F>;{5y??0Apif*t(vY*EsX#iSU<)Wq1t{FZGO1^X8Ae@!>?~D~uPOIdN9nb4D0pX`l6u9*)f4^vW1! z>9UAyy4ZE672o4BRDb7d(*wN-Nr_~DJSnEL_54XLlV(FC@u zp}dZ^J$ctxoiuwy{E5wpyx329UI?bPp!0Y>s4SnPgaJBY z2aA`iVpUXeM`2lOQl{9XJl3w9C7;D!fg)qd7wotsP9M@od zc;|_*n0&LrgJuY7DeM#1lPG9Wy9_V@uFPTT?z#;vW-7w%vn^FrH^ombbKOy*)NK|dq{LtFwGqjE zf{yJ@ceaV#2+91!9d4R9opdN@Coz_N#*1OsPLj zl4<$sbu!*n8S-3xmxC2v>9wGVtYCxfFeQ8g?m3~Mao+1@gz&?I*V}Dn6=1+O*{mkf zNu9-AjoUX3Y+BWZvm|ag31n<^?GWBXQYX&x(Tpohq?I%j?t3z;8@v>ra&Wqb0p0f# zbtu5O=ePy~R9ie>1Dp;<&cq!JN6}uX&QTrRInO0HEn%q(Wo>16jNA@=d?+k34opUK zFT8@rp=Dkg%4{*drc*CcpJlrnjUa%`dhm2*=ZaYM`7;Hui5JTY(^j;ZCEIEJnn5tj*`8-6KJv4!$d@dh z(p2|RhNIP$>|rTiORadotI}#3^XD)<%;v>o8eBxex`3#-2BnPNn1pGsi^dS8wf^Wa zMnf|1%?aWcH$z|Z=5y3n1}&%f*6%BV5q?>n3>Nhihcr*Nd{UpxF!1OMqh zO~R8R^;3;x|8$dT)oJ^mxcrlaC%F76W>VO{UVZ}4)7BGMp8hH)u>2`~lJ#HEX$+wv SEdT&iq@hGQTrB;`-G2b2MhxQs From 61b2508224ada9bc968ccdf7ae47b3e6bb1dff80 Mon Sep 17 00:00:00 2001 From: Martin Doerr Date: Thu, 9 Apr 2026 08:38:59 +0000 Subject: [PATCH 218/359] 8320897: compiler/vectorapi/reshape/TestVectorReinterpret.java fails on ppc64(le) platforms 8348519: [s390x] test failure TestVectorReinterpret.java Reviewed-by: amitkumar, rrich --- test/hotspot/jtreg/ProblemList.txt | 1 - .../tests/TestVectorDoubleExpandShrink.java | 4 +- .../reshape/tests/TestVectorExpandShrink.java | 6 +- .../reshape/tests/TestVectorRebracket.java | 62 +++++++++---------- 4 files changed, 36 insertions(+), 37 deletions(-) diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index d4efaa7e631..b4f9efff830 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -56,7 +56,6 @@ compiler/c2/irTests/TestDuplicateBackedge.java 8318904 generic-all compiler/codecache/jmx/PoolsIndependenceTest.java 8264632 macosx-all -compiler/vectorapi/reshape/TestVectorReinterpret.java 8348519 linux-s390x compiler/vectorapi/VectorRebracket128Test.java 8330538 generic-all compiler/vectorization/TestVectorAlgorithms.java#noSuperWord 8376803 aix-ppc64,linux-s390x diff --git a/test/hotspot/jtreg/compiler/vectorapi/reshape/tests/TestVectorDoubleExpandShrink.java b/test/hotspot/jtreg/compiler/vectorapi/reshape/tests/TestVectorDoubleExpandShrink.java index 91b7113ac14..2d6ca8222a4 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/reshape/tests/TestVectorDoubleExpandShrink.java +++ b/test/hotspot/jtreg/compiler/vectorapi/reshape/tests/TestVectorDoubleExpandShrink.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * 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,7 +71,7 @@ public class TestVectorDoubleExpandShrink { } @Test - @IR(counts = {REINTERPRET_NODE, "2"}) + @IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "2"}) public static void testB128toB64(MemorySegment input, MemorySegment output) { vectorDoubleExpandShrink(BSPEC128, BSPEC64, input, output); } diff --git a/test/hotspot/jtreg/compiler/vectorapi/reshape/tests/TestVectorExpandShrink.java b/test/hotspot/jtreg/compiler/vectorapi/reshape/tests/TestVectorExpandShrink.java index bd3a8f6c12d..92755b96acb 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/reshape/tests/TestVectorExpandShrink.java +++ b/test/hotspot/jtreg/compiler/vectorapi/reshape/tests/TestVectorExpandShrink.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,7 +38,7 @@ import static compiler.vectorapi.reshape.utils.VectorReshapeHelper.*; */ public class TestVectorExpandShrink { @Test - @IR(counts = {REINTERPRET_NODE, "1"}) + @IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "1"}) public static void testB64toB128(MemorySegment input, MemorySegment output) { vectorExpandShrink(BSPEC64, BSPEC128, input, output); } @@ -71,7 +71,7 @@ public class TestVectorExpandShrink { } @Test - @IR(counts = {REINTERPRET_NODE, "1"}) + @IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "1"}) public static void testB128toB64(MemorySegment input, MemorySegment output) { vectorExpandShrink(BSPEC128, BSPEC64, input, output); } diff --git a/test/hotspot/jtreg/compiler/vectorapi/reshape/tests/TestVectorRebracket.java b/test/hotspot/jtreg/compiler/vectorapi/reshape/tests/TestVectorRebracket.java index 2143eb3b500..d3283e991a4 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/reshape/tests/TestVectorRebracket.java +++ b/test/hotspot/jtreg/compiler/vectorapi/reshape/tests/TestVectorRebracket.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,7 +41,7 @@ import static compiler.vectorapi.reshape.utils.VectorReshapeHelper.*; */ public class TestVectorRebracket { @Test - @IR(counts = {REINTERPRET_NODE, "1"}) + @IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "1"}) public static void testB64toS64(byte[] input, short[] output) { vectorRebracket(BSPEC64, SSPEC64, input, output); } @@ -52,7 +52,7 @@ public class TestVectorRebracket { } @Test - @IR(counts = {REINTERPRET_NODE, "1"}) + @IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "1"}) public static void testB64toI64(byte[] input, int[] output) { vectorRebracket(BSPEC64, ISPEC64, input, output); } @@ -63,7 +63,7 @@ public class TestVectorRebracket { } @Test - @IR(counts = {REINTERPRET_NODE, "1"}) + @IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "1"}) public static void testB64toL64(byte[] input, long[] output) { vectorRebracket(BSPEC64, LSPEC64, input, output); } @@ -74,7 +74,7 @@ public class TestVectorRebracket { } @Test - @IR(counts = {REINTERPRET_NODE, "1"}) + @IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "1"}) public static void testB64toF64(byte[] input, float[] output) { vectorRebracket(BSPEC64, FSPEC64, input, output); } @@ -85,7 +85,7 @@ public class TestVectorRebracket { } @Test - @IR(counts = {REINTERPRET_NODE, "1"}) + @IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "1"}) public static void testB64toD64(byte[] input, double[] output) { vectorRebracket(BSPEC64, DSPEC64, input, output); } @@ -96,7 +96,7 @@ public class TestVectorRebracket { } @Test - @IR(counts = {REINTERPRET_NODE, "1"}) + @IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "1"}) public static void testS64toB64(short[] input, byte[] output) { vectorRebracket(SSPEC64, BSPEC64, input, output); } @@ -107,7 +107,7 @@ public class TestVectorRebracket { } @Test - @IR(counts = {REINTERPRET_NODE, "1"}) + @IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "1"}) public static void testS64toI64(short[] input, int[] output) { vectorRebracket(SSPEC64, ISPEC64, input, output); } @@ -118,7 +118,7 @@ public class TestVectorRebracket { } @Test - @IR(counts = {REINTERPRET_NODE, "1"}) + @IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "1"}) public static void testS64toL64(short[] input, long[] output) { vectorRebracket(SSPEC64, LSPEC64, input, output); } @@ -129,7 +129,7 @@ public class TestVectorRebracket { } @Test - @IR(counts = {REINTERPRET_NODE, "1"}) + @IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "1"}) public static void testS64toF64(short[] input, float[] output) { vectorRebracket(SSPEC64, FSPEC64, input, output); } @@ -140,7 +140,7 @@ public class TestVectorRebracket { } @Test - @IR(counts = {REINTERPRET_NODE, "1"}) + @IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "1"}) public static void testS64toD64(short[] input, double[] output) { vectorRebracket(SSPEC64, DSPEC64, input, output); } @@ -151,7 +151,7 @@ public class TestVectorRebracket { } @Test - @IR(counts = {REINTERPRET_NODE, "1"}) + @IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "1"}) public static void testI64toB64(int[] input, byte[] output) { vectorRebracket(ISPEC64, BSPEC64, input, output); } @@ -162,7 +162,7 @@ public class TestVectorRebracket { } @Test - @IR(counts = {REINTERPRET_NODE, "1"}) + @IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "1"}) public static void testI64toS64(int[] input, short[] output) { vectorRebracket(ISPEC64, SSPEC64, input, output); } @@ -173,7 +173,7 @@ public class TestVectorRebracket { } @Test - @IR(counts = {REINTERPRET_NODE, "1"}) + @IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "1"}) public static void testI64toL64(int[] input, long[] output) { vectorRebracket(ISPEC64, LSPEC64, input, output); } @@ -184,7 +184,7 @@ public class TestVectorRebracket { } @Test - @IR(counts = {REINTERPRET_NODE, "1"}) + @IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "1"}) public static void testI64toF64(int[] input, float[] output) { vectorRebracket(ISPEC64, FSPEC64, input, output); } @@ -195,7 +195,7 @@ public class TestVectorRebracket { } @Test - @IR(counts = {REINTERPRET_NODE, "1"}) + @IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "1"}) public static void testI64toD64(int[] input, double[] output) { vectorRebracket(ISPEC64, DSPEC64, input, output); } @@ -206,7 +206,7 @@ public class TestVectorRebracket { } @Test - @IR(counts = {REINTERPRET_NODE, "1"}) + @IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "1"}) public static void testL64toB64(long[] input, byte[] output) { vectorRebracket(LSPEC64, BSPEC64, input, output); } @@ -217,7 +217,7 @@ public class TestVectorRebracket { } @Test - @IR(counts = {REINTERPRET_NODE, "1"}) + @IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "1"}) public static void testL64toS64(long[] input, short[] output) { vectorRebracket(LSPEC64, SSPEC64, input, output); } @@ -228,7 +228,7 @@ public class TestVectorRebracket { } @Test - @IR(counts = {REINTERPRET_NODE, "1"}) + @IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "1"}) public static void testL64toI64(long[] input, int[] output) { vectorRebracket(LSPEC64, ISPEC64, input, output); } @@ -239,7 +239,7 @@ public class TestVectorRebracket { } @Test - @IR(counts = {REINTERPRET_NODE, "1"}) + @IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "1"}) public static void testL64toF64(long[] input, float[] output) { vectorRebracket(LSPEC64, FSPEC64, input, output); } @@ -250,7 +250,7 @@ public class TestVectorRebracket { } @Test - @IR(counts = {REINTERPRET_NODE, "1"}) + @IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "1"}) public static void testL64toD64(long[] input, double[] output) { vectorRebracket(LSPEC64, DSPEC64, input, output); } @@ -261,7 +261,7 @@ public class TestVectorRebracket { } @Test - @IR(counts = {REINTERPRET_NODE, "1"}) + @IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "1"}) public static void testF64toB64(float[] input, byte[] output) { vectorRebracket(FSPEC64, BSPEC64, input, output); } @@ -272,7 +272,7 @@ public class TestVectorRebracket { } @Test - @IR(counts = {REINTERPRET_NODE, "1"}) + @IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "1"}) public static void testF64toS64(float[] input, short[] output) { vectorRebracket(FSPEC64, SSPEC64, input, output); } @@ -283,7 +283,7 @@ public class TestVectorRebracket { } @Test - @IR(counts = {REINTERPRET_NODE, "1"}) + @IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "1"}) public static void testF64toI64(float[] input, int[] output) { vectorRebracket(FSPEC64, ISPEC64, input, output); } @@ -294,7 +294,7 @@ public class TestVectorRebracket { } @Test - @IR(counts = {REINTERPRET_NODE, "1"}) + @IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "1"}) public static void testF64toL64(float[] input, long[] output) { vectorRebracket(FSPEC64, LSPEC64, input, output); } @@ -305,7 +305,7 @@ public class TestVectorRebracket { } @Test - @IR(counts = {REINTERPRET_NODE, "1"}) + @IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "1"}) public static void testF64toD64(float[] input, double[] output) { vectorRebracket(FSPEC64, DSPEC64, input, output); } @@ -316,7 +316,7 @@ public class TestVectorRebracket { } @Test - @IR(counts = {REINTERPRET_NODE, "1"}) + @IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "1"}) public static void testD64toB64(double[] input, byte[] output) { vectorRebracket(DSPEC64, BSPEC64, input, output); } @@ -327,7 +327,7 @@ public class TestVectorRebracket { } @Test - @IR(counts = {REINTERPRET_NODE, "1"}) + @IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "1"}) public static void testD64toS64(double[] input, short[] output) { vectorRebracket(DSPEC64, SSPEC64, input, output); } @@ -338,7 +338,7 @@ public class TestVectorRebracket { } @Test - @IR(counts = {REINTERPRET_NODE, "1"}) + @IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "1"}) public static void testD64toI64(double[] input, int[] output) { vectorRebracket(DSPEC64, ISPEC64, input, output); } @@ -349,7 +349,7 @@ public class TestVectorRebracket { } @Test - @IR(counts = {REINTERPRET_NODE, "1"}) + @IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "1"}) public static void testD64toL64(double[] input, long[] output) { vectorRebracket(DSPEC64, LSPEC64, input, output); } @@ -360,7 +360,7 @@ public class TestVectorRebracket { } @Test - @IR(counts = {REINTERPRET_NODE, "1"}) + @IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "1"}) public static void testD64toF64(double[] input, float[] output) { vectorRebracket(DSPEC64, FSPEC64, input, output); } From 60115c0bbfb564dc9acf7741505d22dd1ceddf95 Mon Sep 17 00:00:00 2001 From: Roland Westrelin Date: Thu, 9 Apr 2026 09:35:13 +0000 Subject: [PATCH 219/359] 8380158: C2: compiler/c2/TestGVNCrash.java asserts with adr and adr_type must agree Reviewed-by: chagedorn, dfenacci --- src/hotspot/share/opto/arraycopynode.cpp | 67 +++++++++++-------- src/hotspot/share/opto/arraycopynode.hpp | 4 ++ .../TestACNonEscapingSrcBadAddPBaseType.java | 65 ++++++++++++++++++ 3 files changed, 109 insertions(+), 27 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/arraycopy/TestACNonEscapingSrcBadAddPBaseType.java diff --git a/src/hotspot/share/opto/arraycopynode.cpp b/src/hotspot/share/opto/arraycopynode.cpp index dab0ca98911..2f64482f55b 100644 --- a/src/hotspot/share/opto/arraycopynode.cpp +++ b/src/hotspot/share/opto/arraycopynode.cpp @@ -258,6 +258,19 @@ Node* ArrayCopyNode::try_clone_instance(PhaseGVN *phase, bool can_reshape, int c return mem; } +// We may have narrowed the type of base because this runs with PhaseIterGVN::_delay_transform true, explicitly +// update the type of the AddP so it's consistent with its base and load() picks the right memory slice. +Node* ArrayCopyNode::make_and_transform_addp(PhaseGVN* phase, Node* base, Node* offset) { + return make_and_transform_addp(phase, base, base, offset); +} + +Node* ArrayCopyNode::make_and_transform_addp(PhaseGVN* phase, Node* base, Node* ptr, Node* offset) { + assert(phase->is_IterGVN() == nullptr || phase->is_IterGVN()->delay_transform(), "helper method when delay transform is set"); + Node* addp = phase->transform(AddPNode::make_with_base(base, ptr, offset)); + phase->set_type(addp, addp->Value(phase)); + return addp; +} + bool ArrayCopyNode::prepare_array_copy(PhaseGVN *phase, bool can_reshape, Node*& adr_src, Node*& base_src, @@ -332,12 +345,11 @@ bool ArrayCopyNode::prepare_array_copy(PhaseGVN *phase, bool can_reshape, Node* dest_scale = phase->transform(new LShiftXNode(dest_offset, phase->intcon(shift))); - adr_src = phase->transform(AddPNode::make_with_base(base_src, src_scale)); - adr_dest = phase->transform(AddPNode::make_with_base(base_dest, dest_scale)); - - adr_src = phase->transform(AddPNode::make_with_base(base_src, adr_src, phase->MakeConX(header))); - adr_dest = phase->transform(AddPNode::make_with_base(base_dest, adr_dest, phase->MakeConX(header))); + adr_src = make_and_transform_addp(phase, base_src, src_scale); + adr_dest = make_and_transform_addp(phase, base_dest, dest_scale); + adr_src = make_and_transform_addp(phase, base_src, adr_src, phase->MakeConX(header)); + adr_dest = make_and_transform_addp(phase, base_dest, adr_dest, phase->MakeConX(header)); copy_type = dest_elem; } else { assert(ary_src != nullptr, "should be a clone"); @@ -355,8 +367,8 @@ bool ArrayCopyNode::prepare_array_copy(PhaseGVN *phase, bool can_reshape, return false; } - adr_src = phase->transform(AddPNode::make_with_base(base_src, src_offset)); - adr_dest = phase->transform(AddPNode::make_with_base(base_dest, dest_offset)); + adr_src = make_and_transform_addp(phase, base_src, src_offset); + adr_dest = make_and_transform_addp(phase, base_dest, dest_offset); // The address is offsetted to an aligned address where a raw copy would start. // If the clone copy is decomposed into load-stores - the address is adjusted to @@ -366,8 +378,8 @@ bool ArrayCopyNode::prepare_array_copy(PhaseGVN *phase, bool can_reshape, int diff = arrayOopDesc::base_offset_in_bytes(elem) - offset; assert(diff >= 0, "clone should not start after 1st array element"); if (diff > 0) { - adr_src = phase->transform(AddPNode::make_with_base(base_src, adr_src, phase->MakeConX(diff))); - adr_dest = phase->transform(AddPNode::make_with_base(base_dest, adr_dest, phase->MakeConX(diff))); + adr_src = make_and_transform_addp(phase, base_src, adr_src, phase->MakeConX(diff)); + adr_dest = make_and_transform_addp(phase, base_dest, adr_dest, phase->MakeConX(diff)); } copy_type = elem; value_type = ary_src->elem(); @@ -429,12 +441,8 @@ Node* ArrayCopyNode::array_copy_forward(PhaseGVN *phase, store(bs, phase, forward_ctl, mm, adr_dest, atp_dest, v, value_type, copy_type); for (int i = 1; i < count; i++) { Node* off = phase->MakeConX(type2aelembytes(copy_type) * i); - Node* next_src = phase->transform(AddPNode::make_with_base(base_src,adr_src,off)); - // We may have narrowed the type of next_src right before calling this method but because this runs with - // PhaseIterGVN::_delay_transform true, explicitly update the type of the AddP so it's consistent with its - // base and load() picks the right memory slice. - phase->set_type(next_src, next_src->Value(phase)); - Node* next_dest = phase->transform(AddPNode::make_with_base(base_dest,adr_dest,off)); + Node* next_src = make_and_transform_addp(phase, base_src,adr_src,off); + Node* next_dest = make_and_transform_addp(phase, base_dest,adr_dest,off); // Same as above phase->set_type(next_dest, next_dest->Value(phase)); v = load(bs, phase, forward_ctl, mm, next_src, atp_src, value_type, copy_type); @@ -473,13 +481,8 @@ Node* ArrayCopyNode::array_copy_backward(PhaseGVN *phase, if (count > 0) { for (int i = count-1; i >= 1; i--) { Node* off = phase->MakeConX(type2aelembytes(copy_type) * i); - Node* next_src = phase->transform(AddPNode::make_with_base(base_src,adr_src,off)); - // We may have narrowed the type of next_src right before calling this method but because this runs with - // PhaseIterGVN::_delay_transform true, explicitly update the type of the AddP so it's consistent with its - // base and store() picks the right memory slice. - phase->set_type(next_src, next_src->Value(phase)); - Node* next_dest = phase->transform(AddPNode::make_with_base(base_dest,adr_dest,off)); - phase->set_type(next_dest, next_dest->Value(phase)); + Node* next_src = make_and_transform_addp(phase, base_src,adr_src,off); + Node* next_dest = make_and_transform_addp(phase, base_dest,adr_dest,off); Node* v = load(bs, phase, backward_ctl, mm, next_src, atp_src, value_type, copy_type); store(bs, phase, backward_ctl, mm, next_dest, atp_dest, v, value_type, copy_type); } @@ -618,21 +621,31 @@ Node *ArrayCopyNode::Ideal(PhaseGVN *phase, bool can_reshape) { phase->set_type(src, phase->type(src)->join_speculative(atp_src)); phase->set_type(dest, phase->type(dest)->join_speculative(atp_dest)); + // Control flow is going to be created, it's easier to do with _delay_transform set to true. + + // prepare_array_copy() doesn't build control flow, but it creates AddP nodes. The src/dest type possibly gets + // narrowed above. If a newly created AddP node is commoned with a pre-existing one, then the type narrowing is lost. + // Setting _delay_transform before prepare_array_copy() guarantees this doesn't happen. + if (can_reshape) { + assert(!phase->is_IterGVN()->delay_transform(), "cannot delay transforms"); + phase->is_IterGVN()->set_delay_transform(true); + } + if (!prepare_array_copy(phase, can_reshape, adr_src, base_src, adr_dest, base_dest, copy_type, value_type, disjoint_bases)) { assert(adr_src == nullptr, "no node can be left behind"); assert(adr_dest == nullptr, "no node can be left behind"); + if (can_reshape) { + assert(phase->is_IterGVN()->delay_transform(), "cannot delay transforms"); + phase->is_IterGVN()->set_delay_transform(false); + } + return nullptr; } Node* in_mem = in(TypeFunc::Memory); - if (can_reshape) { - assert(!phase->is_IterGVN()->delay_transform(), "cannot delay transforms"); - phase->is_IterGVN()->set_delay_transform(true); - } - Node* backward_ctl = phase->C->top(); Node* forward_ctl = phase->C->top(); array_copy_test_overlap(phase, can_reshape, disjoint_bases, count, forward_ctl, backward_ctl); diff --git a/src/hotspot/share/opto/arraycopynode.hpp b/src/hotspot/share/opto/arraycopynode.hpp index 483a3a86267..aa62ee05cd0 100644 --- a/src/hotspot/share/opto/arraycopynode.hpp +++ b/src/hotspot/share/opto/arraycopynode.hpp @@ -104,6 +104,10 @@ private: static const TypePtr* get_address_type(PhaseGVN* phase, const TypePtr* atp, Node* n); Node* try_clone_instance(PhaseGVN *phase, bool can_reshape, int count); + + Node* make_and_transform_addp(PhaseGVN* phase, Node* base, Node* offset); + Node* make_and_transform_addp(PhaseGVN* phase, Node* base, Node* ptr, Node* offset); + bool prepare_array_copy(PhaseGVN *phase, bool can_reshape, Node*& adr_src, Node*& base_src, Node*& adr_dest, Node*& base_dest, BasicType& copy_type, const Type*& value_type, bool& disjoint_bases); diff --git a/test/hotspot/jtreg/compiler/arraycopy/TestACNonEscapingSrcBadAddPBaseType.java b/test/hotspot/jtreg/compiler/arraycopy/TestACNonEscapingSrcBadAddPBaseType.java new file mode 100644 index 00000000000..251c053ff5d --- /dev/null +++ b/test/hotspot/jtreg/compiler/arraycopy/TestACNonEscapingSrcBadAddPBaseType.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2026 IBM Corporation. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8380158 + * @summary C2: compiler/c2/TestGVNCrash.java asserts with adr and adr_type must agree + * @run main/othervm -XX:-TieredCompilation -XX:-UseOnStackReplacement -XX:-BackgroundCompilation + * -XX:CompileOnly=compiler.arraycopy.TestACNonEscapingSrcBadAddPBaseType::test1 + * -XX:+UnlockDiagnosticVMOptions -XX:+StressIGVN -XX:StressSeed=946074051 ${test.main.class} + * @run main/othervm -XX:-TieredCompilation -XX:-UseOnStackReplacement -XX:-BackgroundCompilation + * -XX:CompileOnly=compiler.arraycopy.TestACNonEscapingSrcBadAddPBaseType::test1 + * -XX:+UnlockDiagnosticVMOptions -XX:+StressIGVN ${test.main.class} + * @run main ${test.main.class} + */ + +package compiler.arraycopy; + +public class TestACNonEscapingSrcBadAddPBaseType { + private static volatile int volatileField; + + public static void main(String[] args) { + int[] dst = new int[2]; + for (int i = 0; i < 20_000; i++) { + test1(dst); + } + } + + private static void test1(int[] dst) { + int[] array = new int[2]; + A a = new A(array); + volatileField = 42; + int[] src = a.src; + System.arraycopy(src, 0, dst, 0, src.length); + System.arraycopy(src, 0, dst, 0, src.length); + } + + private static class A { + private final int[] src; + + public A(int[] src) { + this.src = src; + } + } +} From 261011ab138685102166336ad1a1e5f757f6937e Mon Sep 17 00:00:00 2001 From: Daisuke Yamazaki Date: Thu, 9 Apr 2026 10:51:53 +0000 Subject: [PATCH 220/359] 8372325: Refactor tests under jdk/java/net/httpclient to use ${test.main.class} Reviewed-by: dfuchs, syan --- .../java/net/httpclient/ALPNFailureTest.java | 6 ++-- .../net/httpclient/ALPNProxyFailureTest.java | 6 ++-- .../httpclient/AggregateRequestBodyTest.java | 2 +- .../net/httpclient/AltServiceUsageTest.java | 2 +- .../net/httpclient/AsFileDownloadTest.java | 2 +- .../net/httpclient/AsyncExecutorShutdown.java | 2 +- .../java/net/httpclient/AsyncShutdownNow.java | 2 +- .../net/httpclient/AuthFilterCacheTest.java | 2 +- .../java/net/httpclient/AuthSchemesTest.java | 4 +-- .../java/net/httpclient/BasicAuthTest.java | 4 +-- .../java/net/httpclient/BasicHTTP2Test.java | 2 +- .../java/net/httpclient/BasicHTTP3Test.java | 2 +- .../net/httpclient/BasicRedirectTest.java | 2 +- .../BodyProcessorInputStreamTest.java | 4 +-- .../net/httpclient/BodySubscribersTest.java | 2 +- .../java/net/httpclient/BufferSize1Test.java | 4 +-- .../BufferSizePropertyClampTest.java | 8 ++--- .../BufferingSubscriberCancelTest.java | 2 +- .../BufferingSubscriberErrorCompleteTest.java | 2 +- .../httpclient/BufferingSubscriberTest.java | 2 +- .../net/httpclient/ByteArrayPublishers.java | 4 +-- .../net/httpclient/CancelRequestTest.java | 2 +- .../httpclient/CancelStreamedBodyTest.java | 2 +- .../CancelledPartialResponseTest.java | 2 +- .../net/httpclient/CancelledResponse.java | 6 ++-- .../net/httpclient/CancelledResponse2.java | 2 +- .../net/httpclient/ConcurrentResponses.java | 2 +- .../net/httpclient/ConnectExceptionTest.java | 2 +- .../ConnectTimeoutHandshakeAsync.java | 2 +- .../ConnectTimeoutHandshakeSync.java | 2 +- .../httpclient/ContentLengthHeaderTest.java | 2 +- .../java/net/httpclient/CookieHeaderTest.java | 2 +- .../httpclient/CustomRequestPublisher.java | 2 +- .../httpclient/CustomResponseSubscriber.java | 2 +- .../java/net/httpclient/DebugLoggerTest.java | 24 +++++++------- .../net/httpclient/DependentActionsTest.java | 2 +- .../DependentPromiseActionsTest.java | 2 +- .../java/net/httpclient/DigestEchoClient.java | 6 ++-- .../net/httpclient/DigestEchoClientSSL.java | 8 ++--- .../net/httpclient/DurationOverflowTest.java | 10 +++--- .../net/httpclient/EmptyAuthenticate.java | 4 +-- .../net/httpclient/EncodedCharsInURI.java | 2 +- .../net/httpclient/EscapedOctetsInURI.java | 2 +- .../java/net/httpclient/ExecutorShutdown.java | 2 +- .../java/net/httpclient/ExpectContinue.java | 2 +- .../net/httpclient/ExpectContinueTest.java | 2 +- .../net/httpclient/FilePublisherTest.java | 2 +- .../httpclient/FlowAdapterPublisherTest.java | 2 +- .../httpclient/FlowAdapterSubscriberTest.java | 2 +- .../net/httpclient/ForbiddenHeadTest.java | 2 +- .../net/httpclient/GZIPInputStreamTest.java | 2 +- .../net/httpclient/HandshakeFailureTest.java | 8 ++--- test/jdk/java/net/httpclient/HeadTest.java | 2 +- .../net/httpclient/HeadersLowerCaseTest.java | 2 +- .../jdk/java/net/httpclient/HeadersTest1.java | 2 +- .../java/net/httpclient/Http1ChunkedTest.java | 4 +-- .../HttpClientAuthRetryLimitTest.java | 10 +++--- .../net/httpclient/HttpClientBuilderTest.java | 2 +- .../java/net/httpclient/HttpClientClose.java | 2 +- .../httpclient/HttpClientExceptionTest.java | 2 +- .../httpclient/HttpClientLocalAddrTest.java | 2 +- .../net/httpclient/HttpClientSNITest.java | 4 +-- .../HttpClientSendAsyncExceptionTest.java | 4 +-- .../net/httpclient/HttpClientShutdown.java | 2 +- .../httpclient/HttpGetInCancelledFuture.java | 6 ++-- .../java/net/httpclient/HttpHeadersOf.java | 2 +- .../HttpInputStreamAvailableTest.java | 2 +- .../net/httpclient/HttpInputStreamTest.java | 4 +-- .../java/net/httpclient/HttpRedirectTest.java | 2 +- .../OfByteArraysTest.java | 4 +-- .../httpclient/HttpRequestNewBuilderTest.java | 2 +- .../HttpResponseConnectionLabelTest.java | 4 +-- .../HttpResponseInputStreamInterruptTest.java | 2 +- .../HttpResponseInputStreamTest.java | 2 +- .../httpclient/HttpResponseLimitingTest.java | 4 +-- .../net/httpclient/HttpSlowServerTest.java | 4 +-- .../java/net/httpclient/HttpVersionsTest.java | 2 +- .../net/httpclient/HttpsTunnelAuthTest.java | 4 +-- .../java/net/httpclient/HttpsTunnelTest.java | 6 ++-- .../java/net/httpclient/ISO_8859_1_Test.java | 2 +- .../httpclient/IdleConnectionTimeoutTest.java | 20 ++++++------ .../net/httpclient/ImmutableFlowItems.java | 2 +- .../java/net/httpclient/ImmutableHeaders.java | 4 +-- .../httpclient/ImmutableSSLSessionTest.java | 4 +-- .../httpclient/InterruptedBlockingSend.java | 4 +-- ...InvalidInputStreamSubscriptionRequest.java | 6 ++-- .../net/httpclient/InvalidSSLContextTest.java | 2 +- .../InvalidSubscriptionRequest.java | 2 +- .../net/httpclient/LargeHandshakeTest.java | 4 +-- .../net/httpclient/LargeResponseContent.java | 4 +-- .../net/httpclient/LargeResponseTest.java | 4 +-- .../net/httpclient/LineBodyHandlerTest.java | 2 +- .../LineStreamsAndSurrogatesTest.java | 2 +- .../LineSubscribersAndSurrogatesTest.java | 2 +- .../jdk/java/net/httpclient/ManyRequests.java | 10 +++--- .../java/net/httpclient/ManyRequests2.java | 8 ++--- .../net/httpclient/ManyRequestsLegacy.java | 8 ++--- test/jdk/java/net/httpclient/MaxStreams.java | 2 +- .../net/httpclient/MessageHeadersTest.java | 4 +-- .../java/net/httpclient/MultiAuthTest.java | 4 +-- .../java/net/httpclient/NoBodyPartOne.java | 2 +- .../java/net/httpclient/NoBodyPartThree.java | 2 +- .../java/net/httpclient/NoBodyPartTwo.java | 2 +- .../net/httpclient/NonAsciiCharsInURI.java | 2 +- test/jdk/java/net/httpclient/OriginTest.java | 4 +-- .../BodyHandlerOfFileDownloadTest.java | 2 +- .../PathSubscriber/BodyHandlerOfFileTest.java | 2 +- .../BodySubscriberOfFileTest.java | 2 +- .../httpclient/PlainProxyConnectionTest.java | 2 +- .../httpclient/ProxyAuthDisabledSchemes.java | 8 ++--- .../ProxyAuthDisabledSchemesSSL.java | 10 +++--- .../java/net/httpclient/ProxyAuthTest.java | 4 +-- .../net/httpclient/ProxySelectorTest.java | 2 +- test/jdk/java/net/httpclient/ProxyTest.java | 4 +-- .../net/httpclient/RedirectMethodChange.java | 2 +- .../net/httpclient/RedirectTimeoutTest.java | 4 +-- .../net/httpclient/RedirectWithCookie.java | 2 +- .../java/net/httpclient/RequestBodyTest.java | 2 +- .../net/httpclient/RequestBuilderTest.java | 2 +- .../java/net/httpclient/Response1xxTest.java | 2 +- test/jdk/java/net/httpclient/Response204.java | 4 +-- .../net/httpclient/Response204V2Test.java | 2 +- .../httpclient/ResponseBodyBeforeError.java | 2 +- .../net/httpclient/ResponsePublisher.java | 2 +- .../net/httpclient/RestrictedHeadersTest.java | 10 +++--- test/jdk/java/net/httpclient/RetryPost.java | 4 +-- .../java/net/httpclient/RetryWithCookie.java | 2 +- .../java/net/httpclient/SSLExceptionTest.java | 2 +- .../httpclient/SendResponseHeadersTest.java | 2 +- .../java/net/httpclient/ServerCloseTest.java | 2 +- .../java/net/httpclient/ShortRequestBody.java | 4 +-- .../net/httpclient/ShortResponseBodyGet.java | 2 +- .../net/httpclient/ShortResponseBodyPost.java | 2 +- test/jdk/java/net/httpclient/ShutdownNow.java | 2 +- .../jdk/java/net/httpclient/SmallTimeout.java | 6 ++-- test/jdk/java/net/httpclient/SmokeTest.java | 2 +- .../net/httpclient/SpecialHeadersTest.java | 4 +-- .../java/net/httpclient/SplitResponse.java | 4 +-- .../java/net/httpclient/StreamCloseTest.java | 2 +- .../httpclient/SubscriberAPIExceptions.java | 2 +- test/jdk/java/net/httpclient/TestKitTest.java | 2 +- .../ThrowingPublishersCustomAfterCancel.java | 4 +-- .../ThrowingPublishersCustomBeforeCancel.java | 4 +-- .../ThrowingPublishersIOAfterCancel.java | 4 +-- .../ThrowingPublishersIOBeforeCancel.java | 4 +-- .../ThrowingPublishersInNextRequest.java | 4 +-- .../ThrowingPublishersInRequest.java | 4 +-- .../ThrowingPublishersInSubscribe.java | 4 +-- .../httpclient/ThrowingPublishersSanity.java | 4 +-- ...rowingPushPromisesAsInputStreamCustom.java | 4 +-- .../ThrowingPushPromisesAsInputStreamIO.java | 4 +-- .../ThrowingPushPromisesAsLinesCustom.java | 4 +-- .../ThrowingPushPromisesAsLinesIO.java | 4 +-- .../ThrowingPushPromisesAsStringCustom.java | 4 +-- .../ThrowingPushPromisesAsStringIO.java | 4 +-- .../ThrowingPushPromisesSanity.java | 4 +-- .../ThrowingSubscribersAsInputStream.java | 4 +-- ...ThrowingSubscribersAsInputStreamAsync.java | 4 +-- .../ThrowingSubscribersAsLimiting.java | 4 +-- .../ThrowingSubscribersAsLimitingAsync.java | 4 +-- .../ThrowingSubscribersAsLines.java | 4 +-- .../ThrowingSubscribersAsLinesAsync.java | 4 +-- .../ThrowingSubscribersAsString.java | 4 +-- .../ThrowingSubscribersAsStringAsync.java | 4 +-- .../httpclient/ThrowingSubscribersSanity.java | 4 +-- .../jdk/java/net/httpclient/TimeoutBasic.java | 4 +-- .../java/net/httpclient/TimeoutOrdering.java | 6 ++-- .../httpclient/TimeoutResponseBodyTest.java | 6 ++-- .../httpclient/TimeoutResponseHeaderTest.java | 6 ++-- .../java/net/httpclient/TlsContextTest.java | 2 +- .../java/net/httpclient/UnauthorizedTest.java | 2 +- .../net/httpclient/UnknownBodyLengthTest.java | 10 +++--- .../httpclient/UserAuthWithAuthenticator.java | 2 +- .../java/net/httpclient/UserCookieTest.java | 2 +- test/jdk/java/net/httpclient/VersionTest.java | 4 +-- .../java/net/httpclient/ZeroRedirects.java | 4 +-- .../altsvc/AltServiceReasonableAssurance.java | 4 +-- .../net/httpclient/http2/BadHeadersTest.java | 4 +-- .../httpclient/http2/BadPushPromiseTest.java | 4 +-- .../java/net/httpclient/http2/BasicTest.java | 2 +- .../http2/ConnectionFlowControlTest.java | 4 +-- .../httpclient/http2/ConnectionReuseTest.java | 6 ++-- .../http2/ContinuationFrameTest.java | 4 +-- .../java/net/httpclient/http2/ErrorTest.java | 2 +- .../httpclient/http2/FixedThreadPoolTest.java | 2 +- .../net/httpclient/http2/H2GoAwayTest.java | 4 +-- .../httpclient/http2/H2SelectorVTTest.java | 12 +++---- .../http2/IdlePooledConnectionTest.java | 4 +-- .../httpclient/http2/ImplicitPushCancel.java | 2 +- .../java/net/httpclient/http2/NoBodyTest.java | 2 +- .../net/httpclient/http2/PostPutTest.java | 4 +-- .../java/net/httpclient/http2/ProxyTest2.java | 4 +-- .../http2/PushPromiseContinuation.java | 2 +- .../net/httpclient/http2/RedirectTest.java | 2 +- .../java/net/httpclient/http2/ServerPush.java | 2 +- .../http2/ServerPushWithDiffTypes.java | 2 +- .../java/net/httpclient/http2/SimpleGet.java | 6 ++-- .../net/httpclient/http2/TLSConnection.java | 4 +-- .../java/net/httpclient/http2/Timeout.java | 4 +-- .../httpclient/http2/TrailingHeadersTest.java | 4 +-- .../net/httpclient/http2/UserInfoTest.java | 4 +-- .../http3/BadCipherSuiteErrorTest.java | 2 +- .../httpclient/http3/FramesDecoderTest.java | 4 +-- .../net/httpclient/http3/GetHTTP3Test.java | 2 +- .../httpclient/http3/H3BadHeadersTest.java | 2 +- .../net/httpclient/http3/H3BasicTest.java | 2 +- .../httpclient/http3/H3ConcurrentPush.java | 2 +- .../http3/H3ConnectionPoolTest.java | 2 +- .../httpclient/http3/H3DataLimitsTest.java | 2 +- .../httpclient/http3/H3ErrorHandlingTest.java | 2 +- .../net/httpclient/http3/H3GoAwayTest.java | 4 +-- .../http3/H3HeaderSizeLimitTest.java | 2 +- .../httpclient/http3/H3HeadersEncoding.java | 2 +- .../http3/H3ImplicitPushCancel.java | 2 +- .../http3/H3InsertionsLimitTest.java | 2 +- .../http3/H3LogHandshakeErrors.java | 2 +- .../http3/H3MaxInitialTimeoutTest.java | 6 ++-- .../http3/H3MemoryHandlingTest.java | 2 +- .../H3MultipleConnectionsToSameHost.java | 8 ++--- .../net/httpclient/http3/H3ProxyTest.java | 4 +-- .../net/httpclient/http3/H3PushCancel.java | 2 +- .../httpclient/http3/H3QuicTLSConnection.java | 4 +-- .../net/httpclient/http3/H3QuicVTTest.java | 12 +++---- .../net/httpclient/http3/H3RedirectTest.java | 2 +- .../net/httpclient/http3/H3ServerPush.java | 2 +- .../httpclient/http3/H3ServerPushCancel.java | 2 +- .../httpclient/http3/H3ServerPushTest.java | 4 +-- .../http3/H3ServerPushWithDiffTypes.java | 2 +- .../net/httpclient/http3/H3SimpleGet.java | 32 +++++++++---------- .../net/httpclient/http3/H3SimplePost.java | 2 +- .../net/httpclient/http3/H3SimpleTest.java | 8 ++--- .../httpclient/http3/H3StopSendingTest.java | 2 +- .../http3/H3StreamLimitReachedTest.java | 4 +-- .../java/net/httpclient/http3/H3Timeout.java | 4 +-- .../http3/H3UnsupportedSSLParametersTest.java | 4 +-- .../net/httpclient/http3/H3UserInfoTest.java | 4 +-- .../net/httpclient/http3/HTTP3NoBodyTest.java | 2 +- .../http3/Http3ExpectContinueTest.java | 2 +- .../http3/PeerUniStreamDispatcherTest.java | 2 +- .../net/httpclient/http3/PostHTTP3Test.java | 2 +- .../net/httpclient/http3/StopSendingTest.java | 2 +- .../net/httpclient/http3/StreamLimitTest.java | 2 +- .../httpclient/offline/OfflineTesting.java | 2 +- .../qpack/BlockingDecodingTest.java | 4 +-- .../qpack/DecoderInstructionsReaderTest.java | 4 +-- .../qpack/DecoderInstructionsWriterTest.java | 4 +-- .../qpack/DecoderSectionSizeLimitTest.java | 4 +-- .../net/httpclient/qpack/DecoderTest.java | 4 +-- ...namicTableFieldLineRepresentationTest.java | 4 +-- .../httpclient/qpack/DynamicTableTest.java | 4 +-- .../qpack/EncoderDecoderConnectionTest.java | 4 +-- .../httpclient/qpack/EncoderDecoderTest.java | 4 +-- .../qpack/EncoderInstructionsReaderTest.java | 4 +-- .../qpack/EncoderInstructionsWriterTest.java | 4 +-- .../net/httpclient/qpack/EncoderTest.java | 4 +-- .../httpclient/qpack/EntriesEvictionTest.java | 4 +-- .../qpack/FieldSectionPrefixTest.java | 4 +-- .../qpack/IntegerReaderMaxValuesTest.java | 4 +-- .../qpack/StaticTableFieldsTest.java | 4 +-- .../qpack/StringLengthLimitsTest.java | 4 +-- .../httpclient/qpack/TablesIndexerTest.java | 4 +-- .../qpack/UnacknowledgedInsertionTest.java | 4 +-- .../net/httpclient/quic/AckElicitingTest.java | 4 +-- .../net/httpclient/quic/AckFrameTest.java | 2 +- .../httpclient/quic/BuffersReaderTest.java | 4 +-- .../httpclient/quic/BuffersReaderVLTest.java | 2 +- .../httpclient/quic/ConnectionIDSTest.java | 2 +- .../quic/CryptoWriterQueueTest.java | 2 +- .../java/net/httpclient/quic/CubicTest.java | 4 +-- .../net/httpclient/quic/KeyUpdateTest.java | 2 +- .../net/httpclient/quic/OrderedFlowTest.java | 10 +++--- .../java/net/httpclient/quic/PacerTest.java | 2 +- .../httpclient/quic/PacketEncodingTest.java | 22 ++++++------- .../net/httpclient/quic/PacketLossTest.java | 2 +- .../httpclient/quic/PacketNumbersTest.java | 2 +- .../quic/PacketSpaceManagerTest.java | 16 +++++----- .../quic/QuicFramesDecoderTest.java | 2 +- .../quic/QuicRequestResponseTest.java | 2 +- .../quic/StatelessResetReceiptTest.java | 2 +- .../httpclient/quic/VariableLengthTest.java | 2 +- .../quic/VersionNegotiationTest.java | 2 +- .../quic/tls/PacketEncryptionTest.java | 2 +- .../tls/QuicTLSEngineBadParametersTest.java | 4 +-- .../quic/tls/QuicTLSEngineFailedALPNTest.java | 4 +-- .../QuicTLSEngineMissingParametersTest.java | 4 +-- .../quic/tls/Quicv2PacketEncryptionTest.java | 2 +- .../FileProcessorPermissionTest.java | 2 +- .../filePerms/SecurityBeforeFile.java | 2 +- .../httpclient/ssltest/CertificateTest.java | 16 +++++----- .../httpclient/ssltest/TlsVersionTest.java | 6 ++-- .../java/net/httpclient/websocket/Abort.java | 2 +- .../httpclient/websocket/AutomaticPong.java | 2 +- .../websocket/BlowupOutputQueue.java | 2 +- .../websocket/ConnectionHandoverTest.java | 4 +-- .../websocket/HandshakeUrlEncodingTest.java | 2 +- .../websocket/PendingBinaryPingClose.java | 2 +- .../websocket/PendingBinaryPongClose.java | 2 +- .../websocket/PendingPingBinaryClose.java | 2 +- .../websocket/PendingPingTextClose.java | 2 +- .../websocket/PendingPongBinaryClose.java | 2 +- .../websocket/PendingPongTextClose.java | 2 +- .../websocket/PendingTextPingClose.java | 2 +- .../websocket/PendingTextPongClose.java | 2 +- .../net/httpclient/websocket/SendTest.java | 2 +- .../websocket/WSHandshakeExceptionTest.java | 2 +- .../websocket/WebSocketBuilderTest.java | 2 +- .../websocket/WebSocketEndiannessTest.java | 4 +-- .../websocket/WebSocketExtendedTest.java | 2 +- .../websocket/WebSocketProxyTest.java | 2 +- .../httpclient/websocket/WebSocketTest.java | 2 +- .../websocket/security/WSSanityTest.java | 2 +- .../httpclient/whitebox/AltSvcFrameTest.java | 2 +- .../whitebox/AltSvcRegistryTest.java | 2 +- 313 files changed, 572 insertions(+), 572 deletions(-) diff --git a/test/jdk/java/net/httpclient/ALPNFailureTest.java b/test/jdk/java/net/httpclient/ALPNFailureTest.java index 3d6013f557c..dbffec82e28 100644 --- a/test/jdk/java/net/httpclient/ALPNFailureTest.java +++ b/test/jdk/java/net/httpclient/ALPNFailureTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,8 +30,8 @@ * @modules java.net.http * java.logging * @build ALPNFailureTest - * @run main/othervm -Djdk.internal.httpclient.debug=true ALPNFailureTest HTTP_1_1 - * @run main/othervm ALPNFailureTest HTTP_2 + * @run main/othervm -Djdk.internal.httpclient.debug=true ${test.main.class} HTTP_1_1 + * @run main/othervm ${test.main.class} HTTP_2 */ import javax.net.ServerSocketFactory; import javax.net.ssl.SSLContext; diff --git a/test/jdk/java/net/httpclient/ALPNProxyFailureTest.java b/test/jdk/java/net/httpclient/ALPNProxyFailureTest.java index 4dedfed97b1..bae8d55c8cc 100644 --- a/test/jdk/java/net/httpclient/ALPNProxyFailureTest.java +++ b/test/jdk/java/net/httpclient/ALPNProxyFailureTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,8 +31,8 @@ * @build jdk.test.lib.net.SimpleSSLContext DigestEchoServer * jdk.httpclient.test.lib.common.HttpServerAdapters * ALPNFailureTest ALPNProxyFailureTest - * @run main/othervm -Djdk.internal.httpclient.debug=true -Dtest.nolinger=true ALPNProxyFailureTest HTTP_1_1 - * @run main/othervm -Dtest.nolinger=true ALPNProxyFailureTest HTTP_2 + * @run main/othervm -Djdk.internal.httpclient.debug=true -Dtest.nolinger=true ${test.main.class} HTTP_1_1 + * @run main/othervm -Dtest.nolinger=true ${test.main.class} HTTP_2 */ import javax.net.ServerSocketFactory; import javax.net.ssl.SSLContext; diff --git a/test/jdk/java/net/httpclient/AggregateRequestBodyTest.java b/test/jdk/java/net/httpclient/AggregateRequestBodyTest.java index fb67cf02566..df6c9902cf9 100644 --- a/test/jdk/java/net/httpclient/AggregateRequestBodyTest.java +++ b/test/jdk/java/net/httpclient/AggregateRequestBodyTest.java @@ -29,7 +29,7 @@ * ReferenceTracker AggregateRequestBodyTest * @run junit/othervm -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.HttpClient.log=requests,responses,errors,headers,frames - * AggregateRequestBodyTest + * ${test.main.class} * @summary Tests HttpRequest.BodyPublishers::concat */ diff --git a/test/jdk/java/net/httpclient/AltServiceUsageTest.java b/test/jdk/java/net/httpclient/AltServiceUsageTest.java index 59ad2179b90..dd6f9b065b7 100644 --- a/test/jdk/java/net/httpclient/AltServiceUsageTest.java +++ b/test/jdk/java/net/httpclient/AltServiceUsageTest.java @@ -56,7 +56,7 @@ import org.junit.jupiter.api.Test; * * @run junit/othervm -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.HttpClient.log=requests,responses,errors - * AltServiceUsageTest + * ${test.main.class} */ public class AltServiceUsageTest implements HttpServerAdapters { diff --git a/test/jdk/java/net/httpclient/AsFileDownloadTest.java b/test/jdk/java/net/httpclient/AsFileDownloadTest.java index 6e9c4e676cf..fca920cb13c 100644 --- a/test/jdk/java/net/httpclient/AsFileDownloadTest.java +++ b/test/jdk/java/net/httpclient/AsFileDownloadTest.java @@ -87,7 +87,7 @@ import org.junit.jupiter.params.provider.MethodSource; * jdk.test.lib.Platform jdk.test.lib.util.FileUtils * jdk.httpclient.test.lib.common.HttpServerAdapters * jdk.httpclient.test.lib.common.TestServerConfigurator - * @run junit/othervm/timeout=480 AsFileDownloadTest + * @run junit/othervm/timeout=480 ${test.main.class} */ public class AsFileDownloadTest { diff --git a/test/jdk/java/net/httpclient/AsyncExecutorShutdown.java b/test/jdk/java/net/httpclient/AsyncExecutorShutdown.java index 308288bb9bf..ed2482e80b5 100644 --- a/test/jdk/java/net/httpclient/AsyncExecutorShutdown.java +++ b/test/jdk/java/net/httpclient/AsyncExecutorShutdown.java @@ -32,7 +32,7 @@ * @run junit/othervm * -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.HttpClient.log=trace,headers,requests - * AsyncExecutorShutdown + * ${test.main.class} */ // -Djdk.internal.httpclient.debug=true diff --git a/test/jdk/java/net/httpclient/AsyncShutdownNow.java b/test/jdk/java/net/httpclient/AsyncShutdownNow.java index 7dc13cf08e2..39e13b782c9 100644 --- a/test/jdk/java/net/httpclient/AsyncShutdownNow.java +++ b/test/jdk/java/net/httpclient/AsyncShutdownNow.java @@ -34,7 +34,7 @@ * @run junit/othervm * -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.HttpClient.log=trace,headers,requests - * AsyncShutdownNow + * ${test.main.class} */ // -Djdk.internal.httpclient.debug=true diff --git a/test/jdk/java/net/httpclient/AuthFilterCacheTest.java b/test/jdk/java/net/httpclient/AuthFilterCacheTest.java index 0d87055ff51..9fb231de858 100644 --- a/test/jdk/java/net/httpclient/AuthFilterCacheTest.java +++ b/test/jdk/java/net/httpclient/AuthFilterCacheTest.java @@ -67,7 +67,7 @@ import org.junit.jupiter.params.provider.MethodSource; * @run junit/othervm -Dtest.requiresHost=true * -Djdk.httpclient.HttpClient.log=requests,headers,errors,quic * -Djdk.internal.httpclient.debug=false - * AuthFilterCacheTest + * ${test.main.class} */ public class AuthFilterCacheTest implements HttpServerAdapters { diff --git a/test/jdk/java/net/httpclient/AuthSchemesTest.java b/test/jdk/java/net/httpclient/AuthSchemesTest.java index 8e0231c8eaf..128cae0ed20 100644 --- a/test/jdk/java/net/httpclient/AuthSchemesTest.java +++ b/test/jdk/java/net/httpclient/AuthSchemesTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * 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 8217237 * @library /test/lib * @modules java.net.http - * @run main/othervm AuthSchemesTest + * @run main/othervm ${test.main.class} * @summary HttpClient does not deal well with multi-valued WWW-Authenticate challenge headers */ diff --git a/test/jdk/java/net/httpclient/BasicAuthTest.java b/test/jdk/java/net/httpclient/BasicAuthTest.java index fc1f1d4e5aa..f9458fff6a6 100644 --- a/test/jdk/java/net/httpclient/BasicAuthTest.java +++ b/test/jdk/java/net/httpclient/BasicAuthTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * 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 8087112 * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.httpclient.test.lib.common.HttpServerAdapters jdk.test.lib.net.SimpleSSLContext - * @run main/othervm BasicAuthTest + * @run main/othervm ${test.main.class} * @summary Basic Authentication Test */ diff --git a/test/jdk/java/net/httpclient/BasicHTTP2Test.java b/test/jdk/java/net/httpclient/BasicHTTP2Test.java index 4175aceea3d..6f53dd1081c 100644 --- a/test/jdk/java/net/httpclient/BasicHTTP2Test.java +++ b/test/jdk/java/net/httpclient/BasicHTTP2Test.java @@ -29,7 +29,7 @@ * ReferenceTracker * @run junit/othervm -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.HttpClient.log=requests,responses,errors - * BasicHTTP2Test + * ${test.main.class} * @summary Basic HTTP/2 test when HTTP/3 is requested */ diff --git a/test/jdk/java/net/httpclient/BasicHTTP3Test.java b/test/jdk/java/net/httpclient/BasicHTTP3Test.java index aec21e421f9..b3764016818 100644 --- a/test/jdk/java/net/httpclient/BasicHTTP3Test.java +++ b/test/jdk/java/net/httpclient/BasicHTTP3Test.java @@ -76,7 +76,7 @@ import org.junit.jupiter.params.provider.MethodSource; * @run junit/othervm -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.HttpClient.log=requests,responses,errors * -Djavax.net.debug=all - * BasicHTTP3Test + * ${test.main.class} * @summary Basic HTTP/3 test */ public class BasicHTTP3Test implements HttpServerAdapters { diff --git a/test/jdk/java/net/httpclient/BasicRedirectTest.java b/test/jdk/java/net/httpclient/BasicRedirectTest.java index d873a64bb1b..44e3cadd8cd 100644 --- a/test/jdk/java/net/httpclient/BasicRedirectTest.java +++ b/test/jdk/java/net/httpclient/BasicRedirectTest.java @@ -29,7 +29,7 @@ * @run junit/othervm * -Djdk.httpclient.HttpClient.log=trace,headers,requests * -Djdk.internal.httpclient.debug=true - * BasicRedirectTest + * ${test.main.class} */ import java.io.IOException; diff --git a/test/jdk/java/net/httpclient/BodyProcessorInputStreamTest.java b/test/jdk/java/net/httpclient/BodyProcessorInputStreamTest.java index 1f316c2a64d..c82910cc76b 100644 --- a/test/jdk/java/net/httpclient/BodyProcessorInputStreamTest.java +++ b/test/jdk/java/net/httpclient/BodyProcessorInputStreamTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,7 +41,7 @@ import static java.lang.System.err; * @test * @bug 8187503 * @summary An example on how to read a response body with InputStream. - * @run main/othervm/manual -Dtest.debug=true BodyProcessorInputStreamTest + * @run main/othervm/manual -Dtest.debug=true ${test.main.class} * @author daniel fuchs */ public class BodyProcessorInputStreamTest { diff --git a/test/jdk/java/net/httpclient/BodySubscribersTest.java b/test/jdk/java/net/httpclient/BodySubscribersTest.java index abd86693b83..f27642a47a6 100644 --- a/test/jdk/java/net/httpclient/BodySubscribersTest.java +++ b/test/jdk/java/net/httpclient/BodySubscribersTest.java @@ -25,7 +25,7 @@ * @test * @summary Basic test for the standard BodySubscribers default behavior * @bug 8225583 8334028 - * @run junit BodySubscribersTest + * @run junit ${test.main.class} */ import java.net.http.HttpResponse.BodySubscriber; diff --git a/test/jdk/java/net/httpclient/BufferSize1Test.java b/test/jdk/java/net/httpclient/BufferSize1Test.java index e4f2b998cc7..2d7f34f315a 100644 --- a/test/jdk/java/net/httpclient/BufferSize1Test.java +++ b/test/jdk/java/net/httpclient/BufferSize1Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -54,7 +54,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; * to its lowest possible value, 1, does not wedge the client * @library /test/jdk/java/net/httpclient/lib * /test/lib - * @run junit/othervm -Djdk.httpclient.bufsize=1 BufferSize1Test + * @run junit/othervm -Djdk.httpclient.bufsize=1 ${test.main.class} */ class BufferSize1Test implements HttpServerAdapters { diff --git a/test/jdk/java/net/httpclient/BufferSizePropertyClampTest.java b/test/jdk/java/net/httpclient/BufferSizePropertyClampTest.java index d9695dce3cb..f5f77bb4778 100644 --- a/test/jdk/java/net/httpclient/BufferSizePropertyClampTest.java +++ b/test/jdk/java/net/httpclient/BufferSizePropertyClampTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * 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,15 +49,15 @@ import static org.junit.jupiter.api.Assertions.assertEquals; * @run junit/othervm * -Djdk.httpclient.HttpClient.log=errors * -Djdk.httpclient.bufsize=-1 - * BufferSizePropertyClampTest + * ${test.main.class} * @run junit/othervm * -Djdk.httpclient.HttpClient.log=errors * -Djdk.httpclient.bufsize=0 - * BufferSizePropertyClampTest + * ${test.main.class} * @run junit/othervm * -Djdk.httpclient.HttpClient.log=errors * -Djdk.httpclient.bufsize=16385 - * BufferSizePropertyClampTest + * ${test.main.class} */ class BufferSizePropertyClampTest { diff --git a/test/jdk/java/net/httpclient/BufferingSubscriberCancelTest.java b/test/jdk/java/net/httpclient/BufferingSubscriberCancelTest.java index 4d73ec31280..dbcfae4d476 100644 --- a/test/jdk/java/net/httpclient/BufferingSubscriberCancelTest.java +++ b/test/jdk/java/net/httpclient/BufferingSubscriberCancelTest.java @@ -46,7 +46,7 @@ import org.junit.jupiter.params.provider.MethodSource; /* * @test * @summary Direct test for HttpResponse.BodySubscriber.buffering() cancellation - * @run junit/othervm BufferingSubscriberCancelTest + * @run junit/othervm ${test.main.class} */ public class BufferingSubscriberCancelTest { diff --git a/test/jdk/java/net/httpclient/BufferingSubscriberErrorCompleteTest.java b/test/jdk/java/net/httpclient/BufferingSubscriberErrorCompleteTest.java index 255946232be..5895df7d3dc 100644 --- a/test/jdk/java/net/httpclient/BufferingSubscriberErrorCompleteTest.java +++ b/test/jdk/java/net/httpclient/BufferingSubscriberErrorCompleteTest.java @@ -44,7 +44,7 @@ import org.junit.jupiter.params.provider.MethodSource; /* * @test * @summary Test for HttpResponse.BodySubscriber.buffering() onError/onComplete - * @run junit/othervm BufferingSubscriberErrorCompleteTest + * @run junit/othervm ${test.main.class} */ public class BufferingSubscriberErrorCompleteTest { diff --git a/test/jdk/java/net/httpclient/BufferingSubscriberTest.java b/test/jdk/java/net/httpclient/BufferingSubscriberTest.java index bb33b18ed9c..7957c7ab6ae 100644 --- a/test/jdk/java/net/httpclient/BufferingSubscriberTest.java +++ b/test/jdk/java/net/httpclient/BufferingSubscriberTest.java @@ -55,7 +55,7 @@ import org.junit.jupiter.params.provider.MethodSource; * @key randomness * @library /test/lib * @build jdk.test.lib.RandomFactory - * @run junit/othervm/timeout=480 -Djdk.internal.httpclient.debug=true BufferingSubscriberTest + * @run junit/othervm/timeout=480 -Djdk.internal.httpclient.debug=true ${test.main.class} */ public class BufferingSubscriberTest { diff --git a/test/jdk/java/net/httpclient/ByteArrayPublishers.java b/test/jdk/java/net/httpclient/ByteArrayPublishers.java index 114ebcd18a5..b42c2c4613e 100644 --- a/test/jdk/java/net/httpclient/ByteArrayPublishers.java +++ b/test/jdk/java/net/httpclient/ByteArrayPublishers.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,7 @@ * @test * @bug 8222968 * @summary ByteArrayPublisher is not thread-safe resulting in broken re-use of HttpRequests - * @run main/othervm -Dsun.net.httpserver.idleInterval=50000 ByteArrayPublishers + * @run main/othervm -Dsun.net.httpserver.idleInterval=50000 ${test.main.class} */ import java.net.InetAddress; diff --git a/test/jdk/java/net/httpclient/CancelRequestTest.java b/test/jdk/java/net/httpclient/CancelRequestTest.java index dcb60a55061..f21d13d5e98 100644 --- a/test/jdk/java/net/httpclient/CancelRequestTest.java +++ b/test/jdk/java/net/httpclient/CancelRequestTest.java @@ -31,7 +31,7 @@ * ReferenceTracker CancelRequestTest * @run junit/othervm -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.enableAllMethodRetry=true - * CancelRequestTest + * ${test.main.class} */ // * -Dseed=3582896013206826205L // * -Dseed=5784221742235559231L diff --git a/test/jdk/java/net/httpclient/CancelStreamedBodyTest.java b/test/jdk/java/net/httpclient/CancelStreamedBodyTest.java index 48f23ebf370..000602d3c0c 100644 --- a/test/jdk/java/net/httpclient/CancelStreamedBodyTest.java +++ b/test/jdk/java/net/httpclient/CancelStreamedBodyTest.java @@ -30,7 +30,7 @@ * @build jdk.httpclient.test.lib.common.HttpServerAdapters jdk.test.lib.net.SimpleSSLContext * ReferenceTracker CancelStreamedBodyTest * @run junit/othervm -Djdk.internal.httpclient.debug=true - * CancelStreamedBodyTest + * ${test.main.class} */ import jdk.test.lib.net.SimpleSSLContext; diff --git a/test/jdk/java/net/httpclient/CancelledPartialResponseTest.java b/test/jdk/java/net/httpclient/CancelledPartialResponseTest.java index 33df36100ad..5b4d2bff1c2 100644 --- a/test/jdk/java/net/httpclient/CancelledPartialResponseTest.java +++ b/test/jdk/java/net/httpclient/CancelledPartialResponseTest.java @@ -29,7 +29,7 @@ * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.httpclient.test.lib.common.HttpServerAdapters * @run junit/othervm/timeout=40 -Djdk.internal.httpclient.debug=false -Djdk.httpclient.HttpClient.log=trace,errors,headers - * CancelledPartialResponseTest + * ${test.main.class} */ import jdk.httpclient.test.lib.common.HttpServerAdapters; diff --git a/test/jdk/java/net/httpclient/CancelledResponse.java b/test/jdk/java/net/httpclient/CancelledResponse.java index 5449a68418a..d1ead0abad6 100644 --- a/test/jdk/java/net/httpclient/CancelledResponse.java +++ b/test/jdk/java/net/httpclient/CancelledResponse.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ import static java.net.http.HttpOption.Http3DiscoveryMode.ALT_SVC; * @modules java.net.http/jdk.internal.net.http.common * @build jdk.test.lib.net.SimpleSSLContext * @build MockServer ReferenceTracker - * @run main/othervm/timeout=480 CancelledResponse - * @run main/othervm/timeout=480 CancelledResponse SSL + * @run main/othervm/timeout=480 ${test.main.class} + * @run main/othervm/timeout=480 ${test.main.class} SSL */ /** diff --git a/test/jdk/java/net/httpclient/CancelledResponse2.java b/test/jdk/java/net/httpclient/CancelledResponse2.java index 6604fadea20..d08fd027bb5 100644 --- a/test/jdk/java/net/httpclient/CancelledResponse2.java +++ b/test/jdk/java/net/httpclient/CancelledResponse2.java @@ -66,7 +66,7 @@ import org.junit.jupiter.params.provider.MethodSource; * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.test.lib.net.SimpleSSLContext * @compile ReferenceTracker.java - * @run junit/othervm -Djdk.internal.httpclient.debug=true CancelledResponse2 + * @run junit/othervm -Djdk.internal.httpclient.debug=true ${test.main.class} */ // -Djdk.internal.httpclient.debug=true public class CancelledResponse2 implements HttpServerAdapters { diff --git a/test/jdk/java/net/httpclient/ConcurrentResponses.java b/test/jdk/java/net/httpclient/ConcurrentResponses.java index 53c85b8e383..e1f48e1251b 100644 --- a/test/jdk/java/net/httpclient/ConcurrentResponses.java +++ b/test/jdk/java/net/httpclient/ConcurrentResponses.java @@ -31,7 +31,7 @@ * jdk.httpclient.test.lib.common.TestServerConfigurator * @run junit/othervm * -Djdk.internal.httpclient.debug=true - * ConcurrentResponses + * ${test.main.class} */ //* -Djdk.internal.httpclient.HttpClient.log=all diff --git a/test/jdk/java/net/httpclient/ConnectExceptionTest.java b/test/jdk/java/net/httpclient/ConnectExceptionTest.java index 0745e2af934..22ba26c3ac8 100644 --- a/test/jdk/java/net/httpclient/ConnectExceptionTest.java +++ b/test/jdk/java/net/httpclient/ConnectExceptionTest.java @@ -25,7 +25,7 @@ * @test * @summary Expect ConnectException for all non-security related connect errors * @bug 8204864 - * @run junit/othervm -Djdk.net.hosts.file=HostFileDoesNotExist ConnectExceptionTest + * @run junit/othervm -Djdk.net.hosts.file=HostFileDoesNotExist ${test.main.class} */ import java.io.IOException; diff --git a/test/jdk/java/net/httpclient/ConnectTimeoutHandshakeAsync.java b/test/jdk/java/net/httpclient/ConnectTimeoutHandshakeAsync.java index e1f4aee1d51..d91c73f97a1 100644 --- a/test/jdk/java/net/httpclient/ConnectTimeoutHandshakeAsync.java +++ b/test/jdk/java/net/httpclient/ConnectTimeoutHandshakeAsync.java @@ -33,7 +33,7 @@ import org.junit.jupiter.params.provider.MethodSource; * @bug 8208391 * @library /test/lib * @build AbstractConnectTimeoutHandshake - * @run junit/othervm ConnectTimeoutHandshakeAsync + * @run junit/othervm ${test.main.class} */ public class ConnectTimeoutHandshakeAsync diff --git a/test/jdk/java/net/httpclient/ConnectTimeoutHandshakeSync.java b/test/jdk/java/net/httpclient/ConnectTimeoutHandshakeSync.java index eb571b2d16c..fac007df8ad 100644 --- a/test/jdk/java/net/httpclient/ConnectTimeoutHandshakeSync.java +++ b/test/jdk/java/net/httpclient/ConnectTimeoutHandshakeSync.java @@ -33,7 +33,7 @@ import org.junit.jupiter.params.provider.MethodSource; * @bug 8208391 * @library /test/lib * @build AbstractConnectTimeoutHandshake - * @run junit/othervm ConnectTimeoutHandshakeSync + * @run junit/othervm ${test.main.class} */ public class ConnectTimeoutHandshakeSync diff --git a/test/jdk/java/net/httpclient/ContentLengthHeaderTest.java b/test/jdk/java/net/httpclient/ContentLengthHeaderTest.java index 01c166dcb1b..c90ba1ffdf3 100644 --- a/test/jdk/java/net/httpclient/ContentLengthHeaderTest.java +++ b/test/jdk/java/net/httpclient/ContentLengthHeaderTest.java @@ -33,7 +33,7 @@ * @run junit/othervm * -Djdk.httpclient.allowRestrictedHeaders=content-length * -Djdk.internal.httpclient.debug=true - * ContentLengthHeaderTest + * ${test.main.class} */ diff --git a/test/jdk/java/net/httpclient/CookieHeaderTest.java b/test/jdk/java/net/httpclient/CookieHeaderTest.java index 62e62680e03..74faf8ec801 100644 --- a/test/jdk/java/net/httpclient/CookieHeaderTest.java +++ b/test/jdk/java/net/httpclient/CookieHeaderTest.java @@ -30,7 +30,7 @@ * @run junit/othervm * -Djdk.tls.acknowledgeCloseNotify=true * -Djdk.httpclient.HttpClient.log=trace,headers,requests - * CookieHeaderTest + * ${test.main.class} */ import jdk.test.lib.net.SimpleSSLContext; diff --git a/test/jdk/java/net/httpclient/CustomRequestPublisher.java b/test/jdk/java/net/httpclient/CustomRequestPublisher.java index c8d22419852..58acfc4feac 100644 --- a/test/jdk/java/net/httpclient/CustomRequestPublisher.java +++ b/test/jdk/java/net/httpclient/CustomRequestPublisher.java @@ -26,7 +26,7 @@ * @summary Checks correct handling of Publishers that call onComplete without demand * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.httpclient.test.lib.http2.Http2TestServer jdk.test.lib.net.SimpleSSLContext - * @run junit/othervm CustomRequestPublisher + * @run junit/othervm ${test.main.class} */ import java.net.InetAddress; diff --git a/test/jdk/java/net/httpclient/CustomResponseSubscriber.java b/test/jdk/java/net/httpclient/CustomResponseSubscriber.java index b2695271035..ef5d0a30552 100644 --- a/test/jdk/java/net/httpclient/CustomResponseSubscriber.java +++ b/test/jdk/java/net/httpclient/CustomResponseSubscriber.java @@ -27,7 +27,7 @@ * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.test.lib.net.SimpleSSLContext jdk.httpclient.test.lib.http2.Http2TestServer * jdk.httpclient.test.lib.common.TestServerConfigurator - * @run junit/othervm CustomResponseSubscriber + * @run junit/othervm ${test.main.class} */ import java.io.IOException; diff --git a/test/jdk/java/net/httpclient/DebugLoggerTest.java b/test/jdk/java/net/httpclient/DebugLoggerTest.java index 8d81e5cbe69..a5d16e65993 100644 --- a/test/jdk/java/net/httpclient/DebugLoggerTest.java +++ b/test/jdk/java/net/httpclient/DebugLoggerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * 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,17 +52,17 @@ import static java.nio.charset.StandardCharsets.UTF_8; * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.httpclient.test.lib.common.HttpServerAdapters jdk.test.lib.net.SimpleSSLContext * DebugLoggerTest - * @run main/othervm DebugLoggerTest - * @run main/othervm -Djdk.internal.httpclient.debug=errr DebugLoggerTest - * @run main/othervm -Djdk.internal.httpclient.debug=err DebugLoggerTest ERR - * @run main/othervm -Djdk.internal.httpclient.debug=out DebugLoggerTest OUT - * @run main/othervm -Djdk.internal.httpclient.debug=log DebugLoggerTest LOG - * @run main/othervm -Djdk.internal.httpclient.debug=true DebugLoggerTest ERR LOG - * @run main/othervm -Djdk.internal.httpclient.debug=err,OUT DebugLoggerTest ERR OUT - * @run main/othervm -Djdk.internal.httpclient.debug=err,out,log DebugLoggerTest ERR OUT LOG - * @run main/othervm -Djdk.internal.httpclient.debug=true,log DebugLoggerTest ERR LOG - * @run main/othervm -Djdk.internal.httpclient.debug=true,out DebugLoggerTest ERR OUT LOG - * @run main/othervm -Djdk.internal.httpclient.debug=err,OUT,foo DebugLoggerTest ERR OUT + * @run main/othervm ${test.main.class} + * @run main/othervm -Djdk.internal.httpclient.debug=errr ${test.main.class} + * @run main/othervm -Djdk.internal.httpclient.debug=err ${test.main.class} ERR + * @run main/othervm -Djdk.internal.httpclient.debug=out ${test.main.class} OUT + * @run main/othervm -Djdk.internal.httpclient.debug=log ${test.main.class} LOG + * @run main/othervm -Djdk.internal.httpclient.debug=true ${test.main.class} ERR LOG + * @run main/othervm -Djdk.internal.httpclient.debug=err,OUT ${test.main.class} ERR OUT + * @run main/othervm -Djdk.internal.httpclient.debug=err,out,log ${test.main.class} ERR OUT LOG + * @run main/othervm -Djdk.internal.httpclient.debug=true,log ${test.main.class} ERR LOG + * @run main/othervm -Djdk.internal.httpclient.debug=true,out ${test.main.class} ERR OUT LOG + * @run main/othervm -Djdk.internal.httpclient.debug=err,OUT,foo ${test.main.class} ERR OUT */ public class DebugLoggerTest { static final PrintStream stdErr = System.err; diff --git a/test/jdk/java/net/httpclient/DependentActionsTest.java b/test/jdk/java/net/httpclient/DependentActionsTest.java index fcfbb393e5a..571e124ca5d 100644 --- a/test/jdk/java/net/httpclient/DependentActionsTest.java +++ b/test/jdk/java/net/httpclient/DependentActionsTest.java @@ -31,7 +31,7 @@ * DependentActionsTest * @run junit/othervm -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.quic.maxPtoBackoff=9 - * DependentActionsTest + * ${test.main.class} */ import java.io.BufferedReader; diff --git a/test/jdk/java/net/httpclient/DependentPromiseActionsTest.java b/test/jdk/java/net/httpclient/DependentPromiseActionsTest.java index e045f4e22f1..42d2b509c1b 100644 --- a/test/jdk/java/net/httpclient/DependentPromiseActionsTest.java +++ b/test/jdk/java/net/httpclient/DependentPromiseActionsTest.java @@ -29,7 +29,7 @@ * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.httpclient.test.lib.common.HttpServerAdapters jdk.test.lib.net.SimpleSSLContext * DependentPromiseActionsTest - * @run junit/othervm -Djdk.internal.httpclient.debug=true DependentPromiseActionsTest + * @run junit/othervm -Djdk.internal.httpclient.debug=true ${test.main.class} */ import java.io.BufferedReader; diff --git a/test/jdk/java/net/httpclient/DigestEchoClient.java b/test/jdk/java/net/httpclient/DigestEchoClient.java index 6df4ccac9fb..6fbffab95ea 100644 --- a/test/jdk/java/net/httpclient/DigestEchoClient.java +++ b/test/jdk/java/net/httpclient/DigestEchoClient.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,10 +72,10 @@ import static java.net.http.HttpOption.H3_DISCOVERY; * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.httpclient.test.lib.common.HttpServerAdapters jdk.test.lib.net.SimpleSSLContext * DigestEchoServer ReferenceTracker DigestEchoClient - * @run main/othervm DigestEchoClient + * @run main/othervm ${test.main.class} * @run main/othervm -Djdk.http.auth.proxying.disabledSchemes= * -Djdk.http.auth.tunneling.disabledSchemes= - * DigestEchoClient + * ${test.main.class} */ public class DigestEchoClient { diff --git a/test/jdk/java/net/httpclient/DigestEchoClientSSL.java b/test/jdk/java/net/httpclient/DigestEchoClientSSL.java index ecf043f58c8..25dfaf71fc0 100644 --- a/test/jdk/java/net/httpclient/DigestEchoClientSSL.java +++ b/test/jdk/java/net/httpclient/DigestEchoClientSSL.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,17 +33,17 @@ * @run main/othervm/timeout=300 * -Djdk.internal.httpclient.debug=err * -Djdk.httpclient.HttpClient.log=headers - * DigestEchoClientSSL SSL SERVER307 + * ${test.main.class} SSL SERVER307 * @run main/othervm/timeout=300 * -Djdk.httpclient.http3.maxDirectConnectionTimeout=100 * -Djdk.httpclient.HttpClient.log=headers - * DigestEchoClientSSL SSL SERVER PROXY + * ${test.main.class} SSL SERVER PROXY * @run main/othervm/timeout=300 * -Djdk.http.auth.proxying.disabledSchemes= * -Djdk.http.auth.tunneling.disabledSchemes= * -Djdk.httpclient.http3.maxDirectConnectionTimeout=100 * -Djdk.httpclient.HttpClient.log=headers - * DigestEchoClientSSL SSL PROXY + * ${test.main.class} SSL PROXY * */ diff --git a/test/jdk/java/net/httpclient/DurationOverflowTest.java b/test/jdk/java/net/httpclient/DurationOverflowTest.java index 1beb31f74e5..12a852262a6 100644 --- a/test/jdk/java/net/httpclient/DurationOverflowTest.java +++ b/test/jdk/java/net/httpclient/DurationOverflowTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -64,7 +64,7 @@ import static jdk.httpclient.test.lib.common.HttpServerAdapters.createClientBuil * @library /test/jdk/java/net/httpclient/lib * /test/lib * - * @run junit DurationOverflowTest + * @run junit ${test.main.class} */ /* @@ -81,19 +81,19 @@ import static jdk.httpclient.test.lib.common.HttpServerAdapters.createClientBuil * * @run junit/othervm * -Djdk.httpclient.keepalive.timeout=9223372036854775807 - * DurationOverflowTest + * ${test.main.class} * * @comment `h3` infra is also enabled for this test since `j.h.k.timeout.h3` * defaults to `j.h.k.timeout.h2` * @run junit/othervm * -Djdk.httpclient.keepalive.timeout.h2=9223372036854775807 * -DallowedInfras=h2,h2s,h3 - * DurationOverflowTest + * ${test.main.class} * * @run junit/othervm * -Djdk.httpclient.keepalive.timeout.h3=9223372036854775807 * -DallowedInfras=h3 - * DurationOverflowTest + * ${test.main.class} */ public class DurationOverflowTest { diff --git a/test/jdk/java/net/httpclient/EmptyAuthenticate.java b/test/jdk/java/net/httpclient/EmptyAuthenticate.java index 81bbbf3ca5b..4da5592fb85 100644 --- a/test/jdk/java/net/httpclient/EmptyAuthenticate.java +++ b/test/jdk/java/net/httpclient/EmptyAuthenticate.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ * /test/lib * @build jdk.httpclient.test.lib.common.HttpServerAdapters * jdk.test.lib.net.SimpleSSLContext - * @run junit EmptyAuthenticate + * @run junit ${test.main.class} */ import jdk.httpclient.test.lib.common.HttpServerAdapters; diff --git a/test/jdk/java/net/httpclient/EncodedCharsInURI.java b/test/jdk/java/net/httpclient/EncodedCharsInURI.java index 19b0a1d651b..3c8483a4c6d 100644 --- a/test/jdk/java/net/httpclient/EncodedCharsInURI.java +++ b/test/jdk/java/net/httpclient/EncodedCharsInURI.java @@ -32,7 +32,7 @@ * @run junit/othervm * -Djdk.tls.acknowledgeCloseNotify=true * -Djdk.internal.httpclient.debug=true - * -Djdk.httpclient.HttpClient.log=headers,errors EncodedCharsInURI + * -Djdk.httpclient.HttpClient.log=headers,errors ${test.main.class} */ //* -Djdk.internal.httpclient.debug=true diff --git a/test/jdk/java/net/httpclient/EscapedOctetsInURI.java b/test/jdk/java/net/httpclient/EscapedOctetsInURI.java index 6ef71b7d22d..406f82501b1 100644 --- a/test/jdk/java/net/httpclient/EscapedOctetsInURI.java +++ b/test/jdk/java/net/httpclient/EscapedOctetsInURI.java @@ -29,7 +29,7 @@ * @build jdk.httpclient.test.lib.http2.Http2TestServer jdk.test.lib.net.SimpleSSLContext * @run junit/othervm * -Djdk.httpclient.HttpClient.log=reqeusts,headers - * EscapedOctetsInURI + * ${test.main.class} */ import java.io.Closeable; diff --git a/test/jdk/java/net/httpclient/ExecutorShutdown.java b/test/jdk/java/net/httpclient/ExecutorShutdown.java index a46ea66f3ae..d12a9f3e5d7 100644 --- a/test/jdk/java/net/httpclient/ExecutorShutdown.java +++ b/test/jdk/java/net/httpclient/ExecutorShutdown.java @@ -32,7 +32,7 @@ * @run junit/othervm * -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.HttpClient.log=trace,headers,requests - * ExecutorShutdown + * ${test.main.class} */ // -Djdk.internal.httpclient.debug=true diff --git a/test/jdk/java/net/httpclient/ExpectContinue.java b/test/jdk/java/net/httpclient/ExpectContinue.java index e9ae894f3e1..656a887002f 100644 --- a/test/jdk/java/net/httpclient/ExpectContinue.java +++ b/test/jdk/java/net/httpclient/ExpectContinue.java @@ -28,7 +28,7 @@ * @build jdk.test.lib.net.SimpleSSLContext jdk.httpclient.test.lib.common.TestServerConfigurator * @modules java.net.http/jdk.internal.net.http.common * jdk.httpserver - * @run junit/othervm ExpectContinue + * @run junit/othervm ${test.main.class} */ import com.sun.net.httpserver.HttpExchange; diff --git a/test/jdk/java/net/httpclient/ExpectContinueTest.java b/test/jdk/java/net/httpclient/ExpectContinueTest.java index 56fa363870a..0233ffb069c 100644 --- a/test/jdk/java/net/httpclient/ExpectContinueTest.java +++ b/test/jdk/java/net/httpclient/ExpectContinueTest.java @@ -27,7 +27,7 @@ * @bug 8286171 8307648 * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.httpclient.test.lib.common.HttpServerAdapters - * @run junit/othervm -Djdk.internal.httpclient.debug=true -Djdk.httpclient.HttpClient.log=errors ExpectContinueTest + * @run junit/othervm -Djdk.internal.httpclient.debug=true -Djdk.httpclient.HttpClient.log=errors ${test.main.class} */ diff --git a/test/jdk/java/net/httpclient/FilePublisherTest.java b/test/jdk/java/net/httpclient/FilePublisherTest.java index 292f770fc30..dafb6e593b2 100644 --- a/test/jdk/java/net/httpclient/FilePublisherTest.java +++ b/test/jdk/java/net/httpclient/FilePublisherTest.java @@ -29,7 +29,7 @@ * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.httpclient.test.lib.common.HttpServerAdapters * jdk.test.lib.net.SimpleSSLContext - * @run junit/othervm FilePublisherTest + * @run junit/othervm ${test.main.class} */ import jdk.test.lib.net.SimpleSSLContext; diff --git a/test/jdk/java/net/httpclient/FlowAdapterPublisherTest.java b/test/jdk/java/net/httpclient/FlowAdapterPublisherTest.java index 7fd3061aa3c..31dd6d560de 100644 --- a/test/jdk/java/net/httpclient/FlowAdapterPublisherTest.java +++ b/test/jdk/java/net/httpclient/FlowAdapterPublisherTest.java @@ -64,7 +64,7 @@ import org.junit.jupiter.params.provider.MethodSource; * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.httpclient.test.lib.common.HttpServerAdapters * jdk.test.lib.net.SimpleSSLContext - * @run junit/othervm -Djdk.internal.httpclient.debug=err FlowAdapterPublisherTest + * @run junit/othervm -Djdk.internal.httpclient.debug=err ${test.main.class} */ public class FlowAdapterPublisherTest implements HttpServerAdapters { diff --git a/test/jdk/java/net/httpclient/FlowAdapterSubscriberTest.java b/test/jdk/java/net/httpclient/FlowAdapterSubscriberTest.java index 32003023d7f..e85a752940c 100644 --- a/test/jdk/java/net/httpclient/FlowAdapterSubscriberTest.java +++ b/test/jdk/java/net/httpclient/FlowAdapterSubscriberTest.java @@ -74,7 +74,7 @@ import org.junit.jupiter.params.provider.MethodSource; * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.httpclient.test.lib.common.HttpServerAdapters * jdk.test.lib.net.SimpleSSLContext - * @run junit/othervm -Djdk.internal.httpclient.debug=true FlowAdapterSubscriberTest + * @run junit/othervm -Djdk.internal.httpclient.debug=true ${test.main.class} */ public class FlowAdapterSubscriberTest implements HttpServerAdapters { diff --git a/test/jdk/java/net/httpclient/ForbiddenHeadTest.java b/test/jdk/java/net/httpclient/ForbiddenHeadTest.java index f2011766b2b..0a6824d289d 100644 --- a/test/jdk/java/net/httpclient/ForbiddenHeadTest.java +++ b/test/jdk/java/net/httpclient/ForbiddenHeadTest.java @@ -32,7 +32,7 @@ * -Djdk.http.auth.tunneling.disabledSchemes * -Djdk.httpclient.HttpClient.log=headers,requests * -Djdk.internal.httpclient.debug=true - * ForbiddenHeadTest + * ${test.main.class} */ import jdk.test.lib.net.SimpleSSLContext; diff --git a/test/jdk/java/net/httpclient/GZIPInputStreamTest.java b/test/jdk/java/net/httpclient/GZIPInputStreamTest.java index 1cbb24d81ce..8e34f100524 100644 --- a/test/jdk/java/net/httpclient/GZIPInputStreamTest.java +++ b/test/jdk/java/net/httpclient/GZIPInputStreamTest.java @@ -27,7 +27,7 @@ * @summary Tests that you can map an InputStream to a GZIPInputStream * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.test.lib.net.SimpleSSLContext jdk.httpclient.test.lib.common.HttpServerAdapters ReferenceTracker - * @run junit/othervm GZIPInputStreamTest + * @run junit/othervm ${test.main.class} */ import com.sun.net.httpserver.HttpServer; diff --git a/test/jdk/java/net/httpclient/HandshakeFailureTest.java b/test/jdk/java/net/httpclient/HandshakeFailureTest.java index e07dfacbd85..e9e23753ed3 100644 --- a/test/jdk/java/net/httpclient/HandshakeFailureTest.java +++ b/test/jdk/java/net/httpclient/HandshakeFailureTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * 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,15 @@ import javax.net.ssl.SSLSocket; /** * @test * @bug 8238990 8258951 - * @run main/othervm -Djdk.internal.httpclient.debug=true HandshakeFailureTest TLSv1.2 - * @run main/othervm -Djdk.internal.httpclient.debug=true HandshakeFailureTest TLSv1.3 + * @run main/othervm -Djdk.internal.httpclient.debug=true ${test.main.class} TLSv1.2 + * @run main/othervm -Djdk.internal.httpclient.debug=true ${test.main.class} TLSv1.3 * @summary Verify SSLHandshakeException is received when the handshake fails, * either because the server closes (EOF) the connection during handshaking, * or no cipher suite can be negotiated (TLSv1.2) or no available authentication * scheme (TLSv1.3). */ // To switch on debugging use: -// @run main/othervm -Djdk.internal.httpclient.debug=true HandshakeFailureTest +// @run main/othervm -Djdk.internal.httpclient.debug=true ${test.main.class} public class HandshakeFailureTest { // The number of iterations each testXXXClient performs. Can be increased diff --git a/test/jdk/java/net/httpclient/HeadTest.java b/test/jdk/java/net/httpclient/HeadTest.java index 3a52cd101b8..c0bef240520 100644 --- a/test/jdk/java/net/httpclient/HeadTest.java +++ b/test/jdk/java/net/httpclient/HeadTest.java @@ -27,7 +27,7 @@ * @summary Tests Client handles HEAD and 304 responses correctly. * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.test.lib.net.SimpleSSLContext - * @run junit/othervm -Djdk.httpclient.HttpClient.log=trace,headers,requests HeadTest + * @run junit/othervm -Djdk.httpclient.HttpClient.log=trace,headers,requests ${test.main.class} */ import jdk.test.lib.net.SimpleSSLContext; diff --git a/test/jdk/java/net/httpclient/HeadersLowerCaseTest.java b/test/jdk/java/net/httpclient/HeadersLowerCaseTest.java index 00a709a3387..b082f59dd23 100644 --- a/test/jdk/java/net/httpclient/HeadersLowerCaseTest.java +++ b/test/jdk/java/net/httpclient/HeadersLowerCaseTest.java @@ -60,7 +60,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows; * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.test.lib.net.SimpleSSLContext * jdk.httpclient.test.lib.common.HttpServerAdapters - * @run junit/othervm -Djdk.internal.httpclient.debug=true HeadersLowerCaseTest + * @run junit/othervm -Djdk.internal.httpclient.debug=true ${test.main.class} */ public class HeadersLowerCaseTest implements HttpServerAdapters { diff --git a/test/jdk/java/net/httpclient/HeadersTest1.java b/test/jdk/java/net/httpclient/HeadersTest1.java index 26733c1c928..220978b419c 100644 --- a/test/jdk/java/net/httpclient/HeadersTest1.java +++ b/test/jdk/java/net/httpclient/HeadersTest1.java @@ -26,7 +26,7 @@ * @bug 8153142 8195138 * @modules java.net.http * jdk.httpserver - * @run junit/othervm HeadersTest1 + * @run junit/othervm ${test.main.class} */ import java.io.IOException; diff --git a/test/jdk/java/net/httpclient/Http1ChunkedTest.java b/test/jdk/java/net/httpclient/Http1ChunkedTest.java index f51ccf9fd38..23bcc541a18 100644 --- a/test/jdk/java/net/httpclient/Http1ChunkedTest.java +++ b/test/jdk/java/net/httpclient/Http1ChunkedTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,7 +42,7 @@ import java.util.concurrent.CompletableFuture; * @bug 8243246 * @summary Verifies that the HttpClient can accept extensions after * chunk length in a chunked response. - * @run main/othervm Http1ChunkedTest + * @run main/othervm ${test.main.class} */ public class Http1ChunkedTest { diff --git a/test/jdk/java/net/httpclient/HttpClientAuthRetryLimitTest.java b/test/jdk/java/net/httpclient/HttpClientAuthRetryLimitTest.java index 4cfee56e855..7a220c77fda 100644 --- a/test/jdk/java/net/httpclient/HttpClientAuthRetryLimitTest.java +++ b/test/jdk/java/net/httpclient/HttpClientAuthRetryLimitTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * 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,10 +28,10 @@ * @summary Auth retry limit system property * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.httpclient.test.lib.http2.Http2TestServer - * @run junit HttpClientAuthRetryLimitTest - * @run junit/othervm -Djdk.httpclient.auth.retrylimit=1 HttpClientAuthRetryLimitTest - * @run junit/othervm -Djdk.httpclient.auth.retrylimit=0 HttpClientAuthRetryLimitTest - * @run junit/othervm -Djdk.httpclient.auth.retrylimit=-1 HttpClientAuthRetryLimitTest + * @run junit ${test.main.class} + * @run junit/othervm -Djdk.httpclient.auth.retrylimit=1 ${test.main.class} + * @run junit/othervm -Djdk.httpclient.auth.retrylimit=0 ${test.main.class} + * @run junit/othervm -Djdk.httpclient.auth.retrylimit=-1 ${test.main.class} */ import jdk.httpclient.test.lib.common.HttpServerAdapters; diff --git a/test/jdk/java/net/httpclient/HttpClientBuilderTest.java b/test/jdk/java/net/httpclient/HttpClientBuilderTest.java index a5fb1a39e66..7e5db68b8d3 100644 --- a/test/jdk/java/net/httpclient/HttpClientBuilderTest.java +++ b/test/jdk/java/net/httpclient/HttpClientBuilderTest.java @@ -62,7 +62,7 @@ import org.junit.jupiter.api.Test; * @summary HttpClient[.Builder] API and behaviour checks * @library /test/lib * @build jdk.test.lib.net.SimpleSSLContext - * @run junit HttpClientBuilderTest + * @run junit ${test.main.class} */ public class HttpClientBuilderTest { diff --git a/test/jdk/java/net/httpclient/HttpClientClose.java b/test/jdk/java/net/httpclient/HttpClientClose.java index 0a3fc03424a..aa1f399ba30 100644 --- a/test/jdk/java/net/httpclient/HttpClientClose.java +++ b/test/jdk/java/net/httpclient/HttpClientClose.java @@ -34,7 +34,7 @@ * @run junit/othervm * -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.HttpClient.log=trace,headers,requests - * HttpClientClose + * ${test.main.class} */ // -Djdk.internal.httpclient.debug=true diff --git a/test/jdk/java/net/httpclient/HttpClientExceptionTest.java b/test/jdk/java/net/httpclient/HttpClientExceptionTest.java index dff7219c0c8..dc9f34868bd 100644 --- a/test/jdk/java/net/httpclient/HttpClientExceptionTest.java +++ b/test/jdk/java/net/httpclient/HttpClientExceptionTest.java @@ -41,7 +41,7 @@ import org.junit.jupiter.api.Test; * @summary The test checks if UncheckedIOException is thrown * @build HttpClientExceptionTest * @run junit/othervm -Djava.nio.channels.spi.SelectorProvider=HttpClientExceptionTest$CustomSelectorProvider - * HttpClientExceptionTest + * ${test.main.class} */ public class HttpClientExceptionTest { diff --git a/test/jdk/java/net/httpclient/HttpClientLocalAddrTest.java b/test/jdk/java/net/httpclient/HttpClientLocalAddrTest.java index f1e8aecbaa4..a98f180d082 100644 --- a/test/jdk/java/net/httpclient/HttpClientLocalAddrTest.java +++ b/test/jdk/java/net/httpclient/HttpClientLocalAddrTest.java @@ -65,7 +65,7 @@ import org.junit.jupiter.params.provider.MethodSource; * -Djdk.httpclient.HttpClient.log=frames,ssl,requests,responses,errors * -Djdk.internal.httpclient.debug=true * -Dsun.net.httpserver.idleInterval=50000 - * HttpClientLocalAddrTest + * ${test.main.class} * */ public class HttpClientLocalAddrTest implements HttpServerAdapters { diff --git a/test/jdk/java/net/httpclient/HttpClientSNITest.java b/test/jdk/java/net/httpclient/HttpClientSNITest.java index 1f7377f745d..08f725b0c52 100644 --- a/test/jdk/java/net/httpclient/HttpClientSNITest.java +++ b/test/jdk/java/net/httpclient/HttpClientSNITest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -64,7 +64,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; * @build jdk.httpclient.test.lib.common.HttpServerAdapters * jdk.test.lib.net.SimpleSSLContext * jdk.test.lib.net.URIBuilder - * @run junit HttpClientSNITest + * @run junit ${test.main.class} */ public class HttpClientSNITest { private static final String RESP_BODY_TEXT = "hello world"; diff --git a/test/jdk/java/net/httpclient/HttpClientSendAsyncExceptionTest.java b/test/jdk/java/net/httpclient/HttpClientSendAsyncExceptionTest.java index f4a1f3cca82..27562ea2277 100644 --- a/test/jdk/java/net/httpclient/HttpClientSendAsyncExceptionTest.java +++ b/test/jdk/java/net/httpclient/HttpClientSendAsyncExceptionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -57,7 +57,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; * @bug 8368249 * @summary Verifies exceptions thrown by `HttpClient::sendAsync` * @library /test/jdk/java/net/httpclient/lib /test/lib - * @run junit HttpClientSendAsyncExceptionTest + * @run junit ${test.main.class} */ class HttpClientSendAsyncExceptionTest { diff --git a/test/jdk/java/net/httpclient/HttpClientShutdown.java b/test/jdk/java/net/httpclient/HttpClientShutdown.java index 8532146c1e2..36057a025db 100644 --- a/test/jdk/java/net/httpclient/HttpClientShutdown.java +++ b/test/jdk/java/net/httpclient/HttpClientShutdown.java @@ -35,7 +35,7 @@ * @run junit/othervm * -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.HttpClient.log=trace,headers,requests - * HttpClientShutdown + * ${test.main.class} */ // -Djdk.internal.httpclient.debug=true diff --git a/test/jdk/java/net/httpclient/HttpGetInCancelledFuture.java b/test/jdk/java/net/httpclient/HttpGetInCancelledFuture.java index 80e49f20705..9ea47757402 100644 --- a/test/jdk/java/net/httpclient/HttpGetInCancelledFuture.java +++ b/test/jdk/java/net/httpclient/HttpGetInCancelledFuture.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -74,9 +74,9 @@ import static org.junit.jupiter.api.Assertions.assertTrue; * @library /test/lib /test/jdk/java/net/httpclient/lib * @build HttpGetInCancelledFuture ReferenceTracker * @run junit/othervm -DuseReferenceTracker=false - * HttpGetInCancelledFuture + * ${test.main.class} * @run junit/othervm -DuseReferenceTracker=true - * HttpGetInCancelledFuture + * ${test.main.class} * @summary This test verifies that cancelling a future that * does an HTTP request using the HttpClient doesn't cause * HttpClient::close to block forever. diff --git a/test/jdk/java/net/httpclient/HttpHeadersOf.java b/test/jdk/java/net/httpclient/HttpHeadersOf.java index 77a800b7cf2..fbddcf3e4be 100644 --- a/test/jdk/java/net/httpclient/HttpHeadersOf.java +++ b/test/jdk/java/net/httpclient/HttpHeadersOf.java @@ -24,7 +24,7 @@ /* * @test * @summary Tests for HttpHeaders.of factory method - * @run junit HttpHeadersOf + * @run junit ${test.main.class} */ import java.net.http.HttpHeaders; diff --git a/test/jdk/java/net/httpclient/HttpInputStreamAvailableTest.java b/test/jdk/java/net/httpclient/HttpInputStreamAvailableTest.java index 99897a69a8c..395cb50d058 100644 --- a/test/jdk/java/net/httpclient/HttpInputStreamAvailableTest.java +++ b/test/jdk/java/net/httpclient/HttpInputStreamAvailableTest.java @@ -26,7 +26,7 @@ * @bug 8306040 * @summary HttpResponseInputStream.available() returns 1 on empty stream * @library /test/lib /test/jdk/java/net/httpclient/lib - * @run junit/othervm HttpInputStreamAvailableTest + * @run junit/othervm ${test.main.class} * */ import com.sun.net.httpserver.HttpExchange; diff --git a/test/jdk/java/net/httpclient/HttpInputStreamTest.java b/test/jdk/java/net/httpclient/HttpInputStreamTest.java index 2eb7899e1f0..1e04f592f31 100644 --- a/test/jdk/java/net/httpclient/HttpInputStreamTest.java +++ b/test/jdk/java/net/httpclient/HttpInputStreamTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,7 +47,7 @@ import static java.lang.System.err; /* * @test * @summary An example on how to read a response body with InputStream. - * @run main/othervm/manual -Dtest.debug=true HttpInputStreamTest + * @run main/othervm/manual -Dtest.debug=true ${test.main.class} * @author daniel fuchs */ public class HttpInputStreamTest { diff --git a/test/jdk/java/net/httpclient/HttpRedirectTest.java b/test/jdk/java/net/httpclient/HttpRedirectTest.java index 2bf90bbe02c..d611a82967b 100644 --- a/test/jdk/java/net/httpclient/HttpRedirectTest.java +++ b/test/jdk/java/net/httpclient/HttpRedirectTest.java @@ -76,7 +76,7 @@ import org.junit.jupiter.params.provider.MethodSource; * @run junit/othervm -Dtest.requiresHost=true * -Djdk.httpclient.HttpClient.log=headers * -Djdk.internal.httpclient.debug=false - * HttpRedirectTest + * ${test.main.class} * */ public class HttpRedirectTest implements HttpServerAdapters { diff --git a/test/jdk/java/net/httpclient/HttpRequestBodyPublishers/OfByteArraysTest.java b/test/jdk/java/net/httpclient/HttpRequestBodyPublishers/OfByteArraysTest.java index 10784f7dbee..c12dd91e104 100644 --- a/test/jdk/java/net/httpclient/HttpRequestBodyPublishers/OfByteArraysTest.java +++ b/test/jdk/java/net/httpclient/HttpRequestBodyPublishers/OfByteArraysTest.java @@ -52,10 +52,10 @@ import static org.junit.jupiter.api.Assertions.assertThrows; * RecordingSubscriber * ReplayTestSupport * - * @run junit OfByteArraysTest + * @run junit ${test.main.class} * * @comment Using `main/othervm` to initiate tests that depend on a custom-configured JVM - * @run main/othervm -Xmx64m OfByteArraysTest testOOM + * @run main/othervm -Xmx64m ${test.main.class} testOOM */ public class OfByteArraysTest extends ReplayTestSupport { diff --git a/test/jdk/java/net/httpclient/HttpRequestNewBuilderTest.java b/test/jdk/java/net/httpclient/HttpRequestNewBuilderTest.java index 19afbfbd99b..1558711d741 100644 --- a/test/jdk/java/net/httpclient/HttpRequestNewBuilderTest.java +++ b/test/jdk/java/net/httpclient/HttpRequestNewBuilderTest.java @@ -58,7 +58,7 @@ import org.junit.jupiter.params.provider.MethodSource; * @test * @bug 8252304 8276559 * @summary HttpRequest.newBuilder(HttpRequest) API and behaviour checks -* @run junit/othervm HttpRequestNewBuilderTest +* @run junit/othervm ${test.main.class} */ public class HttpRequestNewBuilderTest { static final Class NPE = NullPointerException.class; diff --git a/test/jdk/java/net/httpclient/HttpResponseConnectionLabelTest.java b/test/jdk/java/net/httpclient/HttpResponseConnectionLabelTest.java index 29c4bcc8072..034144841a1 100644 --- a/test/jdk/java/net/httpclient/HttpResponseConnectionLabelTest.java +++ b/test/jdk/java/net/httpclient/HttpResponseConnectionLabelTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @comment Use a higher idle timeout to increase the chances of * the same connection being used for sequential HTTP requests * @run junit/othervm -Djdk.httpclient.keepalive.timeout=120 - * HttpResponseConnectionLabelTest + * ${test.main.class} */ import jdk.httpclient.test.lib.common.HttpServerAdapters; diff --git a/test/jdk/java/net/httpclient/HttpResponseInputStreamInterruptTest.java b/test/jdk/java/net/httpclient/HttpResponseInputStreamInterruptTest.java index 3b955b8feb7..95f554b64e6 100644 --- a/test/jdk/java/net/httpclient/HttpResponseInputStreamInterruptTest.java +++ b/test/jdk/java/net/httpclient/HttpResponseInputStreamInterruptTest.java @@ -25,7 +25,7 @@ * @test * @bug 8294047 * @library /test/lib - * @run junit HttpResponseInputStreamInterruptTest + * @run junit ${test.main.class} */ import com.sun.net.httpserver.HttpExchange; diff --git a/test/jdk/java/net/httpclient/HttpResponseInputStreamTest.java b/test/jdk/java/net/httpclient/HttpResponseInputStreamTest.java index 633c6877716..f7f9b38b7fc 100644 --- a/test/jdk/java/net/httpclient/HttpResponseInputStreamTest.java +++ b/test/jdk/java/net/httpclient/HttpResponseInputStreamTest.java @@ -45,7 +45,7 @@ import org.junit.jupiter.api.Test; * @test * @bug 8197564 8228970 * @summary Simple smoke test for BodySubscriber.asInputStream(); - * @run junit/othervm HttpResponseInputStreamTest + * @run junit/othervm ${test.main.class} * @author daniel fuchs */ public class HttpResponseInputStreamTest { diff --git a/test/jdk/java/net/httpclient/HttpResponseLimitingTest.java b/test/jdk/java/net/httpclient/HttpResponseLimitingTest.java index 450fce35f54..c3471c7ccc0 100644 --- a/test/jdk/java/net/httpclient/HttpResponseLimitingTest.java +++ b/test/jdk/java/net/httpclient/HttpResponseLimitingTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,7 @@ * @build jdk.httpclient.test.lib.common.HttpServerAdapters * jdk.test.lib.RandomFactory * jdk.test.lib.net.SimpleSSLContext - * @run junit HttpResponseLimitingTest + * @run junit ${test.main.class} */ import jdk.httpclient.test.lib.common.HttpServerAdapters; diff --git a/test/jdk/java/net/httpclient/HttpSlowServerTest.java b/test/jdk/java/net/httpclient/HttpSlowServerTest.java index f62f6fa4978..2e56ef232c6 100644 --- a/test/jdk/java/net/httpclient/HttpSlowServerTest.java +++ b/test/jdk/java/net/httpclient/HttpSlowServerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ import static java.net.http.HttpOption.H3_DISCOVERY; * -Djdk.httpclient.HttpClient.log=errors,headers,quic:hs * -Djdk.internal.httpclient.debug=false * -Djdk.httpclient.quic.maxInitialTimeout=60 - * HttpSlowServerTest + * ${test.main.class} * */ public class HttpSlowServerTest implements HttpServerAdapters { diff --git a/test/jdk/java/net/httpclient/HttpVersionsTest.java b/test/jdk/java/net/httpclient/HttpVersionsTest.java index f047e2902e8..17fed725590 100644 --- a/test/jdk/java/net/httpclient/HttpVersionsTest.java +++ b/test/jdk/java/net/httpclient/HttpVersionsTest.java @@ -28,7 +28,7 @@ * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.httpclient.test.lib.http2.Http2TestServer jdk.test.lib.net.SimpleSSLContext * jdk.test.lib.Platform - * @run junit/othervm HttpVersionsTest + * @run junit/othervm ${test.main.class} */ import java.io.IOException; diff --git a/test/jdk/java/net/httpclient/HttpsTunnelAuthTest.java b/test/jdk/java/net/httpclient/HttpsTunnelAuthTest.java index c83abd9cf62..f127b552d2a 100644 --- a/test/jdk/java/net/httpclient/HttpsTunnelAuthTest.java +++ b/test/jdk/java/net/httpclient/HttpsTunnelAuthTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,7 +55,7 @@ import static java.lang.System.out; * -Djdk.http.auth.tunneling.disabledSchemes * -Djdk.httpclient.allowRestrictedHeaders=connection * -Djdk.internal.httpclient.debug=true - * HttpsTunnelAuthTest + * ${test.main.class} * */ //-Djdk.internal.httpclient.debug=true -Dtest.debug=true diff --git a/test/jdk/java/net/httpclient/HttpsTunnelTest.java b/test/jdk/java/net/httpclient/HttpsTunnelTest.java index bb0afacaacb..86e09bcd669 100644 --- a/test/jdk/java/net/httpclient/HttpsTunnelTest.java +++ b/test/jdk/java/net/httpclient/HttpsTunnelTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,11 @@ import static java.net.http.HttpClient.Version.HTTP_2; * DigestEchoServer HttpsTunnelTest * @run main/othervm -Dtest.requiresHost=true * -Djdk.httpclient.HttpClient.log=headers - * -Djdk.internal.httpclient.debug=true HttpsTunnelTest + * -Djdk.internal.httpclient.debug=true ${test.main.class} * @run main/othervm -Dtest.requiresHost=true * -Djdk.httpclient.allowRestrictedHeaders=host * -Djdk.httpclient.HttpClient.log=headers - * -Djdk.internal.httpclient.debug=true HttpsTunnelTest + * -Djdk.internal.httpclient.debug=true ${test.main.class} * */ diff --git a/test/jdk/java/net/httpclient/ISO_8859_1_Test.java b/test/jdk/java/net/httpclient/ISO_8859_1_Test.java index 103284c9d54..474b5866f76 100644 --- a/test/jdk/java/net/httpclient/ISO_8859_1_Test.java +++ b/test/jdk/java/net/httpclient/ISO_8859_1_Test.java @@ -29,7 +29,7 @@ * ReferenceTracker * @run junit/othervm -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.HttpClient.log=requests,responses,errors - * ISO_8859_1_Test + * ${test.main.class} * @summary Tests that a client is able to receive ISO-8859-1 encoded header values. */ diff --git a/test/jdk/java/net/httpclient/IdleConnectionTimeoutTest.java b/test/jdk/java/net/httpclient/IdleConnectionTimeoutTest.java index be7e1db0033..8eaba1d4aa0 100644 --- a/test/jdk/java/net/httpclient/IdleConnectionTimeoutTest.java +++ b/test/jdk/java/net/httpclient/IdleConnectionTimeoutTest.java @@ -70,27 +70,27 @@ import org.junit.jupiter.api.Test; * jdk.httpclient.test.lib.http3.Http3TestServer * * @run junit/othervm -Djdk.httpclient.HttpClient.log=all -Djdk.httpclient.keepalive.timeout=1 - * IdleConnectionTimeoutTest + * ${test.main.class} * @run junit/othervm -Djdk.httpclient.HttpClient.log=all -Djdk.httpclient.keepalive.timeout=20 - * IdleConnectionTimeoutTest + * ${test.main.class} * * @run junit/othervm -Djdk.httpclient.HttpClient.log=all -Djdk.httpclient.keepalive.timeout.h2=1 - * IdleConnectionTimeoutTest + * ${test.main.class} * @run junit/othervm -Djdk.httpclient.HttpClient.log=all -Djdk.httpclient.keepalive.timeout.h2=20 - * IdleConnectionTimeoutTest + * ${test.main.class} * @run junit/othervm -Djdk.httpclient.HttpClient.log=all -Djdk.httpclient.keepalive.timeout.h2=abc - * IdleConnectionTimeoutTest + * ${test.main.class} * @run junit/othervm -Djdk.httpclient.HttpClient.log=all -Djdk.httpclient.keepalive.timeout.h2=-1 - * IdleConnectionTimeoutTest + * ${test.main.class} * * @run junit/othervm -Djdk.httpclient.HttpClient.log=all -Djdk.httpclient.keepalive.timeout.h3=1 - * IdleConnectionTimeoutTest + * ${test.main.class} * @run junit/othervm -Djdk.httpclient.HttpClient.log=all -Djdk.httpclient.keepalive.timeout.h3=20 - * IdleConnectionTimeoutTest + * ${test.main.class} * @run junit/othervm -Djdk.httpclient.HttpClient.log=all -Djdk.httpclient.keepalive.timeout.h3=abc - * IdleConnectionTimeoutTest + * ${test.main.class} * @run junit/othervm -Djdk.httpclient.HttpClient.log=all -Djdk.httpclient.keepalive.timeout.h3=-1 - * IdleConnectionTimeoutTest + * ${test.main.class} */ public class IdleConnectionTimeoutTest { diff --git a/test/jdk/java/net/httpclient/ImmutableFlowItems.java b/test/jdk/java/net/httpclient/ImmutableFlowItems.java index e42e2e21a6e..a47c57a9230 100644 --- a/test/jdk/java/net/httpclient/ImmutableFlowItems.java +++ b/test/jdk/java/net/httpclient/ImmutableFlowItems.java @@ -28,7 +28,7 @@ * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.test.lib.net.SimpleSSLContext jdk.httpclient.test.lib.http2.Http2TestServer * jdk.httpclient.test.lib.common.TestServerConfigurator - * @run junit/othervm ImmutableFlowItems + * @run junit/othervm ${test.main.class} */ import java.io.IOException; diff --git a/test/jdk/java/net/httpclient/ImmutableHeaders.java b/test/jdk/java/net/httpclient/ImmutableHeaders.java index e8d2e5166bb..2ce2234132b 100644 --- a/test/jdk/java/net/httpclient/ImmutableHeaders.java +++ b/test/jdk/java/net/httpclient/ImmutableHeaders.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * 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 8087112 * @modules java.net.http * jdk.httpserver - * @run main/othervm ImmutableHeaders + * @run main/othervm ${test.main.class} * @summary ImmutableHeaders */ diff --git a/test/jdk/java/net/httpclient/ImmutableSSLSessionTest.java b/test/jdk/java/net/httpclient/ImmutableSSLSessionTest.java index 9b5c7961c2f..a7c9deddac7 100644 --- a/test/jdk/java/net/httpclient/ImmutableSSLSessionTest.java +++ b/test/jdk/java/net/httpclient/ImmutableSSLSessionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -79,7 +79,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows; * jdk.httpclient.test.lib.common.HttpServerAdapters * java.net.http/jdk.internal.net.http.common.ImmutableSSLSessionAccess * @run junit/othervm -Djdk.httpclient.HttpClient.log=request,response,headers,errors - * ImmutableSSLSessionTest + * ${test.main.class} */ @TestInstance(TestInstance.Lifecycle.PER_CLASS) public class ImmutableSSLSessionTest implements HttpServerAdapters { diff --git a/test/jdk/java/net/httpclient/InterruptedBlockingSend.java b/test/jdk/java/net/httpclient/InterruptedBlockingSend.java index 0dcd2ca02c2..7605b627038 100644 --- a/test/jdk/java/net/httpclient/InterruptedBlockingSend.java +++ b/test/jdk/java/net/httpclient/InterruptedBlockingSend.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,7 @@ import static java.lang.System.out; * @test * @bug 8245462 * @summary Basic test for interrupted blocking send - * @run main/othervm InterruptedBlockingSend + * @run main/othervm ${test.main.class} */ public class InterruptedBlockingSend { diff --git a/test/jdk/java/net/httpclient/InvalidInputStreamSubscriptionRequest.java b/test/jdk/java/net/httpclient/InvalidInputStreamSubscriptionRequest.java index c83d9d67528..83c09b356ed 100644 --- a/test/jdk/java/net/httpclient/InvalidInputStreamSubscriptionRequest.java +++ b/test/jdk/java/net/httpclient/InvalidInputStreamSubscriptionRequest.java @@ -31,7 +31,7 @@ * jdk.httpclient.test.lib.common.HttpServerAdapters * @run junit/othervm -Dtest.http.version=http3 * -Djdk.internal.httpclient.debug=true - * InvalidInputStreamSubscriptionRequest + * ${test.main.class} */ /* * @test id=http2 @@ -41,7 +41,7 @@ * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.test.lib.net.SimpleSSLContext ReferenceTracker * jdk.httpclient.test.lib.common.HttpServerAdapters - * @run junit/othervm -Dtest.http.version=http2 InvalidInputStreamSubscriptionRequest + * @run junit/othervm -Dtest.http.version=http2 ${test.main.class} */ /* * @test id=http1 @@ -51,7 +51,7 @@ * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.test.lib.net.SimpleSSLContext ReferenceTracker * jdk.httpclient.test.lib.common.HttpServerAdapters - * @run junit/othervm -Dtest.http.version=http1 InvalidInputStreamSubscriptionRequest + * @run junit/othervm -Dtest.http.version=http1 ${test.main.class} */ import com.sun.net.httpserver.HttpServer; diff --git a/test/jdk/java/net/httpclient/InvalidSSLContextTest.java b/test/jdk/java/net/httpclient/InvalidSSLContextTest.java index bbbd1e486ca..418c55364b5 100644 --- a/test/jdk/java/net/httpclient/InvalidSSLContextTest.java +++ b/test/jdk/java/net/httpclient/InvalidSSLContextTest.java @@ -29,7 +29,7 @@ * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.test.lib.net.SimpleSSLContext * jdk.httpclient.test.lib.common.HttpServerAdapters - * @run junit/othervm -Djdk.internal.httpclient.debug=true InvalidSSLContextTest + * @run junit/othervm -Djdk.internal.httpclient.debug=true ${test.main.class} */ import java.io.IOException; diff --git a/test/jdk/java/net/httpclient/InvalidSubscriptionRequest.java b/test/jdk/java/net/httpclient/InvalidSubscriptionRequest.java index 692e4d0bea4..92914843044 100644 --- a/test/jdk/java/net/httpclient/InvalidSubscriptionRequest.java +++ b/test/jdk/java/net/httpclient/InvalidSubscriptionRequest.java @@ -30,7 +30,7 @@ * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.test.lib.net.SimpleSSLContext ReferenceTracker * jdk.httpclient.test.lib.common.HttpServerAdapters - * @run junit/othervm InvalidSubscriptionRequest + * @run junit/othervm ${test.main.class} */ import jdk.test.lib.net.SimpleSSLContext; diff --git a/test/jdk/java/net/httpclient/LargeHandshakeTest.java b/test/jdk/java/net/httpclient/LargeHandshakeTest.java index ff3981e8b3d..59cdad27cbc 100644 --- a/test/jdk/java/net/httpclient/LargeHandshakeTest.java +++ b/test/jdk/java/net/httpclient/LargeHandshakeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * 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,7 +88,7 @@ import static java.net.http.HttpOption.H3_DISCOVERY; * -Djdk.httpclient.HttpClient.log=headers * -Djdk.internal.httpclient.debug=true * -Djdk.tls.maxHandshakeMessageSize=131072 - * LargeHandshakeTest + * ${test.main.class} * */ public class LargeHandshakeTest implements HttpServerAdapters { diff --git a/test/jdk/java/net/httpclient/LargeResponseContent.java b/test/jdk/java/net/httpclient/LargeResponseContent.java index 7a1bca73d13..e510f44c9e4 100644 --- a/test/jdk/java/net/httpclient/LargeResponseContent.java +++ b/test/jdk/java/net/httpclient/LargeResponseContent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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.test.lib.net.URIBuilder; * @bug 8212926 * @library /test/lib * @summary Basic tests for response timeouts - * @run main/othervm LargeResponseContent + * @run main/othervm ${test.main.class} */ public class LargeResponseContent { diff --git a/test/jdk/java/net/httpclient/LargeResponseTest.java b/test/jdk/java/net/httpclient/LargeResponseTest.java index 727cc1768df..f41a40f2960 100644 --- a/test/jdk/java/net/httpclient/LargeResponseTest.java +++ b/test/jdk/java/net/httpclient/LargeResponseTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -69,7 +69,7 @@ import static java.net.http.HttpOption.H3_DISCOVERY; * -Djdk.httpclient.HttpClient.log=headers * -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.quic.maxInitialTimeout=60 - * LargeResponseTest + * ${test.main.class} * */ public class LargeResponseTest implements HttpServerAdapters { diff --git a/test/jdk/java/net/httpclient/LineBodyHandlerTest.java b/test/jdk/java/net/httpclient/LineBodyHandlerTest.java index ddca2e1f7d2..d18c3b170ee 100644 --- a/test/jdk/java/net/httpclient/LineBodyHandlerTest.java +++ b/test/jdk/java/net/httpclient/LineBodyHandlerTest.java @@ -82,7 +82,7 @@ import org.junit.jupiter.params.provider.MethodSource; * @library /test/lib /test/jdk/java/net/httpclient/lib * @build ReferenceTracker jdk.httpclient.test.lib.http2.Http2TestServer * jdk.test.lib.net.SimpleSSLContext - * @run junit/othervm -XX:+UnlockDiagnosticVMOptions -XX:DiagnoseSyncOnValueBasedClasses=1 LineBodyHandlerTest + * @run junit/othervm -XX:+UnlockDiagnosticVMOptions -XX:DiagnoseSyncOnValueBasedClasses=1 ${test.main.class} */ public class LineBodyHandlerTest implements HttpServerAdapters { diff --git a/test/jdk/java/net/httpclient/LineStreamsAndSurrogatesTest.java b/test/jdk/java/net/httpclient/LineStreamsAndSurrogatesTest.java index 01a7ee9fdbf..4dead447295 100644 --- a/test/jdk/java/net/httpclient/LineStreamsAndSurrogatesTest.java +++ b/test/jdk/java/net/httpclient/LineStreamsAndSurrogatesTest.java @@ -49,7 +49,7 @@ import org.junit.jupiter.api.Test; * In particular tests that surrogate characters are handled * correctly. * @modules java.net.http java.logging - * @run junit/othervm LineStreamsAndSurrogatesTest + * @run junit/othervm ${test.main.class} */ public class LineStreamsAndSurrogatesTest { diff --git a/test/jdk/java/net/httpclient/LineSubscribersAndSurrogatesTest.java b/test/jdk/java/net/httpclient/LineSubscribersAndSurrogatesTest.java index 7932744a4db..fc51b1f7a4d 100644 --- a/test/jdk/java/net/httpclient/LineSubscribersAndSurrogatesTest.java +++ b/test/jdk/java/net/httpclient/LineSubscribersAndSurrogatesTest.java @@ -54,7 +54,7 @@ import org.junit.jupiter.api.Test; * In particular tests that surrogate characters are handled * correctly. * @modules java.net.http java.logging - * @run junit/othervm LineSubscribersAndSurrogatesTest + * @run junit/othervm ${test.main.class} */ public class LineSubscribersAndSurrogatesTest { diff --git a/test/jdk/java/net/httpclient/ManyRequests.java b/test/jdk/java/net/httpclient/ManyRequests.java index 3609aa8337a..e8bcfb76b1b 100644 --- a/test/jdk/java/net/httpclient/ManyRequests.java +++ b/test/jdk/java/net/httpclient/ManyRequests.java @@ -27,13 +27,13 @@ * @key intermittent * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.test.lib.net.SimpleSSLContext jdk.httpclient.test.lib.common.HttpServerAdapters - * @run main/othervm/timeout=160 -Djdk.httpclient.HttpClient.log=ssl,channel ManyRequests - * @run main/othervm/timeout=160 -Djdk.httpclient.HttpClient.log=channel -Dtest.insertDelay=true ManyRequests - * @run main/othervm/timeout=160 -Djdk.httpclient.HttpClient.log=channel -Dtest.chunkSize=64 ManyRequests - * @run main/othervm/timeout=160 -Djdk.httpclient.HttpClient.log=channel -Dtest.insertDelay=true -Dtest.chunkSize=64 ManyRequests + * @run main/othervm/timeout=160 -Djdk.httpclient.HttpClient.log=ssl,channel ${test.main.class} + * @run main/othervm/timeout=160 -Djdk.httpclient.HttpClient.log=channel -Dtest.insertDelay=true ${test.main.class} + * @run main/othervm/timeout=160 -Djdk.httpclient.HttpClient.log=channel -Dtest.chunkSize=64 ${test.main.class} + * @run main/othervm/timeout=160 -Djdk.httpclient.HttpClient.log=channel -Dtest.insertDelay=true -Dtest.chunkSize=64 ${test.main.class} * @summary Send a large number of requests asynchronously */ - // * @run main/othervm/timeout=40 -Djdk.httpclient.HttpClient.log=ssl,channel ManyRequests + // * @run main/othervm/timeout=40 -Djdk.httpclient.HttpClient.log=ssl,channel ${test.main.class} import java.io.IOException; import java.io.InputStream; diff --git a/test/jdk/java/net/httpclient/ManyRequests2.java b/test/jdk/java/net/httpclient/ManyRequests2.java index 09fdc18f687..5718e6958f7 100644 --- a/test/jdk/java/net/httpclient/ManyRequests2.java +++ b/test/jdk/java/net/httpclient/ManyRequests2.java @@ -28,15 +28,15 @@ * @build jdk.test.lib.net.SimpleSSLContext jdk.httpclient.test.lib.common.HttpServerAdapters * @build ManyRequests ManyRequests2 * @run main/othervm/timeout=400 -Dsun.net.httpserver.idleInterval=400 -Dtest.XFixed=true - * -Djdk.httpclient.HttpClient.log=channel ManyRequests2 + * -Djdk.httpclient.HttpClient.log=channel ${test.main.class} * @run main/othervm/timeout=400 -Dsun.net.httpserver.idleInterval=400 -Dtest.XFixed=true -Dtest.insertDelay=true - * -Djdk.httpclient.HttpClient.log=channel ManyRequests2 + * -Djdk.httpclient.HttpClient.log=channel ${test.main.class} * @run main/othervm/timeout=400 -Dsun.net.httpserver.idleInterval=400 -Dtest.XFixed=true -Dtest.chunkSize=64 - * -Djdk.httpclient.HttpClient.log=channel ManyRequests2 + * -Djdk.httpclient.HttpClient.log=channel ${test.main.class} * @run main/othervm/timeout=400 -Dsun.net.httpserver.idleInterval=400 -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.HttpClient.log=channel * -Dtest.XFixed=true -Dtest.insertDelay=true - * -Dtest.chunkSize=64 ManyRequests2 + * -Dtest.chunkSize=64 ${test.main.class} * @summary Send a large number of requests asynchronously. * The server echoes back using known content length. */ diff --git a/test/jdk/java/net/httpclient/ManyRequestsLegacy.java b/test/jdk/java/net/httpclient/ManyRequestsLegacy.java index f1c4f881058..b0f7ffdd4cb 100644 --- a/test/jdk/java/net/httpclient/ManyRequestsLegacy.java +++ b/test/jdk/java/net/httpclient/ManyRequestsLegacy.java @@ -25,11 +25,11 @@ * @test * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.test.lib.net.SimpleSSLContext jdk.httpclient.test.lib.common.HttpServerAdapters - * @run main/othervm/timeout=80 -Dsun.net.httpserver.idleInterval=50000 ManyRequestsLegacy - * @run main/othervm/timeout=80 -Dtest.insertDelay=true -Dsun.net.httpserver.idleInterval=50000 ManyRequestsLegacy - * @run main/othervm/timeout=80 -Dtest.chunkSize=64 -Dsun.net.httpserver.idleInterval=50000 ManyRequestsLegacy + * @run main/othervm/timeout=80 -Dsun.net.httpserver.idleInterval=50000 ${test.main.class} + * @run main/othervm/timeout=80 -Dtest.insertDelay=true -Dsun.net.httpserver.idleInterval=50000 ${test.main.class} + * @run main/othervm/timeout=80 -Dtest.chunkSize=64 -Dsun.net.httpserver.idleInterval=50000 ${test.main.class} * @run main/othervm/timeout=80 -Dtest.insertDelay=true -Dsun.net.httpserver.idleInterval=50000 - * -Dtest.chunkSize=64 ManyRequestsLegacy + * -Dtest.chunkSize=64 ${test.main.class} * @summary Send a large number of requests asynchronously using the legacy * URL.openConnection(), to help sanitize results of the test * ManyRequest.java. diff --git a/test/jdk/java/net/httpclient/MaxStreams.java b/test/jdk/java/net/httpclient/MaxStreams.java index 00875aceb6f..b3fc38e11f3 100644 --- a/test/jdk/java/net/httpclient/MaxStreams.java +++ b/test/jdk/java/net/httpclient/MaxStreams.java @@ -27,7 +27,7 @@ * @summary Should HttpClient support SETTINGS_MAX_CONCURRENT_STREAMS from the server * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.httpclient.test.lib.http2.Http2TestServer jdk.test.lib.net.SimpleSSLContext - * @run junit/othervm MaxStreams + * @run junit/othervm ${test.main.class} */ import java.io.IOException; diff --git a/test/jdk/java/net/httpclient/MessageHeadersTest.java b/test/jdk/java/net/httpclient/MessageHeadersTest.java index b0a5130e2b6..ab6ed2e5f94 100644 --- a/test/jdk/java/net/httpclient/MessageHeadersTest.java +++ b/test/jdk/java/net/httpclient/MessageHeadersTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,7 +27,7 @@ * @modules java.net.http * jdk.httpserver * java.base/sun.net.www - * @run main MessageHeadersTest + * @run main ${test.main.class} * @summary Tests expected behavior of MessageHeader. This test * cannot be used to verify 8164704 - it simply verifies * the assumptions on which the fix is based. diff --git a/test/jdk/java/net/httpclient/MultiAuthTest.java b/test/jdk/java/net/httpclient/MultiAuthTest.java index c434591c894..bdf18ee7238 100644 --- a/test/jdk/java/net/httpclient/MultiAuthTest.java +++ b/test/jdk/java/net/httpclient/MultiAuthTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * 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 * @modules java.net.http * jdk.httpserver - * @run main/othervm MultiAuthTest + * @run main/othervm ${test.main.class} * @summary Basic Authentication test with multiple clients issuing * multiple requests. Includes password changes * on server and client side. diff --git a/test/jdk/java/net/httpclient/NoBodyPartOne.java b/test/jdk/java/net/httpclient/NoBodyPartOne.java index 980f4d8d100..6fc4cf02e07 100644 --- a/test/jdk/java/net/httpclient/NoBodyPartOne.java +++ b/test/jdk/java/net/httpclient/NoBodyPartOne.java @@ -30,7 +30,7 @@ * @run junit/othervm * -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.HttpClient.log=all - * NoBodyPartOne + * ${test.main.class} */ import java.nio.file.Files; diff --git a/test/jdk/java/net/httpclient/NoBodyPartThree.java b/test/jdk/java/net/httpclient/NoBodyPartThree.java index 7020f7e2c25..ab9b3822263 100644 --- a/test/jdk/java/net/httpclient/NoBodyPartThree.java +++ b/test/jdk/java/net/httpclient/NoBodyPartThree.java @@ -30,7 +30,7 @@ * @run junit/othervm * -Djdk.httpclient.HttpClient.log=quic,errors * -Djdk.httpclient.HttpClient.log=all - * NoBodyPartThree + * ${test.main.class} */ import java.io.InputStream; diff --git a/test/jdk/java/net/httpclient/NoBodyPartTwo.java b/test/jdk/java/net/httpclient/NoBodyPartTwo.java index 9e7ceb11c55..c59bc5e9b08 100644 --- a/test/jdk/java/net/httpclient/NoBodyPartTwo.java +++ b/test/jdk/java/net/httpclient/NoBodyPartTwo.java @@ -30,7 +30,7 @@ * @run junit/othervm * -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.HttpClient.log=all - * NoBodyPartTwo + * ${test.main.class} */ import java.io.InputStream; diff --git a/test/jdk/java/net/httpclient/NonAsciiCharsInURI.java b/test/jdk/java/net/httpclient/NonAsciiCharsInURI.java index 2e53479a6ee..2bde0c8bd9a 100644 --- a/test/jdk/java/net/httpclient/NonAsciiCharsInURI.java +++ b/test/jdk/java/net/httpclient/NonAsciiCharsInURI.java @@ -31,7 +31,7 @@ * @compile -encoding utf-8 NonAsciiCharsInURI.java * @run junit/othervm * -Djdk.httpclient.HttpClient.log=requests,headers,errors,quic - * NonAsciiCharsInURI + * ${test.main.class} */ import java.io.Closeable; diff --git a/test/jdk/java/net/httpclient/OriginTest.java b/test/jdk/java/net/httpclient/OriginTest.java index 58310ecd9ad..838f8f36df2 100644 --- a/test/jdk/java/net/httpclient/OriginTest.java +++ b/test/jdk/java/net/httpclient/OriginTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,7 +38,7 @@ import static org.junit.jupiter.api.Assertions.fail; * @test * @summary verify the behaviour of jdk.internal.net.http.Origin * @modules java.net.http/jdk.internal.net.http - * @run junit OriginTest + * @run junit ${test.main.class} */ class OriginTest { diff --git a/test/jdk/java/net/httpclient/PathSubscriber/BodyHandlerOfFileDownloadTest.java b/test/jdk/java/net/httpclient/PathSubscriber/BodyHandlerOfFileDownloadTest.java index 92d359e32c6..93f1b36dfd1 100644 --- a/test/jdk/java/net/httpclient/PathSubscriber/BodyHandlerOfFileDownloadTest.java +++ b/test/jdk/java/net/httpclient/PathSubscriber/BodyHandlerOfFileDownloadTest.java @@ -37,7 +37,7 @@ * jdk.test.lib.net.SimpleSSLContext * jdk.test.lib.Platform * jdk.test.lib.util.FileUtils - * @run junit/othervm BodyHandlerOfFileDownloadTest + * @run junit/othervm ${test.main.class} */ import jdk.test.lib.net.SimpleSSLContext; diff --git a/test/jdk/java/net/httpclient/PathSubscriber/BodyHandlerOfFileTest.java b/test/jdk/java/net/httpclient/PathSubscriber/BodyHandlerOfFileTest.java index 53b8607f294..b0977efe69e 100644 --- a/test/jdk/java/net/httpclient/PathSubscriber/BodyHandlerOfFileTest.java +++ b/test/jdk/java/net/httpclient/PathSubscriber/BodyHandlerOfFileTest.java @@ -36,7 +36,7 @@ * jdk.httpclient.test.lib.http2.Queue * jdk.test.lib.net.SimpleSSLContext * jdk.test.lib.Platform jdk.test.lib.util.FileUtils - * @run junit/othervm BodyHandlerOfFileTest + * @run junit/othervm ${test.main.class} */ import jdk.test.lib.net.SimpleSSLContext; diff --git a/test/jdk/java/net/httpclient/PathSubscriber/BodySubscriberOfFileTest.java b/test/jdk/java/net/httpclient/PathSubscriber/BodySubscriberOfFileTest.java index da0c7220b6b..665bf280aca 100644 --- a/test/jdk/java/net/httpclient/PathSubscriber/BodySubscriberOfFileTest.java +++ b/test/jdk/java/net/httpclient/PathSubscriber/BodySubscriberOfFileTest.java @@ -35,7 +35,7 @@ * jdk.httpclient.test.lib.http2.OutgoingPushPromise * jdk.httpclient.test.lib.http2.Queue jdk.test.lib.net.SimpleSSLContext * jdk.test.lib.Platform jdk.test.lib.util.FileUtils - * @run junit/othervm BodySubscriberOfFileTest + * @run junit/othervm ${test.main.class} */ import jdk.test.lib.net.SimpleSSLContext; diff --git a/test/jdk/java/net/httpclient/PlainProxyConnectionTest.java b/test/jdk/java/net/httpclient/PlainProxyConnectionTest.java index cd7049285f1..91a59019355 100644 --- a/test/jdk/java/net/httpclient/PlainProxyConnectionTest.java +++ b/test/jdk/java/net/httpclient/PlainProxyConnectionTest.java @@ -62,7 +62,7 @@ import static java.net.Proxy.NO_PROXY; * /test/jdk/java/net/httpclient/lib * @run main/othervm -Djdk.httpclient.HttpClient.log=headers,requests,trace * -Djdk.internal.httpclient.debug=true - * PlainProxyConnectionTest + * ${test.main.class} */ public class PlainProxyConnectionTest { diff --git a/test/jdk/java/net/httpclient/ProxyAuthDisabledSchemes.java b/test/jdk/java/net/httpclient/ProxyAuthDisabledSchemes.java index 84b29449d67..92f1360d1e2 100644 --- a/test/jdk/java/net/httpclient/ProxyAuthDisabledSchemes.java +++ b/test/jdk/java/net/httpclient/ProxyAuthDisabledSchemes.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,13 +34,13 @@ * jdk.httpclient.test.lib.common.HttpServerAdapters * @run main/othervm -Djdk.http.auth.proxying.disabledSchemes=Basic,Digest * -Djdk.http.auth.tunneling.disabledSchemes=Digest,Basic - * ProxyAuthDisabledSchemes + * ${test.main.class} * @run main/othervm -Djdk.http.auth.proxying.disabledSchemes=Basic * -Djdk.http.auth.tunneling.disabledSchemes=Basic - * ProxyAuthDisabledSchemes CLEAR PROXY + * ${test.main.class} CLEAR PROXY * @run main/othervm -Djdk.http.auth.proxying.disabledSchemes=Digest * -Djdk.http.auth.tunneling.disabledSchemes=Digest - * ProxyAuthDisabledSchemes CLEAR PROXY + * ${test.main.class} CLEAR PROXY */ public class ProxyAuthDisabledSchemes { diff --git a/test/jdk/java/net/httpclient/ProxyAuthDisabledSchemesSSL.java b/test/jdk/java/net/httpclient/ProxyAuthDisabledSchemesSSL.java index 6d9d7e4f11b..e02cbef658b 100644 --- a/test/jdk/java/net/httpclient/ProxyAuthDisabledSchemesSSL.java +++ b/test/jdk/java/net/httpclient/ProxyAuthDisabledSchemesSSL.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,27 +38,27 @@ * -Djdk.httpclient.http3.maxDirectConnectionTimeout=100 * -Djdk.internal.httpclient.debug=err * -Djdk.httpclient.HttpClient.log=headers - * ProxyAuthDisabledSchemesSSL SSL SERVER307 + * ${test.main.class} SSL SERVER307 * @run main/othervm/timeout=300 * -Djdk.http.auth.proxying.disabledSchemes=Basic,Digest * -Djdk.http.auth.tunneling.disabledSchemes=Digest,Basic * -Djdk.httpclient.http3.maxDirectConnectionTimeout=100 * -Djdk.httpclient.HttpClient.log=headers - * ProxyAuthDisabledSchemesSSL SSL SERVER PROXY + * ${test.main.class} SSL SERVER PROXY * @run main/othervm/timeout=300 * -Djdk.http.auth.proxying.disabledSchemes=Basic * -Djdk.http.auth.tunneling.disabledSchemes=Basic * -Dtest.requiresHost=true * -Djdk.httpclient.http3.maxDirectConnectionTimeout=100 * -Djdk.httpclient.HttpClient.log=headers - * ProxyAuthDisabledSchemesSSL SSL PROXY + * ${test.main.class} SSL PROXY * @run main/othervm/timeout=300 * -Djdk.http.auth.proxying.disabledSchemes=Digest * -Djdk.http.auth.tunneling.disabledSchemes=Digest * -Dtest.requiresHost=true * -Djdk.httpclient.http3.maxDirectConnectionTimeout=100 * -Djdk.httpclient.HttpClient.log=headers - * ProxyAuthDisabledSchemesSSL SSL PROXY + * ${test.main.class} SSL PROXY */ public class ProxyAuthDisabledSchemesSSL { diff --git a/test/jdk/java/net/httpclient/ProxyAuthTest.java b/test/jdk/java/net/httpclient/ProxyAuthTest.java index a147e8944d2..63004289934 100644 --- a/test/jdk/java/net/httpclient/ProxyAuthTest.java +++ b/test/jdk/java/net/httpclient/ProxyAuthTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * 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 8163561 * @library /test/lib * @summary Verify that Proxy-Authenticate header is correctly handled - * @run main/othervm ProxyAuthTest + * @run main/othervm ${test.main.class} */ import java.io.BufferedWriter; diff --git a/test/jdk/java/net/httpclient/ProxySelectorTest.java b/test/jdk/java/net/httpclient/ProxySelectorTest.java index bb339e91bdc..3920906d03a 100644 --- a/test/jdk/java/net/httpclient/ProxySelectorTest.java +++ b/test/jdk/java/net/httpclient/ProxySelectorTest.java @@ -33,7 +33,7 @@ * -Djdk.http.auth.tunneling.disabledSchemes * -Djdk.httpclient.HttpClient.log=headers,requests * -Djdk.internal.httpclient.debug=true - * ProxySelectorTest + * ${test.main.class} */ import jdk.test.lib.net.SimpleSSLContext; diff --git a/test/jdk/java/net/httpclient/ProxyTest.java b/test/jdk/java/net/httpclient/ProxyTest.java index d8abea188bd..45000f54f45 100644 --- a/test/jdk/java/net/httpclient/ProxyTest.java +++ b/test/jdk/java/net/httpclient/ProxyTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -74,7 +74,7 @@ import static java.net.Proxy.NO_PROXY; * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.test.lib.net.SimpleSSLContext ProxyTest * jdk.httpclient.test.lib.common.TestServerConfigurator - * @run main/othervm ProxyTest + * @run main/othervm ${test.main.class} * @author danielfuchs */ public class ProxyTest { diff --git a/test/jdk/java/net/httpclient/RedirectMethodChange.java b/test/jdk/java/net/httpclient/RedirectMethodChange.java index 73e27f6efff..545d049d0d5 100644 --- a/test/jdk/java/net/httpclient/RedirectMethodChange.java +++ b/test/jdk/java/net/httpclient/RedirectMethodChange.java @@ -26,7 +26,7 @@ * @summary Method change during redirection * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.httpclient.test.lib.http2.Http2TestServer jdk.test.lib.net.SimpleSSLContext - * @run junit/othervm RedirectMethodChange + * @run junit/othervm ${test.main.class} */ import javax.net.ssl.SSLContext; diff --git a/test/jdk/java/net/httpclient/RedirectTimeoutTest.java b/test/jdk/java/net/httpclient/RedirectTimeoutTest.java index 8c2fa8707ae..eac97e4f73e 100644 --- a/test/jdk/java/net/httpclient/RedirectTimeoutTest.java +++ b/test/jdk/java/net/httpclient/RedirectTimeoutTest.java @@ -29,7 +29,7 @@ * an HttpTimeoutException during the redirected request. * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.test.lib.net.SimpleSSLContext - * @run junit/othervm -Djdk.httpclient.HttpClient.log=errors,trace -Djdk.internal.httpclient.debug=false RedirectTimeoutTest + * @run junit/othervm -Djdk.httpclient.HttpClient.log=errors,trace -Djdk.internal.httpclient.debug=false ${test.main.class} */ import jdk.httpclient.test.lib.common.HttpServerAdapters; @@ -203,4 +203,4 @@ public class RedirectTimeoutTest implements HttpServerAdapters { } } } -} \ No newline at end of file +} diff --git a/test/jdk/java/net/httpclient/RedirectWithCookie.java b/test/jdk/java/net/httpclient/RedirectWithCookie.java index ad94b124132..d9ebf9e1faf 100644 --- a/test/jdk/java/net/httpclient/RedirectWithCookie.java +++ b/test/jdk/java/net/httpclient/RedirectWithCookie.java @@ -28,7 +28,7 @@ * @build jdk.httpclient.test.lib.http2.Http2TestServer jdk.test.lib.net.SimpleSSLContext * @run junit/othervm * -Djdk.httpclient.HttpClient.log=trace,headers,requests - * RedirectWithCookie + * ${test.main.class} */ import java.io.IOException; diff --git a/test/jdk/java/net/httpclient/RequestBodyTest.java b/test/jdk/java/net/httpclient/RequestBodyTest.java index e87cbc694c7..0c65a81c3ed 100644 --- a/test/jdk/java/net/httpclient/RequestBodyTest.java +++ b/test/jdk/java/net/httpclient/RequestBodyTest.java @@ -62,7 +62,7 @@ import org.junit.jupiter.params.provider.MethodSource; * @build LightWeightHttpServer * @build jdk.test.lib.Platform * @build jdk.test.lib.util.FileUtils - * @run junit/othervm RequestBodyTest + * @run junit/othervm ${test.main.class} */ public class RequestBodyTest { diff --git a/test/jdk/java/net/httpclient/RequestBuilderTest.java b/test/jdk/java/net/httpclient/RequestBuilderTest.java index 12af908457b..6ba00fcd10f 100644 --- a/test/jdk/java/net/httpclient/RequestBuilderTest.java +++ b/test/jdk/java/net/httpclient/RequestBuilderTest.java @@ -25,7 +25,7 @@ * @test * @bug 8276559 * @summary HttpRequest[.Builder] API and behaviour checks - * @run junit RequestBuilderTest + * @run junit ${test.main.class} */ import java.net.URI; diff --git a/test/jdk/java/net/httpclient/Response1xxTest.java b/test/jdk/java/net/httpclient/Response1xxTest.java index 9b54f852510..d7e975fa7dc 100644 --- a/test/jdk/java/net/httpclient/Response1xxTest.java +++ b/test/jdk/java/net/httpclient/Response1xxTest.java @@ -63,7 +63,7 @@ import org.junit.jupiter.api.Test; * @build jdk.test.lib.net.SimpleSSLContext jdk.httpclient.test.lib.common.HttpServerAdapters * jdk.httpclient.test.lib.http2.Http2TestServer * @run junit/othervm -Djdk.internal.httpclient.debug=true - * -Djdk.httpclient.HttpClient.log=headers,requests,responses,errors Response1xxTest + * -Djdk.httpclient.HttpClient.log=headers,requests,responses,errors ${test.main.class} */ public class Response1xxTest implements HttpServerAdapters { private static final String EXPECTED_RSP_BODY = "Hello World"; diff --git a/test/jdk/java/net/httpclient/Response204.java b/test/jdk/java/net/httpclient/Response204.java index e68be645ff9..5ee880655b1 100644 --- a/test/jdk/java/net/httpclient/Response204.java +++ b/test/jdk/java/net/httpclient/Response204.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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 8211437 8216974 8218662 - * @run main/othervm -Djdk.httpclient.HttpClient.log=headers,requests Response204 + * @run main/othervm -Djdk.httpclient.HttpClient.log=headers,requests ${test.main.class} * @summary */ diff --git a/test/jdk/java/net/httpclient/Response204V2Test.java b/test/jdk/java/net/httpclient/Response204V2Test.java index 835f7aa65f7..517f6b0c5c6 100644 --- a/test/jdk/java/net/httpclient/Response204V2Test.java +++ b/test/jdk/java/net/httpclient/Response204V2Test.java @@ -29,7 +29,7 @@ * ReferenceTracker jdk.httpclient.test.lib.common.HttpServerAdapters * @run junit/othervm -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.HttpClient.log=requests,responses,errors - * Response204V2Test + * ${test.main.class} * @summary Tests that streams are closed after receiving a 204 response. * This test uses the OperationsTracker and will fail in * teardown if the tracker reports that some HTTP/2 streams diff --git a/test/jdk/java/net/httpclient/ResponseBodyBeforeError.java b/test/jdk/java/net/httpclient/ResponseBodyBeforeError.java index 19393d99ee9..562176b596a 100644 --- a/test/jdk/java/net/httpclient/ResponseBodyBeforeError.java +++ b/test/jdk/java/net/httpclient/ResponseBodyBeforeError.java @@ -28,7 +28,7 @@ * @modules java.net.http/jdk.internal.net.http.common * @library /test/lib * @build jdk.test.lib.net.SimpleSSLContext - * @run junit/othervm/timeout=480 ResponseBodyBeforeError + * @run junit/othervm/timeout=480 ${test.main.class} */ import java.io.Closeable; diff --git a/test/jdk/java/net/httpclient/ResponsePublisher.java b/test/jdk/java/net/httpclient/ResponsePublisher.java index be135e84b31..b436e6e6b18 100644 --- a/test/jdk/java/net/httpclient/ResponsePublisher.java +++ b/test/jdk/java/net/httpclient/ResponsePublisher.java @@ -28,7 +28,7 @@ * immediately with a Publisher> * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.test.lib.net.SimpleSSLContext jdk.httpclient.test.lib.common.HttpServerAdapters - * @run junit/othervm/timeout=480 ResponsePublisher + * @run junit/othervm/timeout=480 ${test.main.class} */ import jdk.internal.net.http.common.OperationTrackers; diff --git a/test/jdk/java/net/httpclient/RestrictedHeadersTest.java b/test/jdk/java/net/httpclient/RestrictedHeadersTest.java index f2ddf85b3f5..108ecb6259a 100644 --- a/test/jdk/java/net/httpclient/RestrictedHeadersTest.java +++ b/test/jdk/java/net/httpclient/RestrictedHeadersTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,10 +25,10 @@ * @test * @bug 8178699 * @modules java.net.http - * @run main/othervm RestrictedHeadersTest - * @run main/othervm -Djdk.httpclient.allowRestrictedHeaders=content-length,connection RestrictedHeadersTest content-length connection - * @run main/othervm -Djdk.httpclient.allowRestrictedHeaders=host,upgrade RestrictedHeadersTest host upgrade - * @run main/othervm -Djdk.httpclient.allowRestrictedHeaders=via RestrictedHeadersTest via + * @run main/othervm ${test.main.class} + * @run main/othervm -Djdk.httpclient.allowRestrictedHeaders=content-length,connection ${test.main.class} content-length connection + * @run main/othervm -Djdk.httpclient.allowRestrictedHeaders=host,upgrade ${test.main.class} host upgrade + * @run main/othervm -Djdk.httpclient.allowRestrictedHeaders=via ${test.main.class} via */ import java.net.URI; diff --git a/test/jdk/java/net/httpclient/RetryPost.java b/test/jdk/java/net/httpclient/RetryPost.java index 67969306acc..a943b92aeea 100644 --- a/test/jdk/java/net/httpclient/RetryPost.java +++ b/test/jdk/java/net/httpclient/RetryPost.java @@ -24,8 +24,8 @@ /* * @test * @summary Ensure that the POST method is retied when the property is set. - * @run junit/othervm -Djdk.httpclient.enableAllMethodRetry RetryPost - * @run junit/othervm -Djdk.httpclient.enableAllMethodRetry=true RetryPost + * @run junit/othervm -Djdk.httpclient.enableAllMethodRetry ${test.main.class} + * @run junit/othervm -Djdk.httpclient.enableAllMethodRetry=true ${test.main.class} */ import java.io.IOException; diff --git a/test/jdk/java/net/httpclient/RetryWithCookie.java b/test/jdk/java/net/httpclient/RetryWithCookie.java index 8638693b50d..b90f9bb6809 100644 --- a/test/jdk/java/net/httpclient/RetryWithCookie.java +++ b/test/jdk/java/net/httpclient/RetryWithCookie.java @@ -31,7 +31,7 @@ * ReferenceTracker * @run junit/othervm * -Djdk.httpclient.HttpClient.log=trace,headers,requests - * RetryWithCookie + * ${test.main.class} */ import jdk.test.lib.net.SimpleSSLContext; diff --git a/test/jdk/java/net/httpclient/SSLExceptionTest.java b/test/jdk/java/net/httpclient/SSLExceptionTest.java index cf94d1b50f7..e6c234fb9e8 100644 --- a/test/jdk/java/net/httpclient/SSLExceptionTest.java +++ b/test/jdk/java/net/httpclient/SSLExceptionTest.java @@ -37,7 +37,7 @@ import org.junit.jupiter.api.Test; * SSLcontext used by HttpClient are not available * @build SSLExceptionTest * @run junit/othervm -Djdk.tls.client.protocols="InvalidTLSv1.4" - * SSLExceptionTest + * ${test.main.class} */ public class SSLExceptionTest { diff --git a/test/jdk/java/net/httpclient/SendResponseHeadersTest.java b/test/jdk/java/net/httpclient/SendResponseHeadersTest.java index 2998522616f..600a4a1f295 100644 --- a/test/jdk/java/net/httpclient/SendResponseHeadersTest.java +++ b/test/jdk/java/net/httpclient/SendResponseHeadersTest.java @@ -27,7 +27,7 @@ * @library /test/lib * @summary Check that sendResponseHeaders throws an IOException when headers * have already been sent - * @run junit/othervm SendResponseHeadersTest + * @run junit/othervm ${test.main.class} */ import com.sun.net.httpserver.HttpExchange; diff --git a/test/jdk/java/net/httpclient/ServerCloseTest.java b/test/jdk/java/net/httpclient/ServerCloseTest.java index d5e762b15a4..715a7b9f4a3 100644 --- a/test/jdk/java/net/httpclient/ServerCloseTest.java +++ b/test/jdk/java/net/httpclient/ServerCloseTest.java @@ -28,7 +28,7 @@ * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.test.lib.net.SimpleSSLContext * jdk.httpclient.test.lib.common.HttpServerAdapters - * @run junit/othervm -Djdk.tls.acknowledgeCloseNotify=true ServerCloseTest + * @run junit/othervm -Djdk.tls.acknowledgeCloseNotify=true ${test.main.class} */ //* -Djdk.internal.httpclient.debug=true diff --git a/test/jdk/java/net/httpclient/ShortRequestBody.java b/test/jdk/java/net/httpclient/ShortRequestBody.java index ffebdeec5ce..274a129c320 100644 --- a/test/jdk/java/net/httpclient/ShortRequestBody.java +++ b/test/jdk/java/net/httpclient/ShortRequestBody.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ import static java.nio.charset.StandardCharsets.UTF_8; * @bug 8151441 * @summary Request body of incorrect (larger or smaller) sizes than that * reported by the body publisher - * @run main/othervm ShortRequestBody + * @run main/othervm ${test.main.class} */ public class ShortRequestBody { diff --git a/test/jdk/java/net/httpclient/ShortResponseBodyGet.java b/test/jdk/java/net/httpclient/ShortResponseBodyGet.java index 47be508c8c1..f5393fe940b 100644 --- a/test/jdk/java/net/httpclient/ShortResponseBodyGet.java +++ b/test/jdk/java/net/httpclient/ShortResponseBodyGet.java @@ -30,7 +30,7 @@ * @build jdk.test.lib.net.SimpleSSLContext ShortResponseBody ShortResponseBodyGet * @run junit/othervm * -Djdk.httpclient.HttpClient.log=headers,errors,channel - * ShortResponseBodyGet + * ${test.main.class} */ import java.io.IOException; diff --git a/test/jdk/java/net/httpclient/ShortResponseBodyPost.java b/test/jdk/java/net/httpclient/ShortResponseBodyPost.java index 60d2796b34f..5a88455fc54 100644 --- a/test/jdk/java/net/httpclient/ShortResponseBodyPost.java +++ b/test/jdk/java/net/httpclient/ShortResponseBodyPost.java @@ -31,7 +31,7 @@ * @run junit/othervm * -Djdk.httpclient.HttpClient.log=headers,errors,channel * -Djdk.internal.httpclient.debug=true - * ShortResponseBodyPost + * ${test.main.class} */ import java.io.IOException; diff --git a/test/jdk/java/net/httpclient/ShutdownNow.java b/test/jdk/java/net/httpclient/ShutdownNow.java index e48667d2c69..0fdc7b2acc3 100644 --- a/test/jdk/java/net/httpclient/ShutdownNow.java +++ b/test/jdk/java/net/httpclient/ShutdownNow.java @@ -35,7 +35,7 @@ * @run junit/othervm * -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.HttpClient.log=trace,headers,requests - * ShutdownNow + * ${test.main.class} */ // -Djdk.internal.httpclient.debug=true diff --git a/test/jdk/java/net/httpclient/SmallTimeout.java b/test/jdk/java/net/httpclient/SmallTimeout.java index 76117ef3075..8ca08b9b65d 100644 --- a/test/jdk/java/net/httpclient/SmallTimeout.java +++ b/test/jdk/java/net/httpclient/SmallTimeout.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * 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,12 +46,12 @@ import static java.lang.System.out; * @bug 8178147 * @modules java.net.http/jdk.internal.net.http.common * @summary Ensures that small timeouts do not cause hangs due to race conditions - * @run main/othervm -Djdk.internal.httpclient.debug=true SmallTimeout + * @run main/othervm -Djdk.internal.httpclient.debug=true ${test.main.class} */ // To enable logging use. Not enabled by default as it changes the dynamics // of the test. -// @run main/othervm -Djdk.httpclient.HttpClient.log=all,frames:all SmallTimeout +// @run main/othervm -Djdk.httpclient.HttpClient.log=all,frames:all ${test.main.class} public class SmallTimeout { diff --git a/test/jdk/java/net/httpclient/SmokeTest.java b/test/jdk/java/net/httpclient/SmokeTest.java index f87cc462fac..487e6cbe21a 100644 --- a/test/jdk/java/net/httpclient/SmokeTest.java +++ b/test/jdk/java/net/httpclient/SmokeTest.java @@ -30,7 +30,7 @@ * @run main/othervm * -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.HttpClient.log=errors,ssl,trace - * SmokeTest + * ${test.main.class} */ import java.net.InetAddress; diff --git a/test/jdk/java/net/httpclient/SpecialHeadersTest.java b/test/jdk/java/net/httpclient/SpecialHeadersTest.java index d4d5f2a85e2..4e022c5b273 100644 --- a/test/jdk/java/net/httpclient/SpecialHeadersTest.java +++ b/test/jdk/java/net/httpclient/SpecialHeadersTest.java @@ -33,10 +33,10 @@ * @requires (vm.compMode != "Xcomp") * @run junit/othervm/timeout=480 * -Djdk.httpclient.HttpClient.log=requests,headers,errors - * SpecialHeadersTest + * ${test.main.class} * @run junit/othervm/timeout=480 -Djdk.httpclient.allowRestrictedHeaders=Host * -Djdk.httpclient.HttpClient.log=requests,headers,errors - * SpecialHeadersTest + * ${test.main.class} */ import jdk.internal.net.http.common.OperationTrackers.Tracker; diff --git a/test/jdk/java/net/httpclient/SplitResponse.java b/test/jdk/java/net/httpclient/SplitResponse.java index abc972fd591..4e0c6b2ba6c 100644 --- a/test/jdk/java/net/httpclient/SplitResponse.java +++ b/test/jdk/java/net/httpclient/SplitResponse.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -54,7 +54,7 @@ import static java.net.http.HttpResponse.BodyHandlers.ofString; * @run main/othervm/timeout=480 * -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.HttpClient.log=all - * SplitResponse HTTP connection:CLOSE mode:SYNC + * ${test.main.class} HTTP connection:CLOSE mode:SYNC */ /** diff --git a/test/jdk/java/net/httpclient/StreamCloseTest.java b/test/jdk/java/net/httpclient/StreamCloseTest.java index 7b228e69de2..49e03a54c59 100644 --- a/test/jdk/java/net/httpclient/StreamCloseTest.java +++ b/test/jdk/java/net/httpclient/StreamCloseTest.java @@ -30,7 +30,7 @@ * @library /test/lib * @build jdk.httpclient.test.lib.common.HttpServerAdapters * jdk.httpclient.test.lib.http2.Http2TestServer - * @run junit/othervm StreamCloseTest + * @run junit/othervm ${test.main.class} */ import java.io.InputStream; diff --git a/test/jdk/java/net/httpclient/SubscriberAPIExceptions.java b/test/jdk/java/net/httpclient/SubscriberAPIExceptions.java index 93f55d066e9..1902abb4a26 100644 --- a/test/jdk/java/net/httpclient/SubscriberAPIExceptions.java +++ b/test/jdk/java/net/httpclient/SubscriberAPIExceptions.java @@ -49,7 +49,7 @@ import org.junit.jupiter.api.Test; * @test * @summary Basic tests for API specified exceptions from Handler, * and Subscriber convenience static factory methods. - * @run junit SubscriberAPIExceptions + * @run junit ${test.main.class} */ public class SubscriberAPIExceptions { diff --git a/test/jdk/java/net/httpclient/TestKitTest.java b/test/jdk/java/net/httpclient/TestKitTest.java index 2aba794426f..28a1bab5a69 100644 --- a/test/jdk/java/net/httpclient/TestKitTest.java +++ b/test/jdk/java/net/httpclient/TestKitTest.java @@ -41,7 +41,7 @@ import org.junit.jupiter.api.Test; /* * @test * @compile TestKit.java - * @run junit TestKitTest + * @run junit ${test.main.class} */ public final class TestKitTest { diff --git a/test/jdk/java/net/httpclient/ThrowingPublishersCustomAfterCancel.java b/test/jdk/java/net/httpclient/ThrowingPublishersCustomAfterCancel.java index 2c1aa2fd9b4..43d3bebf2e4 100644 --- a/test/jdk/java/net/httpclient/ThrowingPublishersCustomAfterCancel.java +++ b/test/jdk/java/net/httpclient/ThrowingPublishersCustomAfterCancel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,7 @@ * jdk.httpclient.test.lib.common.HttpServerAdapters * @run junit/othervm -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.enableAllMethodRetry=true - * ThrowingPublishersCustomAfterCancel + * ${test.main.class} */ diff --git a/test/jdk/java/net/httpclient/ThrowingPublishersCustomBeforeCancel.java b/test/jdk/java/net/httpclient/ThrowingPublishersCustomBeforeCancel.java index ba734185464..e0ff3e2e42a 100644 --- a/test/jdk/java/net/httpclient/ThrowingPublishersCustomBeforeCancel.java +++ b/test/jdk/java/net/httpclient/ThrowingPublishersCustomBeforeCancel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,7 @@ * jdk.httpclient.test.lib.common.HttpServerAdapters * @run junit/othervm -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.enableAllMethodRetry=true - * ThrowingPublishersCustomBeforeCancel + * ${test.main.class} */ diff --git a/test/jdk/java/net/httpclient/ThrowingPublishersIOAfterCancel.java b/test/jdk/java/net/httpclient/ThrowingPublishersIOAfterCancel.java index a5e819942b4..023a2281bce 100644 --- a/test/jdk/java/net/httpclient/ThrowingPublishersIOAfterCancel.java +++ b/test/jdk/java/net/httpclient/ThrowingPublishersIOAfterCancel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,7 @@ * jdk.httpclient.test.lib.common.HttpServerAdapters * @run junit/othervm -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.enableAllMethodRetry=true - * ThrowingPublishersIOAfterCancel + * ${test.main.class} */ diff --git a/test/jdk/java/net/httpclient/ThrowingPublishersIOBeforeCancel.java b/test/jdk/java/net/httpclient/ThrowingPublishersIOBeforeCancel.java index e68f83052bd..54ddbebdd82 100644 --- a/test/jdk/java/net/httpclient/ThrowingPublishersIOBeforeCancel.java +++ b/test/jdk/java/net/httpclient/ThrowingPublishersIOBeforeCancel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,7 @@ * jdk.httpclient.test.lib.common.HttpServerAdapters * @run junit/othervm -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.enableAllMethodRetry=true - * ThrowingPublishersIOBeforeCancel + * ${test.main.class} */ diff --git a/test/jdk/java/net/httpclient/ThrowingPublishersInNextRequest.java b/test/jdk/java/net/httpclient/ThrowingPublishersInNextRequest.java index 62d06fd6019..d690a2bbb3b 100644 --- a/test/jdk/java/net/httpclient/ThrowingPublishersInNextRequest.java +++ b/test/jdk/java/net/httpclient/ThrowingPublishersInNextRequest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,7 @@ * jdk.httpclient.test.lib.common.HttpServerAdapters * @run junit/othervm -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.enableAllMethodRetry=true - * ThrowingPublishersInNextRequest + * ${test.main.class} */ diff --git a/test/jdk/java/net/httpclient/ThrowingPublishersInRequest.java b/test/jdk/java/net/httpclient/ThrowingPublishersInRequest.java index f863f3598ed..c8255ba5fff 100644 --- a/test/jdk/java/net/httpclient/ThrowingPublishersInRequest.java +++ b/test/jdk/java/net/httpclient/ThrowingPublishersInRequest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,7 @@ * jdk.httpclient.test.lib.common.HttpServerAdapters * @run junit/othervm -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.enableAllMethodRetry=true - * ThrowingPublishersInRequest + * ${test.main.class} */ diff --git a/test/jdk/java/net/httpclient/ThrowingPublishersInSubscribe.java b/test/jdk/java/net/httpclient/ThrowingPublishersInSubscribe.java index ce1ad89dc05..400e28e17fc 100644 --- a/test/jdk/java/net/httpclient/ThrowingPublishersInSubscribe.java +++ b/test/jdk/java/net/httpclient/ThrowingPublishersInSubscribe.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,7 @@ * jdk.httpclient.test.lib.common.HttpServerAdapters * @run junit/othervm -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.enableAllMethodRetry=true - * ThrowingPublishersInSubscribe + * ${test.main.class} */ diff --git a/test/jdk/java/net/httpclient/ThrowingPublishersSanity.java b/test/jdk/java/net/httpclient/ThrowingPublishersSanity.java index eee2f9ab7fb..e14ced23514 100644 --- a/test/jdk/java/net/httpclient/ThrowingPublishersSanity.java +++ b/test/jdk/java/net/httpclient/ThrowingPublishersSanity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,7 @@ * jdk.httpclient.test.lib.common.HttpServerAdapters * @run junit/othervm -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.enableAllMethodRetry=true - * ThrowingPublishersSanity + * ${test.main.class} */ import org.junit.jupiter.params.ParameterizedTest; diff --git a/test/jdk/java/net/httpclient/ThrowingPushPromisesAsInputStreamCustom.java b/test/jdk/java/net/httpclient/ThrowingPushPromisesAsInputStreamCustom.java index 797507ac7ad..a70f8f1b3f3 100644 --- a/test/jdk/java/net/httpclient/ThrowingPushPromisesAsInputStreamCustom.java +++ b/test/jdk/java/net/httpclient/ThrowingPushPromisesAsInputStreamCustom.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,7 @@ * @build jdk.test.lib.net.SimpleSSLContext * ReferenceTracker AbstractThrowingPushPromises ThrowingPushPromisesAsInputStreamCustom * jdk.httpclient.test.lib.common.HttpServerAdapters - * @run junit/othervm -Djdk.internal.httpclient.debug=true ThrowingPushPromisesAsInputStreamCustom + * @run junit/othervm -Djdk.internal.httpclient.debug=true ${test.main.class} */ import org.junit.jupiter.params.ParameterizedTest; diff --git a/test/jdk/java/net/httpclient/ThrowingPushPromisesAsInputStreamIO.java b/test/jdk/java/net/httpclient/ThrowingPushPromisesAsInputStreamIO.java index 309f60c0f22..04fd641f66a 100644 --- a/test/jdk/java/net/httpclient/ThrowingPushPromisesAsInputStreamIO.java +++ b/test/jdk/java/net/httpclient/ThrowingPushPromisesAsInputStreamIO.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,7 @@ * @build jdk.test.lib.net.SimpleSSLContext * ReferenceTracker AbstractThrowingPushPromises ThrowingPushPromisesAsInputStreamIO * jdk.httpclient.test.lib.common.HttpServerAdapters - * @run junit/othervm -Djdk.internal.httpclient.debug=true ThrowingPushPromisesAsInputStreamIO + * @run junit/othervm -Djdk.internal.httpclient.debug=true ${test.main.class} */ import org.junit.jupiter.params.ParameterizedTest; diff --git a/test/jdk/java/net/httpclient/ThrowingPushPromisesAsLinesCustom.java b/test/jdk/java/net/httpclient/ThrowingPushPromisesAsLinesCustom.java index 77c87151e19..59cae941d6d 100644 --- a/test/jdk/java/net/httpclient/ThrowingPushPromisesAsLinesCustom.java +++ b/test/jdk/java/net/httpclient/ThrowingPushPromisesAsLinesCustom.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,7 @@ * @build jdk.test.lib.net.SimpleSSLContext * ReferenceTracker AbstractThrowingPushPromises ThrowingPushPromisesAsLinesCustom * jdk.httpclient.test.lib.common.HttpServerAdapters - * @run junit/othervm -Djdk.internal.httpclient.debug=true ThrowingPushPromisesAsLinesCustom + * @run junit/othervm -Djdk.internal.httpclient.debug=true ${test.main.class} */ import org.junit.jupiter.params.ParameterizedTest; diff --git a/test/jdk/java/net/httpclient/ThrowingPushPromisesAsLinesIO.java b/test/jdk/java/net/httpclient/ThrowingPushPromisesAsLinesIO.java index 69deeec533a..f346829fe19 100644 --- a/test/jdk/java/net/httpclient/ThrowingPushPromisesAsLinesIO.java +++ b/test/jdk/java/net/httpclient/ThrowingPushPromisesAsLinesIO.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,7 @@ * @build jdk.test.lib.net.SimpleSSLContext * ReferenceTracker AbstractThrowingPushPromises ThrowingPushPromisesAsLinesIO * jdk.httpclient.test.lib.common.HttpServerAdapters - * @run junit/othervm -Djdk.internal.httpclient.debug=true ThrowingPushPromisesAsLinesIO + * @run junit/othervm -Djdk.internal.httpclient.debug=true ${test.main.class} */ import org.junit.jupiter.params.ParameterizedTest; diff --git a/test/jdk/java/net/httpclient/ThrowingPushPromisesAsStringCustom.java b/test/jdk/java/net/httpclient/ThrowingPushPromisesAsStringCustom.java index de38cf4f782..7180784c553 100644 --- a/test/jdk/java/net/httpclient/ThrowingPushPromisesAsStringCustom.java +++ b/test/jdk/java/net/httpclient/ThrowingPushPromisesAsStringCustom.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,7 @@ * @build jdk.test.lib.net.SimpleSSLContext * ReferenceTracker AbstractThrowingPushPromises ThrowingPushPromisesAsStringCustom * jdk.httpclient.test.lib.common.HttpServerAdapters - * @run junit/othervm -Djdk.internal.httpclient.debug=true ThrowingPushPromisesAsStringCustom + * @run junit/othervm -Djdk.internal.httpclient.debug=true ${test.main.class} */ import org.junit.jupiter.params.ParameterizedTest; diff --git a/test/jdk/java/net/httpclient/ThrowingPushPromisesAsStringIO.java b/test/jdk/java/net/httpclient/ThrowingPushPromisesAsStringIO.java index ec4d682d73f..ea56f30e11f 100644 --- a/test/jdk/java/net/httpclient/ThrowingPushPromisesAsStringIO.java +++ b/test/jdk/java/net/httpclient/ThrowingPushPromisesAsStringIO.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,7 @@ * @build jdk.test.lib.net.SimpleSSLContext * ReferenceTracker AbstractThrowingPushPromises ThrowingPushPromisesAsStringIO * jdk.httpclient.test.lib.common.HttpServerAdapters - * @run junit/othervm -Djdk.internal.httpclient.debug=true ThrowingPushPromisesAsStringIO + * @run junit/othervm -Djdk.internal.httpclient.debug=true ${test.main.class} */ import org.junit.jupiter.params.ParameterizedTest; diff --git a/test/jdk/java/net/httpclient/ThrowingPushPromisesSanity.java b/test/jdk/java/net/httpclient/ThrowingPushPromisesSanity.java index 92f2ab3726d..aeaec438ec4 100644 --- a/test/jdk/java/net/httpclient/ThrowingPushPromisesSanity.java +++ b/test/jdk/java/net/httpclient/ThrowingPushPromisesSanity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,7 @@ * @build jdk.test.lib.net.SimpleSSLContext * ReferenceTracker AbstractThrowingPushPromises ThrowingPushPromisesSanity * jdk.httpclient.test.lib.common.HttpServerAdapters - * @run junit/othervm -Djdk.internal.httpclient.debug=true ThrowingPushPromisesSanity + * @run junit/othervm -Djdk.internal.httpclient.debug=true ${test.main.class} */ import org.junit.jupiter.params.ParameterizedTest; diff --git a/test/jdk/java/net/httpclient/ThrowingSubscribersAsInputStream.java b/test/jdk/java/net/httpclient/ThrowingSubscribersAsInputStream.java index a4c0fc72004..77d1992e948 100644 --- a/test/jdk/java/net/httpclient/ThrowingSubscribersAsInputStream.java +++ b/test/jdk/java/net/httpclient/ThrowingSubscribersAsInputStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,7 @@ * @build jdk.test.lib.net.SimpleSSLContext * ReferenceTracker ThrowingSubscribersAsInputStream AbstractThrowingSubscribers * jdk.httpclient.test.lib.common.HttpServerAdapters - * @run junit/othervm -Djdk.internal.httpclient.debug=true ThrowingSubscribersAsInputStream + * @run junit/othervm -Djdk.internal.httpclient.debug=true ${test.main.class} */ import org.junit.jupiter.params.ParameterizedTest; diff --git a/test/jdk/java/net/httpclient/ThrowingSubscribersAsInputStreamAsync.java b/test/jdk/java/net/httpclient/ThrowingSubscribersAsInputStreamAsync.java index aec4641917c..68df5a2b8b3 100644 --- a/test/jdk/java/net/httpclient/ThrowingSubscribersAsInputStreamAsync.java +++ b/test/jdk/java/net/httpclient/ThrowingSubscribersAsInputStreamAsync.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,7 @@ * @build jdk.test.lib.net.SimpleSSLContext * ReferenceTracker ThrowingSubscribersAsInputStreamAsync AbstractThrowingSubscribers * jdk.httpclient.test.lib.common.HttpServerAdapters - * @run junit/othervm -Djdk.internal.httpclient.debug=true ThrowingSubscribersAsInputStreamAsync + * @run junit/othervm -Djdk.internal.httpclient.debug=true ${test.main.class} */ import org.junit.jupiter.params.ParameterizedTest; diff --git a/test/jdk/java/net/httpclient/ThrowingSubscribersAsLimiting.java b/test/jdk/java/net/httpclient/ThrowingSubscribersAsLimiting.java index 603a8558856..1a9ffe9c182 100644 --- a/test/jdk/java/net/httpclient/ThrowingSubscribersAsLimiting.java +++ b/test/jdk/java/net/httpclient/ThrowingSubscribersAsLimiting.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ * ReferenceTracker * jdk.httpclient.test.lib.common.HttpServerAdapters * jdk.test.lib.net.SimpleSSLContext - * @run junit/othervm -Djdk.internal.httpclient.debug=true ThrowingSubscribersAsLimiting + * @run junit/othervm -Djdk.internal.httpclient.debug=true ${test.main.class} */ diff --git a/test/jdk/java/net/httpclient/ThrowingSubscribersAsLimitingAsync.java b/test/jdk/java/net/httpclient/ThrowingSubscribersAsLimitingAsync.java index e45c6d6487e..31b807beea0 100644 --- a/test/jdk/java/net/httpclient/ThrowingSubscribersAsLimitingAsync.java +++ b/test/jdk/java/net/httpclient/ThrowingSubscribersAsLimitingAsync.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ * ReferenceTracker * jdk.httpclient.test.lib.common.HttpServerAdapters * jdk.test.lib.net.SimpleSSLContext - * @run junit/othervm -Djdk.internal.httpclient.debug=true ThrowingSubscribersAsLimitingAsync + * @run junit/othervm -Djdk.internal.httpclient.debug=true ${test.main.class} */ import org.junit.jupiter.params.ParameterizedTest; diff --git a/test/jdk/java/net/httpclient/ThrowingSubscribersAsLines.java b/test/jdk/java/net/httpclient/ThrowingSubscribersAsLines.java index ba594166b72..9915b921b1f 100644 --- a/test/jdk/java/net/httpclient/ThrowingSubscribersAsLines.java +++ b/test/jdk/java/net/httpclient/ThrowingSubscribersAsLines.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,7 @@ * @build jdk.test.lib.net.SimpleSSLContext * ReferenceTracker ThrowingSubscribersAsLines AbstractThrowingSubscribers * jdk.httpclient.test.lib.common.HttpServerAdapters - * @run junit/othervm -Djdk.internal.httpclient.debug=true ThrowingSubscribersAsLines + * @run junit/othervm -Djdk.internal.httpclient.debug=true ${test.main.class} */ import org.junit.jupiter.params.ParameterizedTest; diff --git a/test/jdk/java/net/httpclient/ThrowingSubscribersAsLinesAsync.java b/test/jdk/java/net/httpclient/ThrowingSubscribersAsLinesAsync.java index a76ff882463..4fd41b987d0 100644 --- a/test/jdk/java/net/httpclient/ThrowingSubscribersAsLinesAsync.java +++ b/test/jdk/java/net/httpclient/ThrowingSubscribersAsLinesAsync.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,7 @@ * @build jdk.test.lib.net.SimpleSSLContext * ReferenceTracker ThrowingSubscribersAsLinesAsync AbstractThrowingSubscribers * jdk.httpclient.test.lib.common.HttpServerAdapters - * @run junit/othervm -Djdk.internal.httpclient.debug=true ThrowingSubscribersAsLinesAsync + * @run junit/othervm -Djdk.internal.httpclient.debug=true ${test.main.class} */ import org.junit.jupiter.params.ParameterizedTest; diff --git a/test/jdk/java/net/httpclient/ThrowingSubscribersAsString.java b/test/jdk/java/net/httpclient/ThrowingSubscribersAsString.java index ba550675096..4fe15f99448 100644 --- a/test/jdk/java/net/httpclient/ThrowingSubscribersAsString.java +++ b/test/jdk/java/net/httpclient/ThrowingSubscribersAsString.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,7 @@ * @build jdk.test.lib.net.SimpleSSLContext * ReferenceTracker ThrowingSubscribersAsString AbstractThrowingSubscribers * jdk.httpclient.test.lib.common.HttpServerAdapters - * @run junit/othervm -Djdk.internal.httpclient.debug=true ThrowingSubscribersAsString + * @run junit/othervm -Djdk.internal.httpclient.debug=true ${test.main.class} */ import org.junit.jupiter.params.ParameterizedTest; diff --git a/test/jdk/java/net/httpclient/ThrowingSubscribersAsStringAsync.java b/test/jdk/java/net/httpclient/ThrowingSubscribersAsStringAsync.java index 304d98e6939..879f0fad5a3 100644 --- a/test/jdk/java/net/httpclient/ThrowingSubscribersAsStringAsync.java +++ b/test/jdk/java/net/httpclient/ThrowingSubscribersAsStringAsync.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,7 @@ * @build jdk.test.lib.net.SimpleSSLContext * ReferenceTracker ThrowingSubscribersAsStringAsync AbstractThrowingSubscribers * jdk.httpclient.test.lib.common.HttpServerAdapters - * @run junit/othervm -Djdk.internal.httpclient.debug=true ThrowingSubscribersAsStringAsync + * @run junit/othervm -Djdk.internal.httpclient.debug=true ${test.main.class} */ import org.junit.jupiter.params.ParameterizedTest; diff --git a/test/jdk/java/net/httpclient/ThrowingSubscribersSanity.java b/test/jdk/java/net/httpclient/ThrowingSubscribersSanity.java index 296e9151c9e..9481d64e195 100644 --- a/test/jdk/java/net/httpclient/ThrowingSubscribersSanity.java +++ b/test/jdk/java/net/httpclient/ThrowingSubscribersSanity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,7 @@ * @build jdk.test.lib.net.SimpleSSLContext * ReferenceTracker ThrowingSubscribersSanity AbstractThrowingSubscribers * jdk.httpclient.test.lib.common.HttpServerAdapters - * @run junit/othervm -Djdk.internal.httpclient.debug=true ThrowingSubscribersSanity + * @run junit/othervm -Djdk.internal.httpclient.debug=true ${test.main.class} */ import org.junit.jupiter.params.ParameterizedTest; diff --git a/test/jdk/java/net/httpclient/TimeoutBasic.java b/test/jdk/java/net/httpclient/TimeoutBasic.java index cae1cda7ade..ba986bbc0d2 100644 --- a/test/jdk/java/net/httpclient/TimeoutBasic.java +++ b/test/jdk/java/net/httpclient/TimeoutBasic.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -60,7 +60,7 @@ import static java.net.http.HttpOption.H3_DISCOVERY; * @library /test/lib * @build jdk.test.lib.net.SimpleSSLContext * @summary Basic tests for response timeouts - * @run main/othervm TimeoutBasic + * @run main/othervm ${test.main.class} */ public class TimeoutBasic { diff --git a/test/jdk/java/net/httpclient/TimeoutOrdering.java b/test/jdk/java/net/httpclient/TimeoutOrdering.java index a39242c871a..ebe8cb3324e 100644 --- a/test/jdk/java/net/httpclient/TimeoutOrdering.java +++ b/test/jdk/java/net/httpclient/TimeoutOrdering.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,11 +41,11 @@ import static java.lang.System.out; /** * @test * @summary Ensures that timeouts of multiple requests are handled in correct order - * @run main/othervm TimeoutOrdering + * @run main/othervm ${test.main.class} */ // To enable logging use -// @run main/othervm -Djdk.httpclient.HttpClient.log=all,frames:all TimeoutOrdering +// @run main/othervm -Djdk.httpclient.HttpClient.log=all,frames:all ${test.main.class} public class TimeoutOrdering { diff --git a/test/jdk/java/net/httpclient/TimeoutResponseBodyTest.java b/test/jdk/java/net/httpclient/TimeoutResponseBodyTest.java index 093885a6ba0..9a09b5acf90 100644 --- a/test/jdk/java/net/httpclient/TimeoutResponseBodyTest.java +++ b/test/jdk/java/net/httpclient/TimeoutResponseBodyTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,7 +55,7 @@ import static org.junit.jupiter.api.Assertions.fail; * -Djdk.httpclient.disableRetryConnect * -Djdk.httpclient.redirects.retrylimit=0 * -Dtest.requestTimeoutMillis=1000 - * TimeoutResponseBodyTest + * ${test.main.class} */ /* @@ -79,7 +79,7 @@ import static org.junit.jupiter.api.Assertions.fail; * -Djdk.httpclient.redirects.retrylimit=3 * -Dtest.requestTimeoutMillis=1000 * -Dtest.responseFailureWaitDurationMillis=600 - * TimeoutResponseBodyTest + * ${test.main.class} */ /** diff --git a/test/jdk/java/net/httpclient/TimeoutResponseHeaderTest.java b/test/jdk/java/net/httpclient/TimeoutResponseHeaderTest.java index ab562f8eab8..6ea2da4c21e 100644 --- a/test/jdk/java/net/httpclient/TimeoutResponseHeaderTest.java +++ b/test/jdk/java/net/httpclient/TimeoutResponseHeaderTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,7 +52,7 @@ import static org.junit.jupiter.api.Assertions.assertTimeoutPreemptively; * -Djdk.httpclient.disableRetryConnect * -Djdk.httpclient.redirects.retrylimit=0 * -Dtest.requestTimeoutMillis=1000 - * TimeoutResponseHeaderTest + * ${test.main.class} */ /* @@ -76,7 +76,7 @@ import static org.junit.jupiter.api.Assertions.assertTimeoutPreemptively; * -Djdk.httpclient.redirects.retrylimit=3 * -Dtest.requestTimeoutMillis=1000 * -Dtest.responseFailureWaitDurationMillis=600 - * TimeoutResponseHeaderTest + * ${test.main.class} */ /** diff --git a/test/jdk/java/net/httpclient/TlsContextTest.java b/test/jdk/java/net/httpclient/TlsContextTest.java index 95cb501d24c..052b20f94eb 100644 --- a/test/jdk/java/net/httpclient/TlsContextTest.java +++ b/test/jdk/java/net/httpclient/TlsContextTest.java @@ -63,7 +63,7 @@ import org.junit.jupiter.params.provider.MethodSource; * -Djdk.httpclient.HttpClient.log=headers * -Djdk.internal.httpclient.disableHostnameVerification * -Djdk.internal.httpclient.debug=false - * TlsContextTest + * ${test.main.class} */ public class TlsContextTest implements HttpServerAdapters { diff --git a/test/jdk/java/net/httpclient/UnauthorizedTest.java b/test/jdk/java/net/httpclient/UnauthorizedTest.java index 1c72bac6cc9..931b9681559 100644 --- a/test/jdk/java/net/httpclient/UnauthorizedTest.java +++ b/test/jdk/java/net/httpclient/UnauthorizedTest.java @@ -34,7 +34,7 @@ * jdk.test.lib.net.SimpleSSLContext ReferenceTracker * @run junit/othervm * -Djdk.httpclient.HttpClient.log=headers - * UnauthorizedTest + * ${test.main.class} */ import jdk.test.lib.net.SimpleSSLContext; diff --git a/test/jdk/java/net/httpclient/UnknownBodyLengthTest.java b/test/jdk/java/net/httpclient/UnknownBodyLengthTest.java index 6c7fabb7f00..4b92eb83fdd 100644 --- a/test/jdk/java/net/httpclient/UnknownBodyLengthTest.java +++ b/test/jdk/java/net/httpclient/UnknownBodyLengthTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ import jdk.test.lib.net.SimpleSSLContext; * @library /test/lib * @build jdk.test.lib.net.SimpleSSLContext * @run main/othervm -Djdk.httpclient.enableAllMethodRetry - * -Djdk.tls.acknowledgeCloseNotify=true UnknownBodyLengthTest plain false + * -Djdk.tls.acknowledgeCloseNotify=true ${test.main.class} plain false * @run main/othervm -Djdk.httpclient.enableAllMethodRetry - * -Djdk.tls.acknowledgeCloseNotify=true UnknownBodyLengthTest SSL false + * -Djdk.tls.acknowledgeCloseNotify=true ${test.main.class} SSL false * @run main/othervm -Djdk.httpclient.enableAllMethodRetry - * -Djdk.tls.acknowledgeCloseNotify=true UnknownBodyLengthTest plain true + * -Djdk.tls.acknowledgeCloseNotify=true ${test.main.class} plain true * @run main/othervm -Djdk.httpclient.enableAllMethodRetry - * -Djdk.tls.acknowledgeCloseNotify=true UnknownBodyLengthTest SSL true + * -Djdk.tls.acknowledgeCloseNotify=true ${test.main.class} SSL true */ public class UnknownBodyLengthTest { diff --git a/test/jdk/java/net/httpclient/UserAuthWithAuthenticator.java b/test/jdk/java/net/httpclient/UserAuthWithAuthenticator.java index 6062fcd9448..3f5f004738a 100644 --- a/test/jdk/java/net/httpclient/UserAuthWithAuthenticator.java +++ b/test/jdk/java/net/httpclient/UserAuthWithAuthenticator.java @@ -74,7 +74,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; * @build jdk.test.lib.net.SimpleSSLContext jdk.httpclient.test.lib.common.HttpServerAdapters * jdk.httpclient.test.lib.http2.Http2TestServer * jdk.test.lib.net.IPSupport - * @run junit UserAuthWithAuthenticator + * @run junit ${test.main.class} */ class UserAuthWithAuthenticator { diff --git a/test/jdk/java/net/httpclient/UserCookieTest.java b/test/jdk/java/net/httpclient/UserCookieTest.java index f49f44c157c..664565f6bd7 100644 --- a/test/jdk/java/net/httpclient/UserCookieTest.java +++ b/test/jdk/java/net/httpclient/UserCookieTest.java @@ -31,7 +31,7 @@ * @run junit/othervm * -Djdk.tls.acknowledgeCloseNotify=true * -Djdk.httpclient.HttpClient.log=trace,headers,requests - * UserCookieTest + * ${test.main.class} */ import java.io.IOException; diff --git a/test/jdk/java/net/httpclient/VersionTest.java b/test/jdk/java/net/httpclient/VersionTest.java index ff864202a9a..546c0933ec5 100644 --- a/test/jdk/java/net/httpclient/VersionTest.java +++ b/test/jdk/java/net/httpclient/VersionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,7 +27,7 @@ * @modules java.net.http java.logging jdk.httpserver * @library /lib/testlibrary/ / * @build ProxyServer - * @run main/othervm -Djdk.httpclient.HttpClient.log=errors,requests,headers,trace VersionTest + * @run main/othervm -Djdk.httpclient.HttpClient.log=errors,requests,headers,trace ${test.main.class} */ import com.sun.net.httpserver.Headers; diff --git a/test/jdk/java/net/httpclient/ZeroRedirects.java b/test/jdk/java/net/httpclient/ZeroRedirects.java index a842ea57930..fe62cc9e77f 100644 --- a/test/jdk/java/net/httpclient/ZeroRedirects.java +++ b/test/jdk/java/net/httpclient/ZeroRedirects.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,7 @@ * @test * @bug 8164941 * @modules java.net.http java.logging jdk.httpserver - * @run main/othervm ZeroRedirects + * @run main/othervm ${test.main.class} */ import com.sun.net.httpserver.HttpContext; diff --git a/test/jdk/java/net/httpclient/altsvc/AltServiceReasonableAssurance.java b/test/jdk/java/net/httpclient/altsvc/AltServiceReasonableAssurance.java index 0da1b238f60..fab27463d90 100644 --- a/test/jdk/java/net/httpclient/altsvc/AltServiceReasonableAssurance.java +++ b/test/jdk/java/net/httpclient/altsvc/AltServiceReasonableAssurance.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ import static org.junit.jupiter.api.Assertions.assertTrue; * @run junit/othervm -Djdk.net.hosts.file=${test.src}/altsvc-dns-hosts.txt * -Djdk.internal.httpclient.debug=true -Djavax.net.debug=all * -Djdk.httpclient.HttpClient.log=requests,responses,errors - * AltServiceReasonableAssurance + * ${test.main.class} */ public class AltServiceReasonableAssurance implements HttpServerAdapters { diff --git a/test/jdk/java/net/httpclient/http2/BadHeadersTest.java b/test/jdk/java/net/httpclient/http2/BadHeadersTest.java index 3bb80031178..01ff090cba7 100644 --- a/test/jdk/java/net/httpclient/http2/BadHeadersTest.java +++ b/test/jdk/java/net/httpclient/http2/BadHeadersTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ * with bad header fields. * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.httpclient.test.lib.http2.Http2TestServer jdk.test.lib.net.SimpleSSLContext - * @run junit/othervm -Djdk.internal.httpclient.debug=true BadHeadersTest + * @run junit/othervm -Djdk.internal.httpclient.debug=true ${test.main.class} */ import jdk.internal.net.http.common.HttpHeadersBuilder; diff --git a/test/jdk/java/net/httpclient/http2/BadPushPromiseTest.java b/test/jdk/java/net/httpclient/http2/BadPushPromiseTest.java index 8eed173409b..8febbb8a12a 100644 --- a/test/jdk/java/net/httpclient/http2/BadPushPromiseTest.java +++ b/test/jdk/java/net/httpclient/http2/BadPushPromiseTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @run junit/othervm * -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.HttpClient.log=errors,requests,responses,trace - * BadPushPromiseTest + * ${test.main.class} */ import jdk.httpclient.test.lib.common.HttpServerAdapters; diff --git a/test/jdk/java/net/httpclient/http2/BasicTest.java b/test/jdk/java/net/httpclient/http2/BasicTest.java index ddcf707e875..b76179f2e71 100644 --- a/test/jdk/java/net/httpclient/http2/BasicTest.java +++ b/test/jdk/java/net/httpclient/http2/BasicTest.java @@ -30,7 +30,7 @@ * jdk.test.lib.Asserts * jdk.test.lib.Utils * jdk.test.lib.net.SimpleSSLContext - * @run junit/othervm -Djdk.httpclient.HttpClient.log=ssl,requests,responses,errors BasicTest + * @run junit/othervm -Djdk.httpclient.HttpClient.log=ssl,requests,responses,errors ${test.main.class} */ import java.io.IOException; diff --git a/test/jdk/java/net/httpclient/http2/ConnectionFlowControlTest.java b/test/jdk/java/net/httpclient/http2/ConnectionFlowControlTest.java index 1b9396effbb..36c46ed3aba 100644 --- a/test/jdk/java/net/httpclient/http2/ConnectionFlowControlTest.java +++ b/test/jdk/java/net/httpclient/http2/ConnectionFlowControlTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ * @run junit/othervm -Djdk.internal.httpclient.debug=err * -Djdk.httpclient.connectionWindowSize=65535 * -Djdk.httpclient.windowsize=16384 - * ConnectionFlowControlTest + * ${test.main.class} */ import java.io.IOException; diff --git a/test/jdk/java/net/httpclient/http2/ConnectionReuseTest.java b/test/jdk/java/net/httpclient/http2/ConnectionReuseTest.java index 360eabaee2b..9396ccd169f 100644 --- a/test/jdk/java/net/httpclient/http2/ConnectionReuseTest.java +++ b/test/jdk/java/net/httpclient/http2/ConnectionReuseTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * 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,9 +62,9 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; * jdk.test.lib.net.IPSupport * jdk.httpclient.test.lib.common.HttpServerAdapters * - * @run junit ConnectionReuseTest + * @run junit ${test.main.class} * @run junit/othervm -Djava.net.preferIPv6Addresses=true - * -Djdk.internal.httpclient.debug=true ConnectionReuseTest + * -Djdk.internal.httpclient.debug=true ${test.main.class} */ public class ConnectionReuseTest { diff --git a/test/jdk/java/net/httpclient/http2/ContinuationFrameTest.java b/test/jdk/java/net/httpclient/http2/ContinuationFrameTest.java index c72beb04d56..cd788db6c7d 100644 --- a/test/jdk/java/net/httpclient/http2/ContinuationFrameTest.java +++ b/test/jdk/java/net/httpclient/http2/ContinuationFrameTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,7 +27,7 @@ * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.httpclient.test.lib.http2.Http2TestServer jdk.test.lib.net.SimpleSSLContext * @compile ../ReferenceTracker.java - * @run junit/othervm ContinuationFrameTest + * @run junit/othervm ${test.main.class} */ import java.io.IOException; diff --git a/test/jdk/java/net/httpclient/http2/ErrorTest.java b/test/jdk/java/net/httpclient/http2/ErrorTest.java index 0f3bafa571d..3e3ce97b582 100644 --- a/test/jdk/java/net/httpclient/http2/ErrorTest.java +++ b/test/jdk/java/net/httpclient/http2/ErrorTest.java @@ -45,7 +45,7 @@ * java.net.http/jdk.internal.net.http.qpack.writers * java.security.jgss * @modules java.base/jdk.internal.util - * @run junit/othervm/timeout=60 -Djavax.net.debug=ssl -Djdk.httpclient.HttpClient.log=all ErrorTest + * @run junit/othervm/timeout=60 -Djavax.net.debug=ssl -Djdk.httpclient.HttpClient.log=all ${test.main.class} * @summary check exception thrown when bad TLS parameters selected */ diff --git a/test/jdk/java/net/httpclient/http2/FixedThreadPoolTest.java b/test/jdk/java/net/httpclient/http2/FixedThreadPoolTest.java index d788d39b441..883e14e7d58 100644 --- a/test/jdk/java/net/httpclient/http2/FixedThreadPoolTest.java +++ b/test/jdk/java/net/httpclient/http2/FixedThreadPoolTest.java @@ -30,7 +30,7 @@ * jdk.test.lib.Asserts * jdk.test.lib.Utils * jdk.test.lib.net.SimpleSSLContext - * @run junit/othervm -Djdk.httpclient.HttpClient.log=ssl,requests,responses,errors FixedThreadPoolTest + * @run junit/othervm -Djdk.httpclient.HttpClient.log=ssl,requests,responses,errors ${test.main.class} */ import java.net.*; diff --git a/test/jdk/java/net/httpclient/http2/H2GoAwayTest.java b/test/jdk/java/net/httpclient/http2/H2GoAwayTest.java index 08c32171d16..f656d72f244 100644 --- a/test/jdk/java/net/httpclient/http2/H2GoAwayTest.java +++ b/test/jdk/java/net/httpclient/http2/H2GoAwayTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -63,7 +63,7 @@ import static org.junit.jupiter.api.Assertions.fail; * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.httpclient.test.lib.common.HttpServerAdapters * jdk.test.lib.net.SimpleSSLContext - * @run junit H2GoAwayTest + * @run junit ${test.main.class} */ public class H2GoAwayTest { private static final String REQ_PATH = "/test"; diff --git a/test/jdk/java/net/httpclient/http2/H2SelectorVTTest.java b/test/jdk/java/net/httpclient/http2/H2SelectorVTTest.java index 7adfd57319c..552e91473d5 100644 --- a/test/jdk/java/net/httpclient/http2/H2SelectorVTTest.java +++ b/test/jdk/java/net/httpclient/http2/H2SelectorVTTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -53,7 +53,7 @@ import static java.net.http.HttpClient.Version.HTTP_2; * jdk.httpclient.test.lib.common.HttpServerAdapters * @run junit/othervm * -Djdk.httpclient.HttpClient.log=requests,responses,headers,errors - * H2SelectorVTTest + * ${test.main.class} */ /* * @test id=never @@ -66,7 +66,7 @@ import static java.net.http.HttpClient.Version.HTTP_2; * @run junit/othervm * -Djdk.internal.httpclient.tcp.selector.useVirtualThreads=never * -Djdk.httpclient.HttpClient.log=requests,responses,headers,errors - * H2SelectorVTTest + * ${test.main.class} */ /* * @test id=always @@ -79,7 +79,7 @@ import static java.net.http.HttpClient.Version.HTTP_2; * @run junit/othervm * -Djdk.internal.httpclient.tcp.selector.useVirtualThreads=always * -Djdk.httpclient.HttpClient.log=requests,responses,headers,errors - * H2SelectorVTTest + * ${test.main.class} */ /* * @test id=explicit-default @@ -92,7 +92,7 @@ import static java.net.http.HttpClient.Version.HTTP_2; * @run junit/othervm * -Djdk.internal.httpclient.tcp.selector.useVirtualThreads=default * -Djdk.httpclient.HttpClient.log=requests,responses,headers,errors - * H2SelectorVTTest + * ${test.main.class} */ /* * @test id=garbage @@ -105,7 +105,7 @@ import static java.net.http.HttpClient.Version.HTTP_2; * @run junit/othervm * -Djdk.internal.httpclient.tcp.selector.useVirtualThreads=garbage * -Djdk.httpclient.HttpClient.log=requests,responses,headers,errors - * H2SelectorVTTest + * ${test.main.class} */ // -Djava.security.debug=all class H2SelectorVTTest implements HttpServerAdapters { diff --git a/test/jdk/java/net/httpclient/http2/IdlePooledConnectionTest.java b/test/jdk/java/net/httpclient/http2/IdlePooledConnectionTest.java index 907afc28fa6..71eb483793f 100644 --- a/test/jdk/java/net/httpclient/http2/IdlePooledConnectionTest.java +++ b/test/jdk/java/net/httpclient/http2/IdlePooledConnectionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -61,7 +61,7 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; * jdk.test.lib.Asserts * @run junit/othervm -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.keepalive.timeout.h2=3 - * IdlePooledConnectionTest + * ${test.main.class} */ public class IdlePooledConnectionTest { diff --git a/test/jdk/java/net/httpclient/http2/ImplicitPushCancel.java b/test/jdk/java/net/httpclient/http2/ImplicitPushCancel.java index 5bcaf95c6fc..c273415ca63 100644 --- a/test/jdk/java/net/httpclient/http2/ImplicitPushCancel.java +++ b/test/jdk/java/net/httpclient/http2/ImplicitPushCancel.java @@ -28,7 +28,7 @@ * @run junit/othervm * -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.HttpClient.log=errors,requests,responses,trace - * ImplicitPushCancel + * ${test.main.class} */ import java.io.ByteArrayInputStream; diff --git a/test/jdk/java/net/httpclient/http2/NoBodyTest.java b/test/jdk/java/net/httpclient/http2/NoBodyTest.java index 2459c8eba4b..a67d2cd250c 100644 --- a/test/jdk/java/net/httpclient/http2/NoBodyTest.java +++ b/test/jdk/java/net/httpclient/http2/NoBodyTest.java @@ -28,7 +28,7 @@ * @build jdk.test.lib.net.SimpleSSLContext jdk.httpclient.test.lib.http2.Http2TestServer * @run junit/othervm -Djdk.httpclient.HttpClient.log=ssl,requests,responses,errors * -Djdk.internal.httpclient.debug=true - * NoBodyTest + * ${test.main.class} */ import java.io.IOException; diff --git a/test/jdk/java/net/httpclient/http2/PostPutTest.java b/test/jdk/java/net/httpclient/http2/PostPutTest.java index 84e86b556ca..132d6936039 100644 --- a/test/jdk/java/net/httpclient/http2/PostPutTest.java +++ b/test/jdk/java/net/httpclient/http2/PostPutTest.java @@ -29,7 +29,7 @@ * @library /test/jdk/java/net/httpclient/lib * @build jdk.httpclient.test.lib.http2.Http2TestServer * @run junit/othervm/timeout=50 -Djdk.httpclient.HttpClient.log=all - * PostPutTest + * ${test.main.class} */ import jdk.httpclient.test.lib.http2.Http2Handler; @@ -168,4 +168,4 @@ public class PostPutTest { exchange.sendResponseHeaders(200, 0); } } -} \ No newline at end of file +} diff --git a/test/jdk/java/net/httpclient/http2/ProxyTest2.java b/test/jdk/java/net/httpclient/http2/ProxyTest2.java index 762a70b95fd..75b48cb251b 100644 --- a/test/jdk/java/net/httpclient/http2/ProxyTest2.java +++ b/test/jdk/java/net/httpclient/http2/ProxyTest2.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ import java.util.concurrent.*; * tunnelling through an HTTP/1.1 proxy. * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.test.lib.net.SimpleSSLContext jdk.httpclient.test.lib.http2.Http2TestServer - * @run main/othervm ProxyTest2 + * @run main/othervm ${test.main.class} * @author danielfuchs */ public class ProxyTest2 { diff --git a/test/jdk/java/net/httpclient/http2/PushPromiseContinuation.java b/test/jdk/java/net/httpclient/http2/PushPromiseContinuation.java index 2d5b5dd4f4e..5d0bfe844f4 100644 --- a/test/jdk/java/net/httpclient/http2/PushPromiseContinuation.java +++ b/test/jdk/java/net/httpclient/http2/PushPromiseContinuation.java @@ -31,7 +31,7 @@ * @build jdk.test.lib.net.SimpleSSLContext jdk.httpclient.test.lib.http2.Http2TestServer * jdk.httpclient.test.lib.http2.BodyOutputStream * jdk.httpclient.test.lib.http2.OutgoingPushPromise - * @run junit/othervm PushPromiseContinuation + * @run junit/othervm ${test.main.class} */ import javax.net.ssl.SSLSession; diff --git a/test/jdk/java/net/httpclient/http2/RedirectTest.java b/test/jdk/java/net/httpclient/http2/RedirectTest.java index 201b56513f6..b5b1ca2f1d5 100644 --- a/test/jdk/java/net/httpclient/http2/RedirectTest.java +++ b/test/jdk/java/net/httpclient/http2/RedirectTest.java @@ -33,7 +33,7 @@ * @run junit/othervm * -Djdk.httpclient.HttpClient.log=frames,ssl,requests,responses,errors * -Djdk.internal.httpclient.debug=true - * RedirectTest + * ${test.main.class} */ import java.net.InetSocketAddress; diff --git a/test/jdk/java/net/httpclient/http2/ServerPush.java b/test/jdk/java/net/httpclient/http2/ServerPush.java index d38b867132b..41200bf8949 100644 --- a/test/jdk/java/net/httpclient/http2/ServerPush.java +++ b/test/jdk/java/net/httpclient/http2/ServerPush.java @@ -31,7 +31,7 @@ * jdk.test.lib.Utils * @run junit/othervm * -Djdk.httpclient.HttpClient.log=errors,requests,responses - * ServerPush + * ${test.main.class} */ import java.io.*; diff --git a/test/jdk/java/net/httpclient/http2/ServerPushWithDiffTypes.java b/test/jdk/java/net/httpclient/http2/ServerPushWithDiffTypes.java index 9cf2a3f7ae2..c77e258f3c5 100644 --- a/test/jdk/java/net/httpclient/http2/ServerPushWithDiffTypes.java +++ b/test/jdk/java/net/httpclient/http2/ServerPushWithDiffTypes.java @@ -28,7 +28,7 @@ * @run junit/othervm * -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.HttpClient.log=errors,requests,responses - * ServerPushWithDiffTypes + * ${test.main.class} */ import java.io.*; diff --git a/test/jdk/java/net/httpclient/http2/SimpleGet.java b/test/jdk/java/net/httpclient/http2/SimpleGet.java index 5df3174f820..1bc7e0974c7 100644 --- a/test/jdk/java/net/httpclient/http2/SimpleGet.java +++ b/test/jdk/java/net/httpclient/http2/SimpleGet.java @@ -27,17 +27,17 @@ * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.test.lib.net.SimpleSSLContext jdk.httpclient.test.lib.common.TestUtil * jdk.httpclient.test.lib.http2.Http2TestServer - * @run junit/othervm -XX:+CrashOnOutOfMemoryError SimpleGet + * @run junit/othervm -XX:+CrashOnOutOfMemoryError ${test.main.class} * @run junit/othervm -XX:+CrashOnOutOfMemoryError * -Dsimpleget.repeat=1 -Dsimpleget.chunks=1 -Dsimpleget.requests=1000 - * SimpleGet + * ${test.main.class} * @run junit/othervm -Dsimpleget.requests=150 * -Dsimpleget.chunks=16384 * -Djdk.httpclient.redirects.retrylimit=5 * -Djdk.httpclient.HttpClient.log=errors * -XX:+CrashOnOutOfMemoryError * -XX:+HeapDumpOnOutOfMemoryError - * SimpleGet + * ${test.main.class} */ import java.io.IOException; diff --git a/test/jdk/java/net/httpclient/http2/TLSConnection.java b/test/jdk/java/net/httpclient/http2/TLSConnection.java index e4009219bca..698a8c59ebe 100644 --- a/test/jdk/java/net/httpclient/http2/TLSConnection.java +++ b/test/jdk/java/net/httpclient/http2/TLSConnection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,7 +48,7 @@ import jdk.httpclient.test.lib.http2.Http2Handler; * @run main/othervm * -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.HttpClient.log=all - * TLSConnection + * ${test.main.class} */ public class TLSConnection { diff --git a/test/jdk/java/net/httpclient/http2/Timeout.java b/test/jdk/java/net/httpclient/http2/Timeout.java index 42a51f56fab..c2f0dfdd5a1 100644 --- a/test/jdk/java/net/httpclient/http2/Timeout.java +++ b/test/jdk/java/net/httpclient/http2/Timeout.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,7 +43,7 @@ import javax.net.ssl.SSLSocket; * @test * @bug 8156710 * @summary Check if HttpTimeoutException is thrown if a server doesn't reply - * @run main/othervm Timeout + * @run main/othervm ${test.main.class} */ public class Timeout { diff --git a/test/jdk/java/net/httpclient/http2/TrailingHeadersTest.java b/test/jdk/java/net/httpclient/http2/TrailingHeadersTest.java index 9ea331d2d84..bff009131a8 100644 --- a/test/jdk/java/net/httpclient/http2/TrailingHeadersTest.java +++ b/test/jdk/java/net/httpclient/http2/TrailingHeadersTest.java @@ -28,7 +28,7 @@ * @bug 8296410 * @library /test/jdk/java/net/httpclient/lib * @build jdk.httpclient.test.lib.http2.Http2TestServer - * @run junit/othervm -Djdk.httpclient.HttpClient.log=all TrailingHeadersTest + * @run junit/othervm -Djdk.httpclient.HttpClient.log=all ${test.main.class} */ import jdk.httpclient.test.lib.http2.OutgoingPushPromise; @@ -321,4 +321,4 @@ public class TrailingHeadersTest { testLog.println("PushPromiseTrailersHandler: Push Promise complete"); } } -} \ No newline at end of file +} diff --git a/test/jdk/java/net/httpclient/http2/UserInfoTest.java b/test/jdk/java/net/httpclient/http2/UserInfoTest.java index 3cea2d92570..53d9dbe3c2b 100644 --- a/test/jdk/java/net/httpclient/http2/UserInfoTest.java +++ b/test/jdk/java/net/httpclient/http2/UserInfoTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,7 +51,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; * jdk.test.lib.net.SimpleSSLContext * jdk.httpclient.test.lib.http2.Http2TestExchange * @compile ../ReferenceTracker.java - * @run junit UserInfoTest + * @run junit ${test.main.class} */ @TestInstance(TestInstance.Lifecycle.PER_CLASS) diff --git a/test/jdk/java/net/httpclient/http3/BadCipherSuiteErrorTest.java b/test/jdk/java/net/httpclient/http3/BadCipherSuiteErrorTest.java index fdfc498b21e..2c38a4a47f4 100644 --- a/test/jdk/java/net/httpclient/http3/BadCipherSuiteErrorTest.java +++ b/test/jdk/java/net/httpclient/http3/BadCipherSuiteErrorTest.java @@ -26,7 +26,7 @@ * @bug 8157105 * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.test.lib.net.SimpleSSLContext jdk.httpclient.test.lib.common.HttpServerAdapters - * @run junit/othervm/timeout=60 -Djavax.net.debug=ssl -Djdk.httpclient.HttpClient.log=all BadCipherSuiteErrorTest + * @run junit/othervm/timeout=60 -Djavax.net.debug=ssl -Djdk.httpclient.HttpClient.log=all ${test.main.class} * @summary check exception thrown when bad TLS parameters selected */ diff --git a/test/jdk/java/net/httpclient/http3/FramesDecoderTest.java b/test/jdk/java/net/httpclient/http3/FramesDecoderTest.java index d406ee491cb..584acb9ef49 100644 --- a/test/jdk/java/net/httpclient/http3/FramesDecoderTest.java +++ b/test/jdk/java/net/httpclient/http3/FramesDecoderTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,7 +42,7 @@ import static org.junit.jupiter.api.Assertions.*; * @modules java.net.http/jdk.internal.net.http.http3 * @modules java.net.http/jdk.internal.net.http.http3.frames * @modules java.net.http/jdk.internal.net.http.quic.streams - * @run junit/othervm FramesDecoderTest + * @run junit/othervm ${test.main.class} * @summary Tests to check HTTP3 methods decode frames correctly */ @TestInstance(TestInstance.Lifecycle.PER_CLASS) diff --git a/test/jdk/java/net/httpclient/http3/GetHTTP3Test.java b/test/jdk/java/net/httpclient/http3/GetHTTP3Test.java index 800a02eb2c4..fd0bdb3c294 100644 --- a/test/jdk/java/net/httpclient/http3/GetHTTP3Test.java +++ b/test/jdk/java/net/httpclient/http3/GetHTTP3Test.java @@ -79,7 +79,7 @@ import org.junit.jupiter.params.provider.MethodSource; * @compile ../ReferenceTracker.java * @run junit/othervm -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.HttpClient.log=requests,responses,errors - * GetHTTP3Test + * ${test.main.class} * @summary Basic HTTP/3 GET test */ // -Djdk.httpclient.http3.maxDirectConnectionTimeout=2500 diff --git a/test/jdk/java/net/httpclient/http3/H3BadHeadersTest.java b/test/jdk/java/net/httpclient/http3/H3BadHeadersTest.java index fff11f4ceb4..adc4c4c7240 100644 --- a/test/jdk/java/net/httpclient/http3/H3BadHeadersTest.java +++ b/test/jdk/java/net/httpclient/http3/H3BadHeadersTest.java @@ -27,7 +27,7 @@ * @build jdk.httpclient.test.lib.common.HttpServerAdapters * jdk.test.lib.net.SimpleSSLContext * @compile ../ReferenceTracker.java - * @run junit/othervm -Djdk.internal.httpclient.debug=true H3BadHeadersTest + * @run junit/othervm -Djdk.internal.httpclient.debug=true ${test.main.class} * @summary this test verifies the behaviour of the HttpClient when presented * with bad headers */ diff --git a/test/jdk/java/net/httpclient/http3/H3BasicTest.java b/test/jdk/java/net/httpclient/http3/H3BasicTest.java index bddb9879ae9..982aa88b3bc 100644 --- a/test/jdk/java/net/httpclient/http3/H3BasicTest.java +++ b/test/jdk/java/net/httpclient/http3/H3BasicTest.java @@ -33,7 +33,7 @@ * jdk.test.lib.net.SimpleSSLContext * @run junit/othervm -Djdk.httpclient.HttpClient.log=ssl,requests,responses,errors * -Djdk.internal.httpclient.debug=true - * H3BasicTest + * ${test.main.class} */ // -Dseed=-163464189156654174 diff --git a/test/jdk/java/net/httpclient/http3/H3ConcurrentPush.java b/test/jdk/java/net/httpclient/http3/H3ConcurrentPush.java index 4392f829258..e15a6bbfc4d 100644 --- a/test/jdk/java/net/httpclient/http3/H3ConcurrentPush.java +++ b/test/jdk/java/net/httpclient/http3/H3ConcurrentPush.java @@ -29,7 +29,7 @@ * -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.HttpClient.log=errors,requests,responses,trace * -Djdk.httpclient.http3.maxConcurrentPushStreams=45 - * H3ConcurrentPush + * ${test.main.class} * @summary This test exercises some of the HTTP/3 specifities for PushPromises. * It sends several concurrent requests, and the server sends a bunch of * identical push promise frames to all of them. That is, there will be diff --git a/test/jdk/java/net/httpclient/http3/H3ConnectionPoolTest.java b/test/jdk/java/net/httpclient/http3/H3ConnectionPoolTest.java index 12956604484..21ab06f8a5c 100644 --- a/test/jdk/java/net/httpclient/http3/H3ConnectionPoolTest.java +++ b/test/jdk/java/net/httpclient/http3/H3ConnectionPoolTest.java @@ -32,7 +32,7 @@ * -Djdk.httpclient.keepalive.timeout.h3=480 * -Djdk.httpclient.quic.idleTimeout=480 * -Djdk.test.server.quic.idleTimeout=480 - * H3ConnectionPoolTest + * ${test.main.class} */ import java.io.IOException; diff --git a/test/jdk/java/net/httpclient/http3/H3DataLimitsTest.java b/test/jdk/java/net/httpclient/http3/H3DataLimitsTest.java index 8a83b51a174..51c30ccfe95 100644 --- a/test/jdk/java/net/httpclient/http3/H3DataLimitsTest.java +++ b/test/jdk/java/net/httpclient/http3/H3DataLimitsTest.java @@ -70,7 +70,7 @@ import org.junit.jupiter.params.provider.MethodSource; * @run junit/othervm/timeout=480 -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.HttpClient.log=requests,responses,errors * -Djavax.net.debug=all - * H3DataLimitsTest + * ${test.main.class} * @summary Verify handling of MAX_DATA / MAX_STREAM_DATA frames */ public class H3DataLimitsTest implements HttpServerAdapters { diff --git a/test/jdk/java/net/httpclient/http3/H3ErrorHandlingTest.java b/test/jdk/java/net/httpclient/http3/H3ErrorHandlingTest.java index 8e20eac95fa..07e086f0676 100644 --- a/test/jdk/java/net/httpclient/http3/H3ErrorHandlingTest.java +++ b/test/jdk/java/net/httpclient/http3/H3ErrorHandlingTest.java @@ -84,7 +84,7 @@ import static org.junit.jupiter.api.Assertions.*; * @build java.net.http/jdk.internal.net.http.Http3ConnectionAccess * @run junit/othervm * -Djdk.internal.httpclient.debug=true - * -Djdk.httpclient.HttpClient.log=requests,responses,errors H3ErrorHandlingTest + * -Djdk.httpclient.HttpClient.log=requests,responses,errors ${test.main.class} */ public class H3ErrorHandlingTest implements HttpServerAdapters { diff --git a/test/jdk/java/net/httpclient/http3/H3GoAwayTest.java b/test/jdk/java/net/httpclient/http3/H3GoAwayTest.java index b9d50ce2939..03d1f8b4ea4 100644 --- a/test/jdk/java/net/httpclient/http3/H3GoAwayTest.java +++ b/test/jdk/java/net/httpclient/http3/H3GoAwayTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -62,7 +62,7 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; * @build jdk.test.lib.net.SimpleSSLContext * @run junit/othervm * -Djdk.httpclient.HttpClient.log=errors,headers,quic:hs,http3 - * H3GoAwayTest + * ${test.main.class} */ public class H3GoAwayTest { diff --git a/test/jdk/java/net/httpclient/http3/H3HeaderSizeLimitTest.java b/test/jdk/java/net/httpclient/http3/H3HeaderSizeLimitTest.java index d5864989436..d4cf941b007 100644 --- a/test/jdk/java/net/httpclient/http3/H3HeaderSizeLimitTest.java +++ b/test/jdk/java/net/httpclient/http3/H3HeaderSizeLimitTest.java @@ -58,7 +58,7 @@ import org.junit.jupiter.api.Test; * @build java.net.http/jdk.internal.net.http.Http3ConnectionAccess * @run junit/othervm * -Djdk.internal.httpclient.debug=true - * -Djdk.httpclient.HttpClient.log=requests,responses,errors H3HeaderSizeLimitTest + * -Djdk.httpclient.HttpClient.log=requests,responses,errors ${test.main.class} */ public class H3HeaderSizeLimitTest implements HttpServerAdapters { diff --git a/test/jdk/java/net/httpclient/http3/H3HeadersEncoding.java b/test/jdk/java/net/httpclient/http3/H3HeadersEncoding.java index 6b7b24f049d..142856596e6 100644 --- a/test/jdk/java/net/httpclient/http3/H3HeadersEncoding.java +++ b/test/jdk/java/net/httpclient/http3/H3HeadersEncoding.java @@ -33,7 +33,7 @@ * -Dhttp3.test.server.decoderMaxTableCapacity=4096 * -Dhttp3.test.server.encoderTableCapacityLimit=4096 * -Djdk.internal.httpclient.qpack.log.level=NORMAL - * H3HeadersEncoding + * ${test.main.class} * @summary this test verifies that when QPACK dynamic table is enabled multiple * random headers can be encoded/decoded correctly */ diff --git a/test/jdk/java/net/httpclient/http3/H3ImplicitPushCancel.java b/test/jdk/java/net/httpclient/http3/H3ImplicitPushCancel.java index 570f84ad620..d9746d496f3 100644 --- a/test/jdk/java/net/httpclient/http3/H3ImplicitPushCancel.java +++ b/test/jdk/java/net/httpclient/http3/H3ImplicitPushCancel.java @@ -28,7 +28,7 @@ * @run junit/othervm * -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.HttpClient.log=errors,requests,responses,trace - * H3ImplicitPushCancel + * ${test.main.class} * @summary This is a clone of http2/ImplicitPushCancel but for HTTP/3 */ diff --git a/test/jdk/java/net/httpclient/http3/H3InsertionsLimitTest.java b/test/jdk/java/net/httpclient/http3/H3InsertionsLimitTest.java index 6eabc23677a..35e5e56bc16 100644 --- a/test/jdk/java/net/httpclient/http3/H3InsertionsLimitTest.java +++ b/test/jdk/java/net/httpclient/http3/H3InsertionsLimitTest.java @@ -67,7 +67,7 @@ import org.junit.jupiter.api.Test; * -Dhttp3.test.server.encoderTableCapacityLimit=4096 * -Djdk.httpclient.maxLiteralWithIndexing=32 * -Djdk.internal.httpclient.qpack.log.level=EXTRA - * H3InsertionsLimitTest + * ${test.main.class} */ public class H3InsertionsLimitTest implements HttpServerAdapters { diff --git a/test/jdk/java/net/httpclient/http3/H3LogHandshakeErrors.java b/test/jdk/java/net/httpclient/http3/H3LogHandshakeErrors.java index 85a4b6113f0..a69028ca701 100644 --- a/test/jdk/java/net/httpclient/http3/H3LogHandshakeErrors.java +++ b/test/jdk/java/net/httpclient/http3/H3LogHandshakeErrors.java @@ -63,7 +63,7 @@ import org.junit.jupiter.api.Test; * jdk.httpclient.test.lib.common.HttpServerAdapters * @run junit/othervm * -Djdk.httpclient.HttpClient.log=errors - * H3LogHandshakeErrors + * ${test.main.class} */ // -Djava.security.debug=all public class H3LogHandshakeErrors implements HttpServerAdapters { diff --git a/test/jdk/java/net/httpclient/http3/H3MaxInitialTimeoutTest.java b/test/jdk/java/net/httpclient/http3/H3MaxInitialTimeoutTest.java index a93c6a37594..33d8c1db994 100644 --- a/test/jdk/java/net/httpclient/http3/H3MaxInitialTimeoutTest.java +++ b/test/jdk/java/net/httpclient/http3/H3MaxInitialTimeoutTest.java @@ -75,15 +75,15 @@ import org.junit.jupiter.params.provider.MethodSource; * @run junit/othervm -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.HttpClient.log=requests,responses,errors,quic:controls * -Djdk.httpclient.quic.maxInitialTimeout=1 - * H3MaxInitialTimeoutTest + * ${test.main.class} * @run junit/othervm -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.HttpClient.log=requests,responses,errors,quic:controls * -Djdk.httpclient.quic.maxInitialTimeout=2 - * H3MaxInitialTimeoutTest + * ${test.main.class} * @run junit/othervm -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.HttpClient.log=requests,responses,errors,quic:controls * -Djdk.httpclient.quic.maxInitialTimeout=2147483647 - * H3MaxInitialTimeoutTest + * ${test.main.class} */ public class H3MaxInitialTimeoutTest implements HttpServerAdapters { diff --git a/test/jdk/java/net/httpclient/http3/H3MemoryHandlingTest.java b/test/jdk/java/net/httpclient/http3/H3MemoryHandlingTest.java index 0d107486fcd..548bd546dab 100644 --- a/test/jdk/java/net/httpclient/http3/H3MemoryHandlingTest.java +++ b/test/jdk/java/net/httpclient/http3/H3MemoryHandlingTest.java @@ -67,7 +67,7 @@ import org.junit.jupiter.api.Test; * -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.HttpClient.log=requests,responses,errors * -Djdk.httpclient.quic.maxStreamInitialData=16384 - * -Djdk.httpclient.quic.streamBufferSize=2048 H3MemoryHandlingTest + * -Djdk.httpclient.quic.streamBufferSize=2048 ${test.main.class} */ public class H3MemoryHandlingTest implements HttpServerAdapters { diff --git a/test/jdk/java/net/httpclient/http3/H3MultipleConnectionsToSameHost.java b/test/jdk/java/net/httpclient/http3/H3MultipleConnectionsToSameHost.java index f9ba35359bc..c38671e65b8 100644 --- a/test/jdk/java/net/httpclient/http3/H3MultipleConnectionsToSameHost.java +++ b/test/jdk/java/net/httpclient/http3/H3MultipleConnectionsToSameHost.java @@ -44,7 +44,7 @@ * -Djdk.httpclient.retryOnStreamlimit=50 * -Djdk.httpclient.HttpClient.log=errors,http3,quic:retransmit * -Dsimpleget.requests=100 - * H3MultipleConnectionsToSameHost + * ${test.main.class} * @summary test multiple connections and concurrent requests with blocking IO and virtual threads */ /* @@ -71,7 +71,7 @@ * -Djdk.httpclient.retryOnStreamlimit=50 * -Djdk.httpclient.HttpClient.log=errors,http3,quic:retransmit * -Dsimpleget.requests=100 - * H3MultipleConnectionsToSameHost + * ${test.main.class} * @summary test multiple connections and concurrent requests with blocking IO and virtual threads * on windows 10 and windows 2016 - but with -XX:-VMContinuations */ @@ -95,7 +95,7 @@ * -Djdk.httpclient.retryOnStreamlimit=50 * -Djdk.httpclient.HttpClient.log=errors,http3,quic:hs:retransmit * -Dsimpleget.requests=100 - * H3MultipleConnectionsToSameHost + * ${test.main.class} * @summary Send 100 large concurrent requests, with connections whose max stream * limit is artificially low, in order to cause concurrent connections * to the same host to be created, with non-blocking IO and selector @@ -120,7 +120,7 @@ * -Djdk.httpclient.HttpClient.log=errors,http3,quic:hs:retransmit * -Dsimpleget.requests=100 * -Djdk.internal.httpclient.quic.congestionController=reno - * H3MultipleConnectionsToSameHost + * ${test.main.class} * @summary Send 100 large concurrent requests, with connections whose max stream * limit is artificially low, in order to cause concurrent connections * to the same host to be created, with Reno congestion controller diff --git a/test/jdk/java/net/httpclient/http3/H3ProxyTest.java b/test/jdk/java/net/httpclient/http3/H3ProxyTest.java index 58deeec1982..fbb4e07fd60 100644 --- a/test/jdk/java/net/httpclient/http3/H3ProxyTest.java +++ b/test/jdk/java/net/httpclient/http3/H3ProxyTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -59,7 +59,7 @@ import static java.net.http.HttpOption.H3_DISCOVERY; * if HTTP3_ONLY is specified * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.test.lib.net.SimpleSSLContext jdk.httpclient.test.lib.common.HttpServerAdapters - * @run main/othervm H3ProxyTest + * @run main/othervm ${test.main.class} * @author danielfuchs */ public class H3ProxyTest implements HttpServerAdapters { diff --git a/test/jdk/java/net/httpclient/http3/H3PushCancel.java b/test/jdk/java/net/httpclient/http3/H3PushCancel.java index b9e15b7d8e5..969297a50ba 100644 --- a/test/jdk/java/net/httpclient/http3/H3PushCancel.java +++ b/test/jdk/java/net/httpclient/http3/H3PushCancel.java @@ -29,7 +29,7 @@ * -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.HttpClient.log=errors,requests,responses,trace * -Djdk.httpclient.http3.maxConcurrentPushStreams=5 - * H3PushCancel + * ${test.main.class} * @summary This test checks that not accepting one of the push promise * will cancel it. It also verifies that receiving a pushId bigger * than the max push ID allowed on the connection will cause diff --git a/test/jdk/java/net/httpclient/http3/H3QuicTLSConnection.java b/test/jdk/java/net/httpclient/http3/H3QuicTLSConnection.java index 6086c26729b..b66744d9f0d 100644 --- a/test/jdk/java/net/httpclient/http3/H3QuicTLSConnection.java +++ b/test/jdk/java/net/httpclient/http3/H3QuicTLSConnection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -61,7 +61,7 @@ import static java.net.http.HttpOption.Http3DiscoveryMode.HTTP_3_URI_ONLY; * @run main/othervm * -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.HttpClient.log=all - * H3QuicTLSConnection + * ${test.main.class} */ public class H3QuicTLSConnection { diff --git a/test/jdk/java/net/httpclient/http3/H3QuicVTTest.java b/test/jdk/java/net/httpclient/http3/H3QuicVTTest.java index 7ea24d81ded..b982528b5e3 100644 --- a/test/jdk/java/net/httpclient/http3/H3QuicVTTest.java +++ b/test/jdk/java/net/httpclient/http3/H3QuicVTTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -57,7 +57,7 @@ import static java.net.http.HttpOption.Http3DiscoveryMode.HTTP_3_URI_ONLY; * jdk.httpclient.test.lib.common.HttpServerAdapters * @run junit/othervm * -Djdk.httpclient.HttpClient.log=requests,responses,headers,errors,http3 - * H3QuicVTTest + * ${test.main.class} */ /* * @test id=never @@ -70,7 +70,7 @@ import static java.net.http.HttpOption.Http3DiscoveryMode.HTTP_3_URI_ONLY; * @run junit/othervm * -Djdk.internal.httpclient.quic.selector.useVirtualThreads=never * -Djdk.httpclient.HttpClient.log=requests,responses,headers,errors,http3 - * H3QuicVTTest + * ${test.main.class} */ /* * @test id=always @@ -83,7 +83,7 @@ import static java.net.http.HttpOption.Http3DiscoveryMode.HTTP_3_URI_ONLY; * @run junit/othervm * -Djdk.internal.httpclient.quic.selector.useVirtualThreads=always * -Djdk.httpclient.HttpClient.log=requests,responses,headers,errors,http3 - * H3QuicVTTest + * ${test.main.class} */ /* * @test id=explicit-default @@ -96,7 +96,7 @@ import static java.net.http.HttpOption.Http3DiscoveryMode.HTTP_3_URI_ONLY; * @run junit/othervm * -Djdk.internal.httpclient.quic.selector.useVirtualThreads=default * -Djdk.httpclient.HttpClient.log=requests,responses,headers,errors,http3 - * H3QuicVTTest + * ${test.main.class} */ /* * @test id=garbage @@ -109,7 +109,7 @@ import static java.net.http.HttpOption.Http3DiscoveryMode.HTTP_3_URI_ONLY; * @run junit/othervm * -Djdk.internal.httpclient.quic.selector.useVirtualThreads=garbage * -Djdk.httpclient.HttpClient.log=requests,responses,headers,errors,http3 - * H3QuicVTTest + * ${test.main.class} */ // -Djava.security.debug=all class H3QuicVTTest implements HttpServerAdapters { diff --git a/test/jdk/java/net/httpclient/http3/H3RedirectTest.java b/test/jdk/java/net/httpclient/http3/H3RedirectTest.java index 67a7d99fa71..4f6c80dc3a2 100644 --- a/test/jdk/java/net/httpclient/http3/H3RedirectTest.java +++ b/test/jdk/java/net/httpclient/http3/H3RedirectTest.java @@ -31,7 +31,7 @@ * @run junit/othervm * -Djdk.httpclient.HttpClient.log=frames,ssl,requests,responses,errors * -Djdk.internal.httpclient.debug=true - * H3RedirectTest + * ${test.main.class} */ import java.net.InetSocketAddress; diff --git a/test/jdk/java/net/httpclient/http3/H3ServerPush.java b/test/jdk/java/net/httpclient/http3/H3ServerPush.java index 50aa817b155..c53828b189d 100644 --- a/test/jdk/java/net/httpclient/http3/H3ServerPush.java +++ b/test/jdk/java/net/httpclient/http3/H3ServerPush.java @@ -32,7 +32,7 @@ * @run junit/othervm/timeout=960 * -Djdk.httpclient.HttpClient.log=errors,requests,headers * -Djdk.internal.httpclient.debug=false - * H3ServerPush + * ${test.main.class} * @summary This is a clone of http2/ServerPush but for HTTP/3 */ diff --git a/test/jdk/java/net/httpclient/http3/H3ServerPushCancel.java b/test/jdk/java/net/httpclient/http3/H3ServerPushCancel.java index b34e2a1567e..955023599d3 100644 --- a/test/jdk/java/net/httpclient/http3/H3ServerPushCancel.java +++ b/test/jdk/java/net/httpclient/http3/H3ServerPushCancel.java @@ -29,7 +29,7 @@ * -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.HttpClient.log=errors,requests,responses,trace * -Djdk.httpclient.http3.maxConcurrentPushStreams=45 - * H3ServerPushCancel + * ${test.main.class} * @summary This test checks that the client deals correctly with a * CANCEL_PUSH frame sent by the server */ diff --git a/test/jdk/java/net/httpclient/http3/H3ServerPushTest.java b/test/jdk/java/net/httpclient/http3/H3ServerPushTest.java index 00fe651c9cf..018e7c2f11d 100644 --- a/test/jdk/java/net/httpclient/http3/H3ServerPushTest.java +++ b/test/jdk/java/net/httpclient/http3/H3ServerPushTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -78,7 +78,7 @@ import static org.junit.jupiter.api.Assertions.fail; * /test/lib * @build jdk.httpclient.test.lib.http2.Http2TestServer * jdk.test.lib.net.SimpleSSLContext - * @run junit/othervm/timeout=240 H3ServerPushTest + * @run junit/othervm/timeout=240 ${test.main.class} */ /** diff --git a/test/jdk/java/net/httpclient/http3/H3ServerPushWithDiffTypes.java b/test/jdk/java/net/httpclient/http3/H3ServerPushWithDiffTypes.java index a863db43c29..ecc3c828abf 100644 --- a/test/jdk/java/net/httpclient/http3/H3ServerPushWithDiffTypes.java +++ b/test/jdk/java/net/httpclient/http3/H3ServerPushWithDiffTypes.java @@ -28,7 +28,7 @@ * @run junit/othervm * -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.HttpClient.log=errors,requests,responses - * H3ServerPushWithDiffTypes + * ${test.main.class} * @summary This is a clone of http2/ServerPushWithDiffTypes but for HTTP/3 */ diff --git a/test/jdk/java/net/httpclient/http3/H3SimpleGet.java b/test/jdk/java/net/httpclient/http3/H3SimpleGet.java index ae113322cd3..4d58f7094b1 100644 --- a/test/jdk/java/net/httpclient/http3/H3SimpleGet.java +++ b/test/jdk/java/net/httpclient/http3/H3SimpleGet.java @@ -31,19 +31,19 @@ * @build jdk.test.lib.net.SimpleSSLContext jdk.httpclient.test.lib.common.TestUtil * jdk.httpclient.test.lib.http2.Http2TestServer * @run junit/othervm/timeout=480 -XX:+HeapDumpOnOutOfMemoryError -XX:+CrashOnOutOfMemoryError - * H3SimpleGet + * ${test.main.class} * @run junit/othervm/timeout=480 -XX:+HeapDumpOnOutOfMemoryError -XX:+CrashOnOutOfMemoryError * -Djdk.httpclient.retryOnStreamlimit=20 * -Djdk.httpclient.redirects.retrylimit=21 * -Dsimpleget.repeat=1 -Dsimpleget.chunks=1 -Dsimpleget.requests=1000 - * H3SimpleGet + * ${test.main.class} * @run junit/othervm/timeout=480 -XX:+HeapDumpOnOutOfMemoryError -XX:+CrashOnOutOfMemoryError * -Dsimpleget.requests=150 * -Dsimpleget.chunks=16384 * -Djdk.httpclient.retryOnStreamlimit=5 * -Djdk.httpclient.redirects.retrylimit=6 * -Djdk.httpclient.quic.defaultMTU=16336 - * H3SimpleGet + * ${test.main.class} */ /* @@ -54,19 +54,19 @@ * @build jdk.test.lib.net.SimpleSSLContext jdk.httpclient.test.lib.common.TestUtil * jdk.httpclient.test.lib.http2.Http2TestServer * @run junit/othervm/timeout=480 -XX:+HeapDumpOnOutOfMemoryError -XX:+CrashOnOutOfMemoryError - * H3SimpleGet + * ${test.main.class} * @run junit/othervm/timeout=480 -XX:+HeapDumpOnOutOfMemoryError -XX:+CrashOnOutOfMemoryError * -Djdk.httpclient.retryOnStreamlimit=20 * -Djdk.httpclient.redirects.retrylimit=21 * -Dsimpleget.repeat=1 -Dsimpleget.chunks=1 -Dsimpleget.requests=1000 - * H3SimpleGet + * ${test.main.class} * @run junit/othervm/timeout=480 -XX:+HeapDumpOnOutOfMemoryError -XX:+CrashOnOutOfMemoryError * -Dsimpleget.requests=150 * -Dsimpleget.chunks=16384 * -Djdk.httpclient.retryOnStreamlimit=5 * -Djdk.httpclient.redirects.retrylimit=6 * -Djdk.httpclient.quic.defaultMTU=8192 - * H3SimpleGet + * ${test.main.class} */ /* @@ -79,13 +79,13 @@ * jdk.httpclient.test.lib.http2.Http2TestServer * @run junit/othervm/timeout=480 -XX:+HeapDumpOnOutOfMemoryError -XX:+CrashOnOutOfMemoryError * -XX:+UnlockExperimentalVMOptions -XX:-VMContinuations - * H3SimpleGet + * ${test.main.class} * @run junit/othervm/timeout=480 -XX:+HeapDumpOnOutOfMemoryError -XX:+CrashOnOutOfMemoryError * -XX:+UnlockExperimentalVMOptions -XX:-VMContinuations * -Djdk.httpclient.retryOnStreamlimit=20 * -Djdk.httpclient.redirects.retrylimit=21 * -Dsimpleget.repeat=1 -Dsimpleget.chunks=1 -Dsimpleget.requests=1000 - * H3SimpleGet + * ${test.main.class} * @run junit/othervm/timeout=480 -XX:+HeapDumpOnOutOfMemoryError -XX:+CrashOnOutOfMemoryError * -XX:+UnlockExperimentalVMOptions -XX:-VMContinuations * -Dsimpleget.requests=150 @@ -93,7 +93,7 @@ * -Djdk.httpclient.retryOnStreamlimit=5 * -Djdk.httpclient.redirects.retrylimit=6 * -Djdk.httpclient.quic.defaultMTU=16336 - * H3SimpleGet + * ${test.main.class} */ /* @@ -105,13 +105,13 @@ * jdk.httpclient.test.lib.http2.Http2TestServer * @run junit/othervm/timeout=480 -XX:+HeapDumpOnOutOfMemoryError -XX:+CrashOnOutOfMemoryError * -Djdk.internal.httpclient.quic.useNioSelector=true - * H3SimpleGet + * ${test.main.class} * @run junit/othervm/timeout=480 -XX:+HeapDumpOnOutOfMemoryError -XX:+CrashOnOutOfMemoryError * -Djdk.internal.httpclient.quic.useNioSelector=true * -Djdk.httpclient.retryOnStreamlimit=20 * -Djdk.httpclient.redirects.retrylimit=21 * -Dsimpleget.repeat=1 -Dsimpleget.chunks=1 -Dsimpleget.requests=1000 - * H3SimpleGet + * ${test.main.class} * @run junit/othervm/timeout=480 -XX:+HeapDumpOnOutOfMemoryError -XX:+CrashOnOutOfMemoryError * -Djdk.internal.httpclient.quic.useNioSelector=true * -Dsimpleget.requests=150 @@ -119,7 +119,7 @@ * -Djdk.httpclient.retryOnStreamlimit=5 * -Djdk.httpclient.redirects.retrylimit=6 * -Djdk.httpclient.quic.defaultMTU=16336 - * H3SimpleGet + * ${test.main.class} */ /* @@ -131,13 +131,13 @@ * jdk.httpclient.test.lib.http2.Http2TestServer * @run junit/othervm/timeout=480 -XX:+HeapDumpOnOutOfMemoryError -XX:+CrashOnOutOfMemoryError * -Djdk.internal.httpclient.quic.useNioSelector=true - * H3SimpleGet + * ${test.main.class} * @run junit/othervm/timeout=480 -XX:+HeapDumpOnOutOfMemoryError -XX:+CrashOnOutOfMemoryError * -Djdk.internal.httpclient.quic.useNioSelector=true * -Djdk.httpclient.retryOnStreamlimit=20 * -Djdk.httpclient.redirects.retrylimit=21 * -Dsimpleget.repeat=1 -Dsimpleget.chunks=1 -Dsimpleget.requests=1000 - * H3SimpleGet + * ${test.main.class} * @run junit/othervm/timeout=480 -XX:+HeapDumpOnOutOfMemoryError -XX:+CrashOnOutOfMemoryError * -Djdk.internal.httpclient.quic.useNioSelector=true * -Dsimpleget.requests=150 @@ -145,7 +145,7 @@ * -Djdk.httpclient.retryOnStreamlimit=5 * -Djdk.httpclient.redirects.retrylimit=6 * -Djdk.httpclient.quic.defaultMTU=8192 - * H3SimpleGet + * ${test.main.class} */ /* @@ -155,7 +155,7 @@ * @build jdk.test.lib.net.SimpleSSLContext jdk.httpclient.test.lib.common.TestUtil * jdk.httpclient.test.lib.http2.Http2TestServer * @run junit/othervm/timeout=480 -Djdk.internal.httpclient.quic.congestionController=reno - * H3SimpleGet + * ${test.main.class} * @summary send multiple GET requests using Reno congestion controller */ diff --git a/test/jdk/java/net/httpclient/http3/H3SimplePost.java b/test/jdk/java/net/httpclient/http3/H3SimplePost.java index 0294f2f69da..6444f2ca90c 100644 --- a/test/jdk/java/net/httpclient/http3/H3SimplePost.java +++ b/test/jdk/java/net/httpclient/http3/H3SimplePost.java @@ -27,7 +27,7 @@ * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.test.lib.net.SimpleSSLContext jdk.httpclient.test.lib.common.TestUtil * jdk.httpclient.test.lib.http2.Http2TestServer - * @run junit/othervm/timeout=480 H3SimplePost + * @run junit/othervm/timeout=480 ${test.main.class} */ // -Djdk.httpclient.HttpClient.log=requests,errors,quic // -Djdk.httpclient.quic.defaultMTU=64000 diff --git a/test/jdk/java/net/httpclient/http3/H3SimpleTest.java b/test/jdk/java/net/httpclient/http3/H3SimpleTest.java index 4258f3bac73..78a1b55fda6 100644 --- a/test/jdk/java/net/httpclient/http3/H3SimpleTest.java +++ b/test/jdk/java/net/httpclient/http3/H3SimpleTest.java @@ -54,22 +54,22 @@ import org.junit.jupiter.api.Test; * @run junit/othervm * -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.HttpClient.log=requests,responses,errors - * H3SimpleTest + * ${test.main.class} * @run junit/othervm * -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.HttpClient.log=requests,responses,errors * -Djava.net.preferIPv6Addresses=true - * H3SimpleTest + * ${test.main.class} * @run junit/othervm * -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.HttpClient.log=requests,responses,errors * -Djava.net.preferIPv4Stack=true - * H3SimpleTest + * ${test.main.class} * @run junit/othervm * -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.HttpClient.log=requests,responses,errors * -Djdk.internal.httpclient.quic.congestionController=reno - * H3SimpleTest + * ${test.main.class} */ // -Djava.security.debug=all public class H3SimpleTest implements HttpServerAdapters { diff --git a/test/jdk/java/net/httpclient/http3/H3StopSendingTest.java b/test/jdk/java/net/httpclient/http3/H3StopSendingTest.java index 86b12a1dae6..3eb88c88f9e 100644 --- a/test/jdk/java/net/httpclient/http3/H3StopSendingTest.java +++ b/test/jdk/java/net/httpclient/http3/H3StopSendingTest.java @@ -27,7 +27,7 @@ * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.httpclient.test.lib.common.HttpServerAdapters * @run junit/othervm/timeout=40 -Djdk.internal.httpclient.debug=true -Djdk.httpclient.HttpClient.log=trace,errors,headers - * H3StopSendingTest + * ${test.main.class} */ import jdk.httpclient.test.lib.common.HttpServerAdapters; diff --git a/test/jdk/java/net/httpclient/http3/H3StreamLimitReachedTest.java b/test/jdk/java/net/httpclient/http3/H3StreamLimitReachedTest.java index 1ac4a750d77..aa14087862b 100644 --- a/test/jdk/java/net/httpclient/http3/H3StreamLimitReachedTest.java +++ b/test/jdk/java/net/httpclient/http3/H3StreamLimitReachedTest.java @@ -49,7 +49,7 @@ * @run junit/othervm -Djdk.httpclient.HttpClient.log=ssl,requests,responses,errors,http3,quic:control * -Djdk.internal.httpclient.debug=false * -Djdk.internal.httpclient.quic.maxBidiStreams=1 - * H3StreamLimitReachedTest + * ${test.main.class} */ /* @@ -82,7 +82,7 @@ * -Djdk.internal.httpclient.quic.maxBidiStreams=1 * -Djdk.httpclient.http3.maxStreamLimitTimeout=0 * -Djdk.httpclient.retryOnStreamlimit=9 - * H3StreamLimitReachedTest + * ${test.main.class} */ import java.io.IOException; diff --git a/test/jdk/java/net/httpclient/http3/H3Timeout.java b/test/jdk/java/net/httpclient/http3/H3Timeout.java index fedb4d46952..befc8e5d159 100644 --- a/test/jdk/java/net/httpclient/http3/H3Timeout.java +++ b/test/jdk/java/net/httpclient/http3/H3Timeout.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -53,7 +53,7 @@ import static java.net.http.HttpOption.H3_DISCOVERY; * @build jdk.test.lib.net.SimpleSSLContext jdk.httpclient.test.lib.common.TestUtil * jdk.httpclient.test.lib.common.HttpServerAdapters * @compile ../ReferenceTracker.java - * @run main/othervm -Djdk.httpclient.HttpClient.log=ssl,requests,responses,errors H3Timeout + * @run main/othervm -Djdk.httpclient.HttpClient.log=ssl,requests,responses,errors ${test.main.class} */ public class H3Timeout implements HttpServerAdapters { diff --git a/test/jdk/java/net/httpclient/http3/H3UnsupportedSSLParametersTest.java b/test/jdk/java/net/httpclient/http3/H3UnsupportedSSLParametersTest.java index 790af245db8..2a490884927 100644 --- a/test/jdk/java/net/httpclient/http3/H3UnsupportedSSLParametersTest.java +++ b/test/jdk/java/net/httpclient/http3/H3UnsupportedSSLParametersTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,7 +38,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; * @summary Tests that a HttpClient configured with SSLParameters that doesn't include TLSv1.3 * cannot be used for HTTP3 * @library /test/lib /test/jdk/java/net/httpclient/lib - * @run junit H3UnsupportedSSLParametersTest + * @run junit ${test.main.class} */ public class H3UnsupportedSSLParametersTest { diff --git a/test/jdk/java/net/httpclient/http3/H3UserInfoTest.java b/test/jdk/java/net/httpclient/http3/H3UserInfoTest.java index 8eaad2ce4de..ad5db51f48b 100644 --- a/test/jdk/java/net/httpclient/http3/H3UserInfoTest.java +++ b/test/jdk/java/net/httpclient/http3/H3UserInfoTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -59,7 +59,7 @@ import static org.junit.jupiter.api.Assertions.fail; * @compile ../ReferenceTracker.java * @run junit/othervm -Djdk.httpclient.HttpClient.log=quic,errors * -Djdk.httpclient.http3.maxDirectConnectionTimeout=4000 - * -Djdk.internal.httpclient.debug=true H3UserInfoTest + * -Djdk.internal.httpclient.debug=true ${test.main.class} */ @TestInstance(TestInstance.Lifecycle.PER_CLASS) diff --git a/test/jdk/java/net/httpclient/http3/HTTP3NoBodyTest.java b/test/jdk/java/net/httpclient/http3/HTTP3NoBodyTest.java index b43ce8dcf79..fcd5b1eadb7 100644 --- a/test/jdk/java/net/httpclient/http3/HTTP3NoBodyTest.java +++ b/test/jdk/java/net/httpclient/http3/HTTP3NoBodyTest.java @@ -31,7 +31,7 @@ * @compile ../ReferenceTracker.java * @run junit/othervm -Djdk.httpclient.HttpClient.log=ssl,requests,responses,errors * -Djdk.internal.httpclient.debug=true - * HTTP3NoBodyTest + * ${test.main.class} * @summary this is a copy of http2/NoBodyTest over HTTP/3 */ diff --git a/test/jdk/java/net/httpclient/http3/Http3ExpectContinueTest.java b/test/jdk/java/net/httpclient/http3/Http3ExpectContinueTest.java index 1cf6900ed5d..0d34c197d1a 100644 --- a/test/jdk/java/net/httpclient/http3/Http3ExpectContinueTest.java +++ b/test/jdk/java/net/httpclient/http3/Http3ExpectContinueTest.java @@ -29,7 +29,7 @@ * @build jdk.httpclient.test.lib.common.HttpServerAdapters * @run junit/othervm -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.HttpClient.log=errors,requests,headers - * Http3ExpectContinueTest + * ${test.main.class} */ import jdk.httpclient.test.lib.common.HttpServerAdapters; diff --git a/test/jdk/java/net/httpclient/http3/PeerUniStreamDispatcherTest.java b/test/jdk/java/net/httpclient/http3/PeerUniStreamDispatcherTest.java index fc6d43bb472..7404a3cb1e9 100644 --- a/test/jdk/java/net/httpclient/http3/PeerUniStreamDispatcherTest.java +++ b/test/jdk/java/net/httpclient/http3/PeerUniStreamDispatcherTest.java @@ -25,7 +25,7 @@ * @test * @run junit/othervm * -Djdk.internal.httpclient.debug=out - * PeerUniStreamDispatcherTest + * ${test.main.class} * @summary Unit test for the PeerUniStreamDispatcher */ diff --git a/test/jdk/java/net/httpclient/http3/PostHTTP3Test.java b/test/jdk/java/net/httpclient/http3/PostHTTP3Test.java index 1f109e27ebc..c783da4a10b 100644 --- a/test/jdk/java/net/httpclient/http3/PostHTTP3Test.java +++ b/test/jdk/java/net/httpclient/http3/PostHTTP3Test.java @@ -85,7 +85,7 @@ import org.junit.jupiter.params.provider.MethodSource; * @compile ../ReferenceTracker.java * @run junit/othervm -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.HttpClient.log=requests,responses,errors - * PostHTTP3Test + * ${test.main.class} * @summary Basic HTTP/3 POST test */ // -Djdk.httpclient.http3.maxDirectConnectionTimeout=2500 diff --git a/test/jdk/java/net/httpclient/http3/StopSendingTest.java b/test/jdk/java/net/httpclient/http3/StopSendingTest.java index 8c9a6f84b65..e13568740bb 100644 --- a/test/jdk/java/net/httpclient/http3/StopSendingTest.java +++ b/test/jdk/java/net/httpclient/http3/StopSendingTest.java @@ -61,7 +61,7 @@ import org.junit.jupiter.api.Test; * jdk.httpclient.test.lib.common.HttpServerAdapters * @compile ../ReferenceTracker.java * @run junit/othervm -Djdk.internal.httpclient.debug=true - * -Djdk.httpclient.HttpClient.log=requests,responses,errors StopSendingTest + * -Djdk.httpclient.HttpClient.log=requests,responses,errors ${test.main.class} */ public class StopSendingTest implements HttpServerAdapters { diff --git a/test/jdk/java/net/httpclient/http3/StreamLimitTest.java b/test/jdk/java/net/httpclient/http3/StreamLimitTest.java index 9e15db9ceb9..6505a542e8c 100644 --- a/test/jdk/java/net/httpclient/http3/StreamLimitTest.java +++ b/test/jdk/java/net/httpclient/http3/StreamLimitTest.java @@ -65,7 +65,7 @@ import org.junit.jupiter.api.Test; * @build jdk.test.lib.net.SimpleSSLContext * jdk.httpclient.test.lib.common.HttpServerAdapters * jdk.httpclient.test.lib.http3.Http3TestServer - * @run junit/othervm -Djdk.internal.httpclient.debug=true StreamLimitTest + * @run junit/othervm -Djdk.internal.httpclient.debug=true ${test.main.class} */ public class StreamLimitTest { diff --git a/test/jdk/java/net/httpclient/offline/OfflineTesting.java b/test/jdk/java/net/httpclient/offline/OfflineTesting.java index f36a457022e..754a4233f3f 100644 --- a/test/jdk/java/net/httpclient/offline/OfflineTesting.java +++ b/test/jdk/java/net/httpclient/offline/OfflineTesting.java @@ -25,7 +25,7 @@ * @test * @summary Demonstrates how to achieve testing without network connections * @build DelegatingHttpClient FixedHttpResponse FixedResponseHttpClient - * @run junit/othervm OfflineTesting + * @run junit/othervm ${test.main.class} */ import java.io.IOException; diff --git a/test/jdk/java/net/httpclient/qpack/BlockingDecodingTest.java b/test/jdk/java/net/httpclient/qpack/BlockingDecodingTest.java index 778783ad64c..afa61c0e582 100644 --- a/test/jdk/java/net/httpclient/qpack/BlockingDecodingTest.java +++ b/test/jdk/java/net/httpclient/qpack/BlockingDecodingTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -59,7 +59,7 @@ import org.junit.jupiter.api.Test; * java.net.http/jdk.internal.net.http.http3.frames * java.net.http/jdk.internal.net.http.http3 * @build EncoderDecoderConnector - * @run junit/othervm -Djdk.internal.httpclient.qpack.log.level=EXTRA BlockingDecodingTest + * @run junit/othervm -Djdk.internal.httpclient.qpack.log.level=EXTRA ${test.main.class} */ diff --git a/test/jdk/java/net/httpclient/qpack/DecoderInstructionsReaderTest.java b/test/jdk/java/net/httpclient/qpack/DecoderInstructionsReaderTest.java index e231d0dded3..ea945b76f83 100644 --- a/test/jdk/java/net/httpclient/qpack/DecoderInstructionsReaderTest.java +++ b/test/jdk/java/net/httpclient/qpack/DecoderInstructionsReaderTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * 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 * @key randomness * @library /test/lib - * @run junit/othervm -Djdk.internal.httpclient.qpack.log.level=NORMAL DecoderInstructionsReaderTest + * @run junit/othervm -Djdk.internal.httpclient.qpack.log.level=NORMAL ${test.main.class} */ import jdk.internal.net.http.qpack.QPACK; diff --git a/test/jdk/java/net/httpclient/qpack/DecoderInstructionsWriterTest.java b/test/jdk/java/net/httpclient/qpack/DecoderInstructionsWriterTest.java index 275dec34927..539eb47dc53 100644 --- a/test/jdk/java/net/httpclient/qpack/DecoderInstructionsWriterTest.java +++ b/test/jdk/java/net/httpclient/qpack/DecoderInstructionsWriterTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ * java.net.http/jdk.internal.net.http.http3.streams * java.net.http/jdk.internal.net.http.http3.frames * java.net.http/jdk.internal.net.http.http3 - * @run junit/othervm -Djdk.internal.httpclient.qpack.log.level=NORMAL DecoderInstructionsWriterTest + * @run junit/othervm -Djdk.internal.httpclient.qpack.log.level=NORMAL ${test.main.class} */ import jdk.internal.net.http.qpack.DynamicTable; diff --git a/test/jdk/java/net/httpclient/qpack/DecoderSectionSizeLimitTest.java b/test/jdk/java/net/httpclient/qpack/DecoderSectionSizeLimitTest.java index 1ad094916d4..372554e824f 100644 --- a/test/jdk/java/net/httpclient/qpack/DecoderSectionSizeLimitTest.java +++ b/test/jdk/java/net/httpclient/qpack/DecoderSectionSizeLimitTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ * java.net.http/jdk.internal.net.http.http3 * @build EncoderDecoderConnector * @run junit/othervm -Djdk.internal.httpclient.qpack.log.level=NORMAL - * DecoderSectionSizeLimitTest + * ${test.main.class} */ import jdk.internal.net.http.http3.ConnectionSettings; diff --git a/test/jdk/java/net/httpclient/qpack/DecoderTest.java b/test/jdk/java/net/httpclient/qpack/DecoderTest.java index 15d4bef7cc9..799ea13d45f 100644 --- a/test/jdk/java/net/httpclient/qpack/DecoderTest.java +++ b/test/jdk/java/net/httpclient/qpack/DecoderTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -53,7 +53,7 @@ import org.junit.jupiter.params.provider.MethodSource; * java.net.http/jdk.internal.net.http.http3.streams * java.net.http/jdk.internal.net.http.http3.frames * java.net.http/jdk.internal.net.http.http3 - * @run junit/othervm DecoderTest + * @run junit/othervm ${test.main.class} */ @TestInstance(TestInstance.Lifecycle.PER_CLASS) public class DecoderTest { diff --git a/test/jdk/java/net/httpclient/qpack/DynamicTableFieldLineRepresentationTest.java b/test/jdk/java/net/httpclient/qpack/DynamicTableFieldLineRepresentationTest.java index c314688ab52..0a93a2ed594 100644 --- a/test/jdk/java/net/httpclient/qpack/DynamicTableFieldLineRepresentationTest.java +++ b/test/jdk/java/net/httpclient/qpack/DynamicTableFieldLineRepresentationTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ import org.junit.jupiter.api.Test; * @run junit/othervm -Djdk.internal.httpclient.qpack.log.level=EXTRA * -Djdk.http.qpack.allowBlockingEncoding=true * -Djdk.http.qpack.decoderBlockedStreams=4 - * DynamicTableFieldLineRepresentationTest + * ${test.main.class} */ public class DynamicTableFieldLineRepresentationTest { diff --git a/test/jdk/java/net/httpclient/qpack/DynamicTableTest.java b/test/jdk/java/net/httpclient/qpack/DynamicTableTest.java index c340a25088a..d87532329e5 100644 --- a/test/jdk/java/net/httpclient/qpack/DynamicTableTest.java +++ b/test/jdk/java/net/httpclient/qpack/DynamicTableTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,7 +27,7 @@ * @library /test/lib * @modules java.net.http/jdk.internal.net.http.qpack:+open * java.net.http/jdk.internal.net.http.qpack.readers - * @run junit/othervm -Djdk.internal.httpclient.qpack.log.level=NORMAL DynamicTableTest + * @run junit/othervm -Djdk.internal.httpclient.qpack.log.level=NORMAL ${test.main.class} */ import jdk.internal.net.http.qpack.DynamicTable; diff --git a/test/jdk/java/net/httpclient/qpack/EncoderDecoderConnectionTest.java b/test/jdk/java/net/httpclient/qpack/EncoderDecoderConnectionTest.java index c2bed98bc3c..99680608db8 100644 --- a/test/jdk/java/net/httpclient/qpack/EncoderDecoderConnectionTest.java +++ b/test/jdk/java/net/httpclient/qpack/EncoderDecoderConnectionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * 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 org.junit.jupiter.api.Test; * java.net.http/jdk.internal.net.http.http3 * @build EncoderDecoderConnector * @run junit/othervm -Djdk.internal.httpclient.qpack.log.level=EXTRA - * EncoderDecoderConnectionTest + * ${test.main.class} */ public class EncoderDecoderConnectionTest { diff --git a/test/jdk/java/net/httpclient/qpack/EncoderDecoderTest.java b/test/jdk/java/net/httpclient/qpack/EncoderDecoderTest.java index 7dc1bf73960..9b277c87c3c 100644 --- a/test/jdk/java/net/httpclient/qpack/EncoderDecoderTest.java +++ b/test/jdk/java/net/httpclient/qpack/EncoderDecoderTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -61,7 +61,7 @@ import org.junit.jupiter.params.provider.MethodSource; * java.net.http/jdk.internal.net.http.http3.frames * java.net.http/jdk.internal.net.http.http3 * @build EncoderDecoderConnector - * @run junit/othervm EncoderDecoderTest + * @run junit/othervm ${test.main.class} */ @TestInstance(TestInstance.Lifecycle.PER_CLASS) public class EncoderDecoderTest { diff --git a/test/jdk/java/net/httpclient/qpack/EncoderInstructionsReaderTest.java b/test/jdk/java/net/httpclient/qpack/EncoderInstructionsReaderTest.java index 5c31762cdb3..3a816f4203e 100644 --- a/test/jdk/java/net/httpclient/qpack/EncoderInstructionsReaderTest.java +++ b/test/jdk/java/net/httpclient/qpack/EncoderInstructionsReaderTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * 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 * @key randomness * @library /test/lib - * @run junit/othervm -Djdk.internal.httpclient.qpack.log.level=NORMAL EncoderInstructionsReaderTest + * @run junit/othervm -Djdk.internal.httpclient.qpack.log.level=NORMAL ${test.main.class} */ import jdk.internal.net.http.hpack.QuickHuffman; diff --git a/test/jdk/java/net/httpclient/qpack/EncoderInstructionsWriterTest.java b/test/jdk/java/net/httpclient/qpack/EncoderInstructionsWriterTest.java index fd1fc41d8f7..cbfe4c15cc8 100644 --- a/test/jdk/java/net/httpclient/qpack/EncoderInstructionsWriterTest.java +++ b/test/jdk/java/net/httpclient/qpack/EncoderInstructionsWriterTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * 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 static org.junit.jupiter.api.Assertions.*; * java.net.http/jdk.internal.net.http.http3.streams * java.net.http/jdk.internal.net.http.http3.frames * java.net.http/jdk.internal.net.http.http3 - * @run junit/othervm -Djdk.internal.httpclient.qpack.log.level=NORMAL EncoderInstructionsWriterTest + * @run junit/othervm -Djdk.internal.httpclient.qpack.log.level=NORMAL ${test.main.class} */ @TestInstance(TestInstance.Lifecycle.PER_CLASS) diff --git a/test/jdk/java/net/httpclient/qpack/EncoderTest.java b/test/jdk/java/net/httpclient/qpack/EncoderTest.java index b721fa3d27a..3612e027b79 100644 --- a/test/jdk/java/net/httpclient/qpack/EncoderTest.java +++ b/test/jdk/java/net/httpclient/qpack/EncoderTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * 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,7 +85,7 @@ import org.junit.jupiter.params.provider.MethodSource; * java.net.http/jdk.internal.net.http.http3.streams * java.net.http/jdk.internal.net.http.http3.frames * java.net.http/jdk.internal.net.http.http3 - * @run junit/othervm EncoderTest + * @run junit/othervm ${test.main.class} */ @TestInstance(TestInstance.Lifecycle.PER_CLASS) public class EncoderTest { diff --git a/test/jdk/java/net/httpclient/qpack/EntriesEvictionTest.java b/test/jdk/java/net/httpclient/qpack/EntriesEvictionTest.java index 76d15d0ace9..b5b2348b7ab 100644 --- a/test/jdk/java/net/httpclient/qpack/EntriesEvictionTest.java +++ b/test/jdk/java/net/httpclient/qpack/EntriesEvictionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ * java.net.http/jdk.internal.net.http.http3.streams * java.net.http/jdk.internal.net.http.http3.frames * java.net.http/jdk.internal.net.http.http3 - * @run junit/othervm -Djdk.internal.httpclient.qpack.log.level=EXTRA EntriesEvictionTest + * @run junit/othervm -Djdk.internal.httpclient.qpack.log.level=EXTRA ${test.main.class} */ import java.util.ArrayList; diff --git a/test/jdk/java/net/httpclient/qpack/FieldSectionPrefixTest.java b/test/jdk/java/net/httpclient/qpack/FieldSectionPrefixTest.java index b6fac8291f8..12b1ca60bb4 100644 --- a/test/jdk/java/net/httpclient/qpack/FieldSectionPrefixTest.java +++ b/test/jdk/java/net/httpclient/qpack/FieldSectionPrefixTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ * java.net.http/jdk.internal.net.http.http3.streams * java.net.http/jdk.internal.net.http.http3.frames * java.net.http/jdk.internal.net.http.http3 - * @run junit FieldSectionPrefixTest + * @run junit ${test.main.class} */ diff --git a/test/jdk/java/net/httpclient/qpack/IntegerReaderMaxValuesTest.java b/test/jdk/java/net/httpclient/qpack/IntegerReaderMaxValuesTest.java index ac156e2b547..0005c96df88 100644 --- a/test/jdk/java/net/httpclient/qpack/IntegerReaderMaxValuesTest.java +++ b/test/jdk/java/net/httpclient/qpack/IntegerReaderMaxValuesTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. * 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 org.junit.jupiter.params.provider.MethodSource; * java.net.http/jdk.internal.net.http.qpack.readers * java.net.http/jdk.internal.net.http.qpack.writers * @run junit/othervm -Djdk.internal.httpclient.qpack.log.level=INFO - * IntegerReaderMaxValuesTest + * ${test.main.class} */ @TestInstance(TestInstance.Lifecycle.PER_CLASS) public class IntegerReaderMaxValuesTest { diff --git a/test/jdk/java/net/httpclient/qpack/StaticTableFieldsTest.java b/test/jdk/java/net/httpclient/qpack/StaticTableFieldsTest.java index eea9b31e932..fcee35df53e 100644 --- a/test/jdk/java/net/httpclient/qpack/StaticTableFieldsTest.java +++ b/test/jdk/java/net/httpclient/qpack/StaticTableFieldsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * 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 * @modules java.net.http/jdk.internal.net.http.qpack - * @run junit/othervm -Djdk.internal.httpclient.qpack.log.level=NORMAL StaticTableFieldsTest + * @run junit/othervm -Djdk.internal.httpclient.qpack.log.level=NORMAL ${test.main.class} */ import jdk.internal.net.http.qpack.StaticTable; diff --git a/test/jdk/java/net/httpclient/qpack/StringLengthLimitsTest.java b/test/jdk/java/net/httpclient/qpack/StringLengthLimitsTest.java index 7c94abf1504..56d26db31e4 100644 --- a/test/jdk/java/net/httpclient/qpack/StringLengthLimitsTest.java +++ b/test/jdk/java/net/httpclient/qpack/StringLengthLimitsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -61,7 +61,7 @@ import org.junit.jupiter.params.provider.MethodSource; * java.net.http/jdk.internal.net.http.http3 * @build EncoderDecoderConnector * @run junit/othervm -Djdk.http.qpack.allowBlockingEncoding=true - * StringLengthLimitsTest + * ${test.main.class} */ @TestInstance(TestInstance.Lifecycle.PER_CLASS) public class StringLengthLimitsTest { diff --git a/test/jdk/java/net/httpclient/qpack/TablesIndexerTest.java b/test/jdk/java/net/httpclient/qpack/TablesIndexerTest.java index 1a175342c6b..10b5b58b0e4 100644 --- a/test/jdk/java/net/httpclient/qpack/TablesIndexerTest.java +++ b/test/jdk/java/net/httpclient/qpack/TablesIndexerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * 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 * @modules java.net.http/jdk.internal.net.http.qpack - * @run junit/othervm -Djdk.internal.httpclient.qpack.log.level=INFO TablesIndexerTest + * @run junit/othervm -Djdk.internal.httpclient.qpack.log.level=INFO ${test.main.class} */ import jdk.internal.net.http.qpack.DynamicTable; diff --git a/test/jdk/java/net/httpclient/qpack/UnacknowledgedInsertionTest.java b/test/jdk/java/net/httpclient/qpack/UnacknowledgedInsertionTest.java index 5d0129234f3..24a2195cdbd 100644 --- a/test/jdk/java/net/httpclient/qpack/UnacknowledgedInsertionTest.java +++ b/test/jdk/java/net/httpclient/qpack/UnacknowledgedInsertionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -57,7 +57,7 @@ import org.junit.jupiter.params.provider.MethodSource; * java.net.http/jdk.internal.net.http.http3.frames * java.net.http/jdk.internal.net.http.http3 * @build EncoderDecoderConnector - * @run junit/othervm -Djdk.internal.httpclient.qpack.log.level=EXTRA UnacknowledgedInsertionTest + * @run junit/othervm -Djdk.internal.httpclient.qpack.log.level=EXTRA ${test.main.class} */ @TestInstance(TestInstance.Lifecycle.PER_CLASS) public class UnacknowledgedInsertionTest { diff --git a/test/jdk/java/net/httpclient/quic/AckElicitingTest.java b/test/jdk/java/net/httpclient/quic/AckElicitingTest.java index 7fbc00f9148..97da68c1031 100644 --- a/test/jdk/java/net/httpclient/quic/AckElicitingTest.java +++ b/test/jdk/java/net/httpclient/quic/AckElicitingTest.java @@ -89,8 +89,8 @@ import org.junit.jupiter.params.provider.MethodSource; * @summary tests the logic to decide whether a packet or * a frame is ACK-eliciting. * @library /test/lib - * @run junit AckElicitingTest - * @run junit/othervm -Dseed=-7997973196290088038 AckElicitingTest + * @run junit ${test.main.class} + * @run junit/othervm -Dseed=-7997973196290088038 ${test.main.class} */ public class AckElicitingTest { diff --git a/test/jdk/java/net/httpclient/quic/AckFrameTest.java b/test/jdk/java/net/httpclient/quic/AckFrameTest.java index 3c8c027e73b..51326628521 100644 --- a/test/jdk/java/net/httpclient/quic/AckFrameTest.java +++ b/test/jdk/java/net/httpclient/quic/AckFrameTest.java @@ -46,7 +46,7 @@ import org.junit.jupiter.params.provider.MethodSource; * @test * @summary tests the logic to build an AckFrame * @library /test/lib - * @run junit AckFrameTest + * @run junit ${test.main.class} */ public class AckFrameTest { diff --git a/test/jdk/java/net/httpclient/quic/BuffersReaderTest.java b/test/jdk/java/net/httpclient/quic/BuffersReaderTest.java index 8d03f4265b3..d73178a88ec 100644 --- a/test/jdk/java/net/httpclient/quic/BuffersReaderTest.java +++ b/test/jdk/java/net/httpclient/quic/BuffersReaderTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,7 +50,7 @@ import static org.junit.jupiter.api.Assertions.*; * @test * @library /test/lib * @modules java.net.http/jdk.internal.net.http.quic - * @run junit/othervm BuffersReaderTest + * @run junit/othervm ${test.main.class} * @summary Tests various BuffersReader methods * work as expected. */ diff --git a/test/jdk/java/net/httpclient/quic/BuffersReaderVLTest.java b/test/jdk/java/net/httpclient/quic/BuffersReaderVLTest.java index 100a6112de5..dc2c4a986c3 100644 --- a/test/jdk/java/net/httpclient/quic/BuffersReaderVLTest.java +++ b/test/jdk/java/net/httpclient/quic/BuffersReaderVLTest.java @@ -39,7 +39,7 @@ import org.junit.jupiter.params.provider.MethodSource; * @test * @library /test/lib * @modules java.net.http/jdk.internal.net.http.quic - * @run junit/othervm BuffersReaderVLTest + * @run junit/othervm ${test.main.class} * @summary Tests to check quic/util methods encode/decodeVariableLength methods * work as expected. */ diff --git a/test/jdk/java/net/httpclient/quic/ConnectionIDSTest.java b/test/jdk/java/net/httpclient/quic/ConnectionIDSTest.java index 96aeace0898..a54662f4f87 100644 --- a/test/jdk/java/net/httpclient/quic/ConnectionIDSTest.java +++ b/test/jdk/java/net/httpclient/quic/ConnectionIDSTest.java @@ -35,7 +35,7 @@ import org.junit.jupiter.api.Test; /* * @test - * @run junit/othervm ConnectionIDSTest + * @run junit/othervm ${test.main.class} */ public class ConnectionIDSTest { diff --git a/test/jdk/java/net/httpclient/quic/CryptoWriterQueueTest.java b/test/jdk/java/net/httpclient/quic/CryptoWriterQueueTest.java index 422d71ca964..6a87d859170 100644 --- a/test/jdk/java/net/httpclient/quic/CryptoWriterQueueTest.java +++ b/test/jdk/java/net/httpclient/quic/CryptoWriterQueueTest.java @@ -34,7 +34,7 @@ import org.junit.jupiter.api.Test; * @summary Tests jdk.internal.net.http.quic.streams,CryptoWriterQueue * @modules java.net.http/jdk.internal.net.http.quic.streams * java.net.http/jdk.internal.net.http.quic.frames - * @run junit CryptoWriterQueueTest + * @run junit ${test.main.class} */ public class CryptoWriterQueueTest { diff --git a/test/jdk/java/net/httpclient/quic/CubicTest.java b/test/jdk/java/net/httpclient/quic/CubicTest.java index f4b08e6d9b7..711be0700fa 100644 --- a/test/jdk/java/net/httpclient/quic/CubicTest.java +++ b/test/jdk/java/net/httpclient/quic/CubicTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,7 +38,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; /* * @test - * @run junit/othervm -Djdk.httpclient.HttpClient.log=trace,quic:cc CubicTest + * @run junit/othervm -Djdk.httpclient.HttpClient.log=trace,quic:cc ${test.main.class} */ public class CubicTest { static class TimeSource implements TimeLine { diff --git a/test/jdk/java/net/httpclient/quic/KeyUpdateTest.java b/test/jdk/java/net/httpclient/quic/KeyUpdateTest.java index eaec0bc8b95..23b667d3953 100644 --- a/test/jdk/java/net/httpclient/quic/KeyUpdateTest.java +++ b/test/jdk/java/net/httpclient/quic/KeyUpdateTest.java @@ -83,7 +83,7 @@ import org.junit.jupiter.api.Test; * @run junit/othervm -Djava.security.properties=${test.src}/quic-tls-keylimits-java.security * -Djdk.internal.httpclient.debug=true * -Djavax.net.debug=all - * KeyUpdateTest + * ${test.main.class} */ public class KeyUpdateTest { diff --git a/test/jdk/java/net/httpclient/quic/OrderedFlowTest.java b/test/jdk/java/net/httpclient/quic/OrderedFlowTest.java index a1fafba8760..f5f742d9226 100644 --- a/test/jdk/java/net/httpclient/quic/OrderedFlowTest.java +++ b/test/jdk/java/net/httpclient/quic/OrderedFlowTest.java @@ -50,11 +50,11 @@ import org.junit.jupiter.params.provider.MethodSource; * @summary tests the reordering logic implemented by OrderedFlow * and its two concrete subclasses * @library /test/lib - * @run junit OrderedFlowTest - * @run junit/othervm -Dseed=-2680947227866359853 OrderedFlowTest - * @run junit/othervm -Dseed=-273117134353023275 OrderedFlowTest - * @run junit/othervm -Dseed=3649132517916066643 OrderedFlowTest - * @run junit/othervm -Dseed=4568737726943220431 OrderedFlowTest + * @run junit ${test.main.class} + * @run junit/othervm -Dseed=-2680947227866359853 ${test.main.class} + * @run junit/othervm -Dseed=-273117134353023275 ${test.main.class} + * @run junit/othervm -Dseed=3649132517916066643 ${test.main.class} + * @run junit/othervm -Dseed=4568737726943220431 ${test.main.class} */ public class OrderedFlowTest { diff --git a/test/jdk/java/net/httpclient/quic/PacerTest.java b/test/jdk/java/net/httpclient/quic/PacerTest.java index aebbbce34d3..a624817bd4e 100644 --- a/test/jdk/java/net/httpclient/quic/PacerTest.java +++ b/test/jdk/java/net/httpclient/quic/PacerTest.java @@ -40,7 +40,7 @@ import org.junit.jupiter.params.provider.MethodSource; /* * @test - * @run junit/othervm -Djdk.httpclient.quic.timerFrequency=1000 PacerTest + * @run junit/othervm -Djdk.httpclient.quic.timerFrequency=1000 ${test.main.class} */ public class PacerTest { diff --git a/test/jdk/java/net/httpclient/quic/PacketEncodingTest.java b/test/jdk/java/net/httpclient/quic/PacketEncodingTest.java index a96904c8410..fa43baa853f 100644 --- a/test/jdk/java/net/httpclient/quic/PacketEncodingTest.java +++ b/test/jdk/java/net/httpclient/quic/PacketEncodingTest.java @@ -80,17 +80,17 @@ import org.junit.jupiter.params.provider.MethodSource; * @library /test/lib * @summary test packet encoding and decoding in unencrypted form and without * any network involvement. - * @run junit/othervm -Dseed=2646683818688275736 PacketEncodingTest - * @run junit/othervm -Dseed=-3723256402256409075 PacketEncodingTest - * @run junit/othervm -Dseed=-3689060484817342283 PacketEncodingTest - * @run junit/othervm -Dseed=2425718686525936108 PacketEncodingTest - * @run junit/othervm -Dseed=-2996954753243104355 PacketEncodingTest - * @run junit/othervm -Dseed=8750823652999067800 PacketEncodingTest - * @run junit/othervm -Dseed=2906555779406889127 PacketEncodingTest - * @run junit/othervm -Dseed=902801756808168822 PacketEncodingTest - * @run junit/othervm -Dseed=5643545543196691308 PacketEncodingTest - * @run junit/othervm -Dseed=2646683818688275736 PacketEncodingTest - * @run junit/othervm -Djdk.internal.httpclient.debug=true PacketEncodingTest + * @run junit/othervm -Dseed=2646683818688275736 ${test.main.class} + * @run junit/othervm -Dseed=-3723256402256409075 ${test.main.class} + * @run junit/othervm -Dseed=-3689060484817342283 ${test.main.class} + * @run junit/othervm -Dseed=2425718686525936108 ${test.main.class} + * @run junit/othervm -Dseed=-2996954753243104355 ${test.main.class} + * @run junit/othervm -Dseed=8750823652999067800 ${test.main.class} + * @run junit/othervm -Dseed=2906555779406889127 ${test.main.class} + * @run junit/othervm -Dseed=902801756808168822 ${test.main.class} + * @run junit/othervm -Dseed=5643545543196691308 ${test.main.class} + * @run junit/othervm -Dseed=2646683818688275736 ${test.main.class} + * @run junit/othervm -Djdk.internal.httpclient.debug=true ${test.main.class} */ public class PacketEncodingTest { diff --git a/test/jdk/java/net/httpclient/quic/PacketLossTest.java b/test/jdk/java/net/httpclient/quic/PacketLossTest.java index a597c826e73..9ecb3444060 100644 --- a/test/jdk/java/net/httpclient/quic/PacketLossTest.java +++ b/test/jdk/java/net/httpclient/quic/PacketLossTest.java @@ -63,7 +63,7 @@ import org.junit.jupiter.api.Test; * -Djdk.httpclient.quic.minPtoBackoffTime=60 * -Djdk.httpclient.quic.maxPtoBackoffTime=10 * -Djdk.httpclient.quic.maxPtoBackoff=9 - * -Djdk.httpclient.HttpClient.log=quic,errors PacketLossTest + * -Djdk.httpclient.HttpClient.log=quic,errors ${test.main.class} */ public class PacketLossTest { diff --git a/test/jdk/java/net/httpclient/quic/PacketNumbersTest.java b/test/jdk/java/net/httpclient/quic/PacketNumbersTest.java index c018079ea4e..7c19e8b414e 100644 --- a/test/jdk/java/net/httpclient/quic/PacketNumbersTest.java +++ b/test/jdk/java/net/httpclient/quic/PacketNumbersTest.java @@ -37,7 +37,7 @@ import org.junit.jupiter.params.provider.MethodSource; /* * @test - * @run junit PacketNumbersTest + * @run junit ${test.main.class} */ public class PacketNumbersTest { diff --git a/test/jdk/java/net/httpclient/quic/PacketSpaceManagerTest.java b/test/jdk/java/net/httpclient/quic/PacketSpaceManagerTest.java index fe3b748a2fa..0a363e104ae 100644 --- a/test/jdk/java/net/httpclient/quic/PacketSpaceManagerTest.java +++ b/test/jdk/java/net/httpclient/quic/PacketSpaceManagerTest.java @@ -94,14 +94,14 @@ import org.junit.jupiter.params.provider.MethodSource; * @library /test/lib * @library ../debug * @build java.net.http/jdk.internal.net.http.common.TestLoggerUtil - * @run junit/othervm PacketSpaceManagerTest - * @run junit/othervm -Dseed=-7947549564260911920 PacketSpaceManagerTest - * @run junit/othervm -Dseed=-5413111674202728207 PacketSpaceManagerTest - * @run junit/othervm -Dseed=-176652423987357212 PacketSpaceManagerTest - * @run junit/othervm -Dseed=6550551791799910315 PacketSpaceManagerTest - * @run junit/othervm -Dseed=-4159871071396382784 PacketSpaceManagerTest - * @run junit/othervm -Dseed=2252276218459363615 PacketSpaceManagerTest - * @run junit/othervm -Dseed=-5130588140709404919 PacketSpaceManagerTest + * @run junit/othervm ${test.main.class} + * @run junit/othervm -Dseed=-7947549564260911920 ${test.main.class} + * @run junit/othervm -Dseed=-5413111674202728207 ${test.main.class} + * @run junit/othervm -Dseed=-176652423987357212 ${test.main.class} + * @run junit/othervm -Dseed=6550551791799910315 ${test.main.class} + * @run junit/othervm -Dseed=-4159871071396382784 ${test.main.class} + * @run junit/othervm -Dseed=2252276218459363615 ${test.main.class} + * @run junit/othervm -Dseed=-5130588140709404919 ${test.main.class} */ // -Djdk.internal.httpclient.debug=true public class PacketSpaceManagerTest { diff --git a/test/jdk/java/net/httpclient/quic/QuicFramesDecoderTest.java b/test/jdk/java/net/httpclient/quic/QuicFramesDecoderTest.java index ef0801e6c18..d6eeda32cad 100644 --- a/test/jdk/java/net/httpclient/quic/QuicFramesDecoderTest.java +++ b/test/jdk/java/net/httpclient/quic/QuicFramesDecoderTest.java @@ -37,7 +37,7 @@ import org.junit.jupiter.params.provider.MethodSource; * @test * @library /test/lib * @summary Tests to check QUIC frame decoding errors are handled correctly - * @run junit/othervm QuicFramesDecoderTest + * @run junit/othervm ${test.main.class} */ public class QuicFramesDecoderTest { diff --git a/test/jdk/java/net/httpclient/quic/QuicRequestResponseTest.java b/test/jdk/java/net/httpclient/quic/QuicRequestResponseTest.java index 2393ac7df12..d70b5ac8443 100644 --- a/test/jdk/java/net/httpclient/quic/QuicRequestResponseTest.java +++ b/test/jdk/java/net/httpclient/quic/QuicRequestResponseTest.java @@ -55,7 +55,7 @@ import org.junit.jupiter.api.Test; * jdk.httpclient.test.lib.quic.ClientConnection * jdk.httpclient.test.lib.common.TestUtil * jdk.test.lib.net.SimpleSSLContext - * @run junit/othervm -Djdk.internal.httpclient.debug=true QuicRequestResponseTest + * @run junit/othervm -Djdk.internal.httpclient.debug=true ${test.main.class} */ public class QuicRequestResponseTest { diff --git a/test/jdk/java/net/httpclient/quic/StatelessResetReceiptTest.java b/test/jdk/java/net/httpclient/quic/StatelessResetReceiptTest.java index 9f7852740b4..bed76c9b0a2 100644 --- a/test/jdk/java/net/httpclient/quic/StatelessResetReceiptTest.java +++ b/test/jdk/java/net/httpclient/quic/StatelessResetReceiptTest.java @@ -71,7 +71,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.httpclient.test.lib.quic.QuicStandaloneServer * jdk.test.lib.net.SimpleSSLContext jdk.httpclient.test.lib.common.TestUtil - * @run junit/othervm -Djdk.internal.httpclient.debug=true StatelessResetReceiptTest + * @run junit/othervm -Djdk.internal.httpclient.debug=true ${test.main.class} */ public class StatelessResetReceiptTest { diff --git a/test/jdk/java/net/httpclient/quic/VariableLengthTest.java b/test/jdk/java/net/httpclient/quic/VariableLengthTest.java index 6d805fbad5a..f5dbb8f159c 100644 --- a/test/jdk/java/net/httpclient/quic/VariableLengthTest.java +++ b/test/jdk/java/net/httpclient/quic/VariableLengthTest.java @@ -38,7 +38,7 @@ import org.opentest4j.TestAbortedException; * @test * @library /test/lib * @modules java.net.http/jdk.internal.net.http.quic - * @run junit/othervm VariableLengthTest + * @run junit/othervm ${test.main.class} * @summary Tests to check quic/util methods encode/decodeVariableLength methods * work as expected. */ diff --git a/test/jdk/java/net/httpclient/quic/VersionNegotiationTest.java b/test/jdk/java/net/httpclient/quic/VersionNegotiationTest.java index 6b40bf84a8e..bee9bfc7d2c 100644 --- a/test/jdk/java/net/httpclient/quic/VersionNegotiationTest.java +++ b/test/jdk/java/net/httpclient/quic/VersionNegotiationTest.java @@ -59,7 +59,7 @@ import org.junit.jupiter.api.Test; * jdk.httpclient.test.lib.common.TestUtil * jdk.httpclient.test.lib.quic.ClientConnection * jdk.test.lib.net.SimpleSSLContext - * @run junit/othervm -Djdk.internal.httpclient.debug=true VersionNegotiationTest + * @run junit/othervm -Djdk.internal.httpclient.debug=true ${test.main.class} */ public class VersionNegotiationTest { diff --git a/test/jdk/java/net/httpclient/quic/tls/PacketEncryptionTest.java b/test/jdk/java/net/httpclient/quic/tls/PacketEncryptionTest.java index d80e473696a..bb69e377860 100644 --- a/test/jdk/java/net/httpclient/quic/tls/PacketEncryptionTest.java +++ b/test/jdk/java/net/httpclient/quic/tls/PacketEncryptionTest.java @@ -52,7 +52,7 @@ import org.junit.jupiter.api.Test; * java.base/jdk.internal.net.quic * @build java.base/sun.security.ssl.QuicTLSEngineImplAccessor * @summary known-answer test for packet encryption and decryption - * @run junit/othervm PacketEncryptionTest + * @run junit/othervm ${test.main.class} */ public class PacketEncryptionTest { diff --git a/test/jdk/java/net/httpclient/quic/tls/QuicTLSEngineBadParametersTest.java b/test/jdk/java/net/httpclient/quic/tls/QuicTLSEngineBadParametersTest.java index 0b7e6875b96..5a10136470b 100644 --- a/test/jdk/java/net/httpclient/quic/tls/QuicTLSEngineBadParametersTest.java +++ b/test/jdk/java/net/httpclient/quic/tls/QuicTLSEngineBadParametersTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,7 +44,7 @@ import static org.junit.jupiter.api.Assertions.*; * @build jdk.test.lib.net.SimpleSSLContext * @summary Verify that QuicTransportExceptions thrown by transport parameter consumer * are propagated to the QuicTLSEngine user - * @run junit/othervm QuicTLSEngineBadParametersTest + * @run junit/othervm ${test.main.class} */ public class QuicTLSEngineBadParametersTest { diff --git a/test/jdk/java/net/httpclient/quic/tls/QuicTLSEngineFailedALPNTest.java b/test/jdk/java/net/httpclient/quic/tls/QuicTLSEngineFailedALPNTest.java index 5767d81cc83..1fd37e32eaa 100644 --- a/test/jdk/java/net/httpclient/quic/tls/QuicTLSEngineFailedALPNTest.java +++ b/test/jdk/java/net/httpclient/quic/tls/QuicTLSEngineFailedALPNTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,7 +42,7 @@ import static org.junit.jupiter.api.Assertions.*; * java.base/jdk.internal.net.quic * @build jdk.test.lib.net.SimpleSSLContext * @summary Verify that a missing ALPN extension results in no_application_protocol alert - * @run junit/othervm QuicTLSEngineFailedALPNTest + * @run junit/othervm ${test.main.class} */ public class QuicTLSEngineFailedALPNTest { diff --git a/test/jdk/java/net/httpclient/quic/tls/QuicTLSEngineMissingParametersTest.java b/test/jdk/java/net/httpclient/quic/tls/QuicTLSEngineMissingParametersTest.java index 933d258f912..f5c882a074d 100644 --- a/test/jdk/java/net/httpclient/quic/tls/QuicTLSEngineMissingParametersTest.java +++ b/test/jdk/java/net/httpclient/quic/tls/QuicTLSEngineMissingParametersTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,7 +42,7 @@ import static org.junit.jupiter.api.Assertions.*; * java.base/jdk.internal.net.quic * @build jdk.test.lib.net.SimpleSSLContext * @summary Verify that a missing transport parameters extension results in missing_extension alert - * @run junit/othervm QuicTLSEngineMissingParametersTest + * @run junit/othervm ${test.main.class} */ public class QuicTLSEngineMissingParametersTest { diff --git a/test/jdk/java/net/httpclient/quic/tls/Quicv2PacketEncryptionTest.java b/test/jdk/java/net/httpclient/quic/tls/Quicv2PacketEncryptionTest.java index 285fa2e4cd4..6205c8f3c7b 100644 --- a/test/jdk/java/net/httpclient/quic/tls/Quicv2PacketEncryptionTest.java +++ b/test/jdk/java/net/httpclient/quic/tls/Quicv2PacketEncryptionTest.java @@ -52,7 +52,7 @@ import org.junit.jupiter.api.Test; * java.base/jdk.internal.net.quic * @build java.base/sun.security.ssl.QuicTLSEngineImplAccessor * @summary known-answer test for packet encryption and decryption with Quic v2 - * @run junit/othervm Quicv2PacketEncryptionTest + * @run junit/othervm ${test.main.class} */ public class Quicv2PacketEncryptionTest { diff --git a/test/jdk/java/net/httpclient/security/filePerms/FileProcessorPermissionTest.java b/test/jdk/java/net/httpclient/security/filePerms/FileProcessorPermissionTest.java index 361b053fe43..d703907c2eb 100644 --- a/test/jdk/java/net/httpclient/security/filePerms/FileProcessorPermissionTest.java +++ b/test/jdk/java/net/httpclient/security/filePerms/FileProcessorPermissionTest.java @@ -24,7 +24,7 @@ /* * @test * @summary Basic checks for File Processors - * @run junit/othervm FileProcessorPermissionTest + * @run junit/othervm ${test.main.class} */ import java.nio.file.Path; diff --git a/test/jdk/java/net/httpclient/security/filePerms/SecurityBeforeFile.java b/test/jdk/java/net/httpclient/security/filePerms/SecurityBeforeFile.java index c8d7bb64b36..ab03ee08d64 100644 --- a/test/jdk/java/net/httpclient/security/filePerms/SecurityBeforeFile.java +++ b/test/jdk/java/net/httpclient/security/filePerms/SecurityBeforeFile.java @@ -25,7 +25,7 @@ * @test * @summary Verifies security checks are performed before existence checks * in pre-defined body processors APIs - * @run junit/othervm SecurityBeforeFile + * @run junit/othervm ${test.main.class} */ import java.io.FileNotFoundException; diff --git a/test/jdk/java/net/httpclient/ssltest/CertificateTest.java b/test/jdk/java/net/httpclient/ssltest/CertificateTest.java index 1d0502c9ce3..23f7aebf9fc 100644 --- a/test/jdk/java/net/httpclient/ssltest/CertificateTest.java +++ b/test/jdk/java/net/httpclient/ssltest/CertificateTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,21 +42,21 @@ import jdk.test.lib.security.SSLContextBuilder; * @library /test/lib /test/jdk/java/net/httpclient/lib * @build Server CertificateTest jdk.httpclient.test.lib.common.TestServerConfigurator * @modules java.net.http/jdk.internal.net.http.common - * @run main/othervm CertificateTest GOOD_CERT expectSuccess - * @run main/othervm CertificateTest BAD_CERT expectFailure + * @run main/othervm ${test.main.class} GOOD_CERT expectSuccess + * @run main/othervm ${test.main.class} BAD_CERT expectFailure * @run main/othervm * -Djdk.internal.httpclient.disableHostnameVerification - * CertificateTest BAD_CERT expectSuccess + * ${test.main.class} BAD_CERT expectSuccess * @run main/othervm * -Djdk.internal.httpclient.disableHostnameVerification=true - * CertificateTest BAD_CERT expectSuccess + * ${test.main.class} BAD_CERT expectSuccess * @run main/othervm * -Djdk.internal.httpclient.disableHostnameVerification=false - * CertificateTest BAD_CERT expectFailure + * ${test.main.class} BAD_CERT expectFailure * @run main/othervm * -Djdk.internal.httpclient.disableHostnameVerification=xxyyzz - * CertificateTest BAD_CERT expectFailure - * @run main/othervm CertificateTest LOOPBACK_CERT expectSuccess + * ${test.main.class} BAD_CERT expectFailure + * @run main/othervm ${test.main.class} LOOPBACK_CERT expectSuccess */ /** diff --git a/test/jdk/java/net/httpclient/ssltest/TlsVersionTest.java b/test/jdk/java/net/httpclient/ssltest/TlsVersionTest.java index 2e364461793..0916022e89a 100644 --- a/test/jdk/java/net/httpclient/ssltest/TlsVersionTest.java +++ b/test/jdk/java/net/httpclient/ssltest/TlsVersionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * 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,12 +47,12 @@ import static java.net.http.HttpClient.Builder.NO_PROXY; * @modules java.net.http/jdk.internal.net.http.common * @run main/othervm * -Djdk.internal.httpclient.disableHostnameVerification - * TlsVersionTest false + * ${test.main.class} false * * @run main/othervm * -Djdk.internal.httpclient.disableHostnameVerification * -Djdk.tls.client.protocols="TLSv1.2" - * TlsVersionTest true + * ${test.main.class} true */ /** diff --git a/test/jdk/java/net/httpclient/websocket/Abort.java b/test/jdk/java/net/httpclient/websocket/Abort.java index a6088f8cce2..6a388878db2 100644 --- a/test/jdk/java/net/httpclient/websocket/Abort.java +++ b/test/jdk/java/net/httpclient/websocket/Abort.java @@ -26,7 +26,7 @@ * @build DummyWebSocketServer * @run junit/othervm * -Djdk.internal.httpclient.websocket.debug=true - * Abort + * ${test.main.class} */ diff --git a/test/jdk/java/net/httpclient/websocket/AutomaticPong.java b/test/jdk/java/net/httpclient/websocket/AutomaticPong.java index b438cb8e728..a590790c29a 100644 --- a/test/jdk/java/net/httpclient/websocket/AutomaticPong.java +++ b/test/jdk/java/net/httpclient/websocket/AutomaticPong.java @@ -26,7 +26,7 @@ * @build DummyWebSocketServer * @run junit/othervm * -Djdk.internal.httpclient.websocket.debug=true - * AutomaticPong + * ${test.main.class} */ import jdk.internal.net.http.websocket.Frame; diff --git a/test/jdk/java/net/httpclient/websocket/BlowupOutputQueue.java b/test/jdk/java/net/httpclient/websocket/BlowupOutputQueue.java index 1865ca05e4f..191fd4bcb37 100644 --- a/test/jdk/java/net/httpclient/websocket/BlowupOutputQueue.java +++ b/test/jdk/java/net/httpclient/websocket/BlowupOutputQueue.java @@ -27,7 +27,7 @@ * @run junit/othervm * -Djdk.internal.httpclient.debug=true * -Djdk.internal.httpclient.websocket.debug=true - * BlowupOutputQueue + * ${test.main.class} */ import java.io.IOException; diff --git a/test/jdk/java/net/httpclient/websocket/ConnectionHandoverTest.java b/test/jdk/java/net/httpclient/websocket/ConnectionHandoverTest.java index 30569fa80d7..0633fe9c20f 100644 --- a/test/jdk/java/net/httpclient/websocket/ConnectionHandoverTest.java +++ b/test/jdk/java/net/httpclient/websocket/ConnectionHandoverTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * 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 8164625 * @summary Verifies HttpClient yields the connection to the WebSocket * @build DummyWebSocketServer - * @run main/othervm -Djdk.httpclient.HttpClient.log=trace ConnectionHandoverTest + * @run main/othervm -Djdk.httpclient.HttpClient.log=trace ${test.main.class} */ import java.io.IOException; diff --git a/test/jdk/java/net/httpclient/websocket/HandshakeUrlEncodingTest.java b/test/jdk/java/net/httpclient/websocket/HandshakeUrlEncodingTest.java index 6854cacbcc2..344e6fbc086 100644 --- a/test/jdk/java/net/httpclient/websocket/HandshakeUrlEncodingTest.java +++ b/test/jdk/java/net/httpclient/websocket/HandshakeUrlEncodingTest.java @@ -29,7 +29,7 @@ * @build jdk.test.lib.net.SimpleSSLContext jdk.httpclient.test.lib.common.TestServerConfigurator * @modules java.net.http/jdk.internal.net.http.common * jdk.httpserver - * @run junit/othervm -Djdk.internal.httpclient.debug=true HandshakeUrlEncodingTest + * @run junit/othervm -Djdk.internal.httpclient.debug=true ${test.main.class} */ import com.sun.net.httpserver.HttpHandler; diff --git a/test/jdk/java/net/httpclient/websocket/PendingBinaryPingClose.java b/test/jdk/java/net/httpclient/websocket/PendingBinaryPingClose.java index 4a5ae315e91..67d53eafd31 100644 --- a/test/jdk/java/net/httpclient/websocket/PendingBinaryPingClose.java +++ b/test/jdk/java/net/httpclient/websocket/PendingBinaryPingClose.java @@ -28,7 +28,7 @@ * -Djdk.httpclient.sendBufferSize=8192 * -Djdk.internal.httpclient.debug=true * -Djdk.internal.httpclient.websocket.debug=true - * PendingBinaryPingClose + * ${test.main.class} */ import java.net.http.WebSocket; diff --git a/test/jdk/java/net/httpclient/websocket/PendingBinaryPongClose.java b/test/jdk/java/net/httpclient/websocket/PendingBinaryPongClose.java index a8330faeb3f..f634fe8bd45 100644 --- a/test/jdk/java/net/httpclient/websocket/PendingBinaryPongClose.java +++ b/test/jdk/java/net/httpclient/websocket/PendingBinaryPongClose.java @@ -28,7 +28,7 @@ * -Djdk.httpclient.sendBufferSize=8192 * -Djdk.internal.httpclient.debug=true * -Djdk.internal.httpclient.websocket.debug=true - * PendingBinaryPongClose + * ${test.main.class} */ import java.net.http.WebSocket; diff --git a/test/jdk/java/net/httpclient/websocket/PendingPingBinaryClose.java b/test/jdk/java/net/httpclient/websocket/PendingPingBinaryClose.java index e07ebe0d03a..1f5263368f1 100644 --- a/test/jdk/java/net/httpclient/websocket/PendingPingBinaryClose.java +++ b/test/jdk/java/net/httpclient/websocket/PendingPingBinaryClose.java @@ -26,7 +26,7 @@ * @build DummyWebSocketServer * @run junit/othervm * -Djdk.httpclient.sendBufferSize=8192 - * PendingPingBinaryClose + * ${test.main.class} */ // This test produce huge logs (14Mb+) so disable logging by default diff --git a/test/jdk/java/net/httpclient/websocket/PendingPingTextClose.java b/test/jdk/java/net/httpclient/websocket/PendingPingTextClose.java index eae01f804a4..ab7f3b0be87 100644 --- a/test/jdk/java/net/httpclient/websocket/PendingPingTextClose.java +++ b/test/jdk/java/net/httpclient/websocket/PendingPingTextClose.java @@ -26,7 +26,7 @@ * @build DummyWebSocketServer * @run junit/othervm * -Djdk.httpclient.sendBufferSize=8192 - * PendingPingTextClose + * ${test.main.class} */ // This test produce huge logs (14Mb+) so disable logging by default diff --git a/test/jdk/java/net/httpclient/websocket/PendingPongBinaryClose.java b/test/jdk/java/net/httpclient/websocket/PendingPongBinaryClose.java index 32640853b00..2c631c798e0 100644 --- a/test/jdk/java/net/httpclient/websocket/PendingPongBinaryClose.java +++ b/test/jdk/java/net/httpclient/websocket/PendingPongBinaryClose.java @@ -26,7 +26,7 @@ * @build DummyWebSocketServer * @run junit/othervm * -Djdk.httpclient.sendBufferSize=8192 - * PendingPongBinaryClose + * ${test.main.class} */ // This test produce huge logs (14Mb+) so disable logging by default diff --git a/test/jdk/java/net/httpclient/websocket/PendingPongTextClose.java b/test/jdk/java/net/httpclient/websocket/PendingPongTextClose.java index f4d6c84c2f5..33b0ade39e3 100644 --- a/test/jdk/java/net/httpclient/websocket/PendingPongTextClose.java +++ b/test/jdk/java/net/httpclient/websocket/PendingPongTextClose.java @@ -26,7 +26,7 @@ * @build DummyWebSocketServer * @run junit/othervm * -Djdk.httpclient.sendBufferSize=8192 - * PendingPongTextClose + * ${test.main.class} */ // This test produce huge logs (14Mb+) so disable logging by default diff --git a/test/jdk/java/net/httpclient/websocket/PendingTextPingClose.java b/test/jdk/java/net/httpclient/websocket/PendingTextPingClose.java index 76f12430804..a35f27f4b16 100644 --- a/test/jdk/java/net/httpclient/websocket/PendingTextPingClose.java +++ b/test/jdk/java/net/httpclient/websocket/PendingTextPingClose.java @@ -28,7 +28,7 @@ * -Djdk.internal.httpclient.debug=true * -Djdk.internal.httpclient.websocket.debug=true * -Djdk.httpclient.sendBufferSize=8192 - * PendingTextPingClose + * ${test.main.class} */ import java.net.http.WebSocket; diff --git a/test/jdk/java/net/httpclient/websocket/PendingTextPongClose.java b/test/jdk/java/net/httpclient/websocket/PendingTextPongClose.java index a2a41a73d7b..80c72297e43 100644 --- a/test/jdk/java/net/httpclient/websocket/PendingTextPongClose.java +++ b/test/jdk/java/net/httpclient/websocket/PendingTextPongClose.java @@ -28,7 +28,7 @@ * -Djdk.internal.httpclient.debug=true * -Djdk.internal.httpclient.websocket.debug=true * -Djdk.httpclient.sendBufferSize=8192 - * PendingTextPongClose + * ${test.main.class} */ import java.net.http.WebSocket; diff --git a/test/jdk/java/net/httpclient/websocket/SendTest.java b/test/jdk/java/net/httpclient/websocket/SendTest.java index b3a433b5c29..124d15e1cc0 100644 --- a/test/jdk/java/net/httpclient/websocket/SendTest.java +++ b/test/jdk/java/net/httpclient/websocket/SendTest.java @@ -26,7 +26,7 @@ * @build DummyWebSocketServer * @run junit/othervm * -Djdk.internal.httpclient.websocket.debug=true - * SendTest + * ${test.main.class} */ import java.io.IOException; diff --git a/test/jdk/java/net/httpclient/websocket/WSHandshakeExceptionTest.java b/test/jdk/java/net/httpclient/websocket/WSHandshakeExceptionTest.java index f28d84b2f20..cf77c66e7c7 100644 --- a/test/jdk/java/net/httpclient/websocket/WSHandshakeExceptionTest.java +++ b/test/jdk/java/net/httpclient/websocket/WSHandshakeExceptionTest.java @@ -29,7 +29,7 @@ * @build jdk.test.lib.net.SimpleSSLContext jdk.httpclient.test.lib.common.TestServerConfigurator * @modules java.net.http/jdk.internal.net.http.common * jdk.httpserver - * @run junit/othervm -Djdk.internal.httpclient.debug=true WSHandshakeExceptionTest + * @run junit/othervm -Djdk.internal.httpclient.debug=true ${test.main.class} */ import com.sun.net.httpserver.HttpHandler; diff --git a/test/jdk/java/net/httpclient/websocket/WebSocketBuilderTest.java b/test/jdk/java/net/httpclient/websocket/WebSocketBuilderTest.java index beef8cb42a4..a5b5f73077c 100644 --- a/test/jdk/java/net/httpclient/websocket/WebSocketBuilderTest.java +++ b/test/jdk/java/net/httpclient/websocket/WebSocketBuilderTest.java @@ -26,7 +26,7 @@ * @bug 8159053 * @build DummyWebSocketServer * Support - * @run junit/othervm WebSocketBuilderTest + * @run junit/othervm ${test.main.class} */ import java.net.URI; diff --git a/test/jdk/java/net/httpclient/websocket/WebSocketEndiannessTest.java b/test/jdk/java/net/httpclient/websocket/WebSocketEndiannessTest.java index 0d532669a10..dc28c5a33c2 100644 --- a/test/jdk/java/net/httpclient/websocket/WebSocketEndiannessTest.java +++ b/test/jdk/java/net/httpclient/websocket/WebSocketEndiannessTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,7 @@ * @library /test/lib * @build DummyWebSocketServer * jdk.test.lib.Asserts - * @run main WebSocketEndiannessTest + * @run main ${test.main.class} */ import jdk.internal.net.http.websocket.Frame; diff --git a/test/jdk/java/net/httpclient/websocket/WebSocketExtendedTest.java b/test/jdk/java/net/httpclient/websocket/WebSocketExtendedTest.java index 56474555235..e0096a55297 100644 --- a/test/jdk/java/net/httpclient/websocket/WebSocketExtendedTest.java +++ b/test/jdk/java/net/httpclient/websocket/WebSocketExtendedTest.java @@ -28,7 +28,7 @@ * -Djdk.internal.httpclient.websocket.debug=true * -Djdk.internal.httpclient.debug=true * -Djdk.httpclient.websocket.writeBufferSize=1024 - * -Djdk.httpclient.websocket.intermediateBufferSize=2048 WebSocketExtendedTest + * -Djdk.httpclient.websocket.intermediateBufferSize=2048 ${test.main.class} */ import jdk.internal.net.http.websocket.Frame; diff --git a/test/jdk/java/net/httpclient/websocket/WebSocketProxyTest.java b/test/jdk/java/net/httpclient/websocket/WebSocketProxyTest.java index a410aa9fe75..d3aa4d96866 100644 --- a/test/jdk/java/net/httpclient/websocket/WebSocketProxyTest.java +++ b/test/jdk/java/net/httpclient/websocket/WebSocketProxyTest.java @@ -33,7 +33,7 @@ * -Djdk.internal.httpclient.websocket.debug=true * -Djdk.httpclient.HttpClient.log=errors,requests,headers * -Djdk.http.auth.tunneling.disabledSchemes= - * WebSocketProxyTest + * ${test.main.class} */ import java.io.IOException; diff --git a/test/jdk/java/net/httpclient/websocket/WebSocketTest.java b/test/jdk/java/net/httpclient/websocket/WebSocketTest.java index 2b1df3d7e87..4d395d9195e 100644 --- a/test/jdk/java/net/httpclient/websocket/WebSocketTest.java +++ b/test/jdk/java/net/httpclient/websocket/WebSocketTest.java @@ -28,7 +28,7 @@ * @build DummyWebSocketServer * java.net.http/jdk.internal.net.http.HttpClientTimerAccess * @run junit/othervm - * WebSocketTest + * ${test.main.class} */ diff --git a/test/jdk/java/net/httpclient/websocket/security/WSSanityTest.java b/test/jdk/java/net/httpclient/websocket/security/WSSanityTest.java index c8e4faa1ad3..7e9e296aa9d 100644 --- a/test/jdk/java/net/httpclient/websocket/security/WSSanityTest.java +++ b/test/jdk/java/net/httpclient/websocket/security/WSSanityTest.java @@ -25,7 +25,7 @@ * @test * @summary Basic sanity checks for WebSocket URI from the Builder * @compile ../DummyWebSocketServer.java ../../ProxyServer.java - * @run junit/othervm WSSanityTest + * @run junit/othervm ${test.main.class} */ import java.io.IOException; diff --git a/test/jdk/java/net/httpclient/whitebox/AltSvcFrameTest.java b/test/jdk/java/net/httpclient/whitebox/AltSvcFrameTest.java index b9e5f2d58fe..e4c3aeffac3 100644 --- a/test/jdk/java/net/httpclient/whitebox/AltSvcFrameTest.java +++ b/test/jdk/java/net/httpclient/whitebox/AltSvcFrameTest.java @@ -89,7 +89,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; * -Djdk.httpclient.HttpClient.log=headers * -Djdk.internal.httpclient.disableHostnameVerification * -Djdk.internal.httpclient.debug=true - * AltSvcFrameTest + * ${test.main.class} */ public class AltSvcFrameTest { diff --git a/test/jdk/java/net/httpclient/whitebox/AltSvcRegistryTest.java b/test/jdk/java/net/httpclient/whitebox/AltSvcRegistryTest.java index 682082ba9f8..7e7b2ba6bf3 100644 --- a/test/jdk/java/net/httpclient/whitebox/AltSvcRegistryTest.java +++ b/test/jdk/java/net/httpclient/whitebox/AltSvcRegistryTest.java @@ -80,7 +80,7 @@ import org.junit.jupiter.api.Test; * -Djdk.httpclient.HttpClient.log=headers * -Djdk.internal.httpclient.disableHostnameVerification * -Djdk.internal.httpclient.debug=true - * AltSvcRegistryTest + * ${test.main.class} */ public class AltSvcRegistryTest implements HttpServerAdapters { From 289f3e2f6236e7b80c16443d5c3547b3c28010fe Mon Sep 17 00:00:00 2001 From: Kieran Farrell Date: Thu, 9 Apr 2026 11:06:58 +0000 Subject: [PATCH 221/359] 8381184: Code clean up: missing line break and print out duplication Reviewed-by: dholmes, kevinw --- src/hotspot/os/linux/os_linux.cpp | 2 -- src/hotspot/share/utilities/vmError.cpp | 3 +-- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index bf096897aa7..a87c0ab33fa 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -2163,8 +2163,6 @@ void os::print_os_info(outputStream* st) { os::Posix::print_rlimit_info(st); - os::print_open_file_descriptors(st); - os::Posix::print_load_average(st); st->cr(); diff --git a/src/hotspot/share/utilities/vmError.cpp b/src/hotspot/share/utilities/vmError.cpp index d78fd331b56..1cecdc0cb33 100644 --- a/src/hotspot/share/utilities/vmError.cpp +++ b/src/hotspot/share/utilities/vmError.cpp @@ -1327,13 +1327,13 @@ void VMError::report(outputStream* st, bool _verbose) { STEP_IF("printing OS information", _verbose) os::print_os_info(st); - st->cr(); #ifdef __APPLE__ // Avoid large stack allocation on Mac for FD count during signal-handling. os::Bsd::print_open_file_descriptors(st, buf, sizeof(buf)); st->cr(); #else os::print_open_file_descriptors(st); + st->cr(); #endif STEP_IF("printing CPU info", _verbose) @@ -1553,7 +1553,6 @@ void VMError::print_vm_info(outputStream* st) { // STEP("printing OS information") os::print_os_info(st); - st->cr(); os::print_open_file_descriptors(st); st->cr(); From 31b58871fc13739c91b1d648670e5303d67bd9b0 Mon Sep 17 00:00:00 2001 From: Daishi Tabata Date: Thu, 9 Apr 2026 13:43:48 +0000 Subject: [PATCH 222/359] 8381566: G1: Concurrent refinement pre-sweep time logged as incorrect negative value Reviewed-by: tschatzl, ayang --- src/hotspot/share/gc/g1/g1ConcurrentRefine.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1ConcurrentRefine.cpp b/src/hotspot/share/gc/g1/g1ConcurrentRefine.cpp index 8546e6e2d64..e12a8c284de 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentRefine.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentRefine.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -326,11 +326,14 @@ bool G1ConcurrentRefineSweepState::complete_work(bool concurrent, bool print_log if (print_log) { G1ConcurrentRefineStats* s = &_stats; - log_debug(gc, refine)("Refinement took %.2fms (pre-sweep %.2fms card refine %.2f) " + State state_bounded_by_sweeprt = (_state == State::SweepRT || _state == State::CompleteRefineWork) + ? State::SweepRT : _state; + + log_debug(gc, refine)("Refinement took %.2fms (pre-sweep %.2fms card refine %.2fms) " "(scanned %zu clean %zu (%.2f%%) not_clean %zu (%.2f%%) not_parsable %zu " "refers_to_cset %zu (%.2f%%) still_refers_to_cset %zu (%.2f%%) no_cross_region %zu pending %zu)", get_duration(State::Idle, _state).seconds() * 1000.0, - get_duration(State::Idle, State::SweepRT).seconds() * 1000.0, + get_duration(State::Idle, state_bounded_by_sweeprt).seconds() * 1000.0, TimeHelper::counter_to_millis(s->refine_duration()), s->cards_scanned(), s->cards_clean(), From 81cc497e6efb97c26dbccac63786864047e5c443 Mon Sep 17 00:00:00 2001 From: Ashutosh Mehra Date: Thu, 9 Apr 2026 13:51:18 +0000 Subject: [PATCH 223/359] 8381819: Test compiler/cpuflags/TestAESIntrinsicsOnUnsupportedConfig.java fails after JDK-8364584 Reviewed-by: kvn, mbaesken --- src/hotspot/cpu/x86/vm_version_x86.cpp | 20 +++++++++---------- .../share/runtime/abstract_vm_version.hpp | 2 +- .../TestAESIntrinsicsOnSupportedConfig.java | 1 - .../TestAESIntrinsicsOnUnsupportedConfig.java | 2 +- 4 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/hotspot/cpu/x86/vm_version_x86.cpp b/src/hotspot/cpu/x86/vm_version_x86.cpp index d8f998520d1..39a9c618350 100644 --- a/src/hotspot/cpu/x86/vm_version_x86.cpp +++ b/src/hotspot/cpu/x86/vm_version_x86.cpp @@ -1207,16 +1207,7 @@ void VM_Version::get_processor_features() { } } } else { - if (!UseAES) { - if (UseAESIntrinsics && !FLAG_IS_DEFAULT(UseAESIntrinsics)) { - warning("AES intrinsics require UseAES flag to be enabled. Intrinsics will be disabled."); - } - FLAG_SET_DEFAULT(UseAESIntrinsics, false); - if (UseAESCTRIntrinsics && !FLAG_IS_DEFAULT(UseAESCTRIntrinsics)) { - warning("AES_CTR intrinsics require UseAES flag to be enabled. AES_CTR intrinsics will be disabled."); - } - FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false); - } else if (!cpu_supports_aes()) { + if (!cpu_supports_aes()) { if (UseAESIntrinsics && !FLAG_IS_DEFAULT(UseAESIntrinsics)) { warning("AES intrinsics are not available on this CPU"); } @@ -1225,6 +1216,15 @@ void VM_Version::get_processor_features() { warning("AES-CTR intrinsics are not available on this CPU"); } FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false); + } else if (!UseAES) { + if (UseAESIntrinsics && !FLAG_IS_DEFAULT(UseAESIntrinsics)) { + warning("AES intrinsics require UseAES flag to be enabled. Intrinsics will be disabled."); + } + FLAG_SET_DEFAULT(UseAESIntrinsics, false); + if (UseAESCTRIntrinsics && !FLAG_IS_DEFAULT(UseAESCTRIntrinsics)) { + warning("AES_CTR intrinsics require UseAES flag to be enabled. AES_CTR intrinsics will be disabled."); + } + FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false); } } diff --git a/src/hotspot/share/runtime/abstract_vm_version.hpp b/src/hotspot/share/runtime/abstract_vm_version.hpp index 61a8aa84080..794fa4dabcf 100644 --- a/src/hotspot/share/runtime/abstract_vm_version.hpp +++ b/src/hotspot/share/runtime/abstract_vm_version.hpp @@ -55,7 +55,7 @@ enum class vmIntrinsicID; } \ } else if (Use##feature) { \ if (!FLAG_IS_DEFAULT(Use##feature)) { \ - warning(#feature " instructions not available on this CPU"); \ + warning(#feature " instructions are not available on this CPU"); \ } \ FLAG_SET_DEFAULT(Use##feature, false); \ } diff --git a/test/hotspot/jtreg/compiler/cpuflags/TestAESIntrinsicsOnSupportedConfig.java b/test/hotspot/jtreg/compiler/cpuflags/TestAESIntrinsicsOnSupportedConfig.java index 421307e85ca..b3aa0283fa5 100644 --- a/test/hotspot/jtreg/compiler/cpuflags/TestAESIntrinsicsOnSupportedConfig.java +++ b/test/hotspot/jtreg/compiler/cpuflags/TestAESIntrinsicsOnSupportedConfig.java @@ -26,7 +26,6 @@ * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management - * @requires (vm.cpu.features ~= ".*aes.*" | vm.cpu.features ~= ".*zvkn.*") & !vm.graal.enabled * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm/timeout=600 -Xbootclasspath/a:. diff --git a/test/hotspot/jtreg/compiler/cpuflags/TestAESIntrinsicsOnUnsupportedConfig.java b/test/hotspot/jtreg/compiler/cpuflags/TestAESIntrinsicsOnUnsupportedConfig.java index 50677f5197e..7fc6d7f86c1 100644 --- a/test/hotspot/jtreg/compiler/cpuflags/TestAESIntrinsicsOnUnsupportedConfig.java +++ b/test/hotspot/jtreg/compiler/cpuflags/TestAESIntrinsicsOnUnsupportedConfig.java @@ -81,7 +81,7 @@ public class TestAESIntrinsicsOnUnsupportedConfig extends AESIntrinsicsBase { /** * Test checks following situation:
- * UseAESIntrinsics flag is set to true, TestAESMain is executed
+ * UseAES flag is set to true, TestAESMain is executed
* Expected result: UseAES flag is set to false
* UseAES flag is set to false
* Output shouldn't contain intrinsics usage
From 9df6054d432157284bc5f099a73be538aef61711 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eirik=20Bj=C3=B8rsn=C3=B8s?= Date: Thu, 9 Apr 2026 13:52:13 +0000 Subject: [PATCH 224/359] 8380450: (zipfs) ZipFileSystem::getPath and ZipPath::resolve throw unspecified IllegalArgumentException for unmappable names Reviewed-by: lancea --- .../classes/jdk/nio/zipfs/ZipFileSystem.java | 6 +- .../jdk/jdk/nio/zipfs/UnmappablePathName.java | 118 ++++++++++++++++++ 2 files changed, 123 insertions(+), 1 deletion(-) create mode 100644 test/jdk/jdk/nio/zipfs/UnmappablePathName.java diff --git a/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java b/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java index 3223ff9dccd..0280f7c33bb 100644 --- a/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java +++ b/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java @@ -1246,7 +1246,11 @@ class ZipFileSystem extends FileSystem { private LinkedHashMap inodes; final byte[] getBytes(String name) { - return zc.getBytes(name); + try { + return zc.getBytes(name); + } catch (IllegalArgumentException e) { + throw new InvalidPathException(name, "unmappable character in path name"); + } } final String getString(byte[] name) { diff --git a/test/jdk/jdk/nio/zipfs/UnmappablePathName.java b/test/jdk/jdk/nio/zipfs/UnmappablePathName.java new file mode 100644 index 00000000000..3fe915734eb --- /dev/null +++ b/test/jdk/jdk/nio/zipfs/UnmappablePathName.java @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.net.URI; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.nio.file.*; +import java.util.HashMap; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +/* @test + * @bug 8380450 + * @summary Unmappable characters in ZipFileSystem path names should be rejected with InvalidPathException + * @run junit ${test.main.class} + */ +public class UnmappablePathName { + + // Charset used when creating the ZipFileSystem used in this test + static final Charset CHARSET = StandardCharsets.US_ASCII; + // 'ø' is an unmappable character in US_ASCII + static final String UNMAPPABLE = "\u00f8"; + // ZIP file created in this test + static final Path ZIP = Paths.get("unmappable-path.zip"); + + /** + * Verify that calling ZipFileSystem.getPath with an unmappable path + * name is rejected with an InvalidPathException. + * + * @throws IOException if an unexpected IO error occurs + */ + @Test + void unmappableGetPath() throws IOException { + try (FileSystem fs = createFileSystem(ZIP, CHARSET)) { + assertThrows(InvalidPathException.class, () -> fs.getPath(UNMAPPABLE)); + } + } + + /** + * Verify that calling ZipFileSystem.getPath with a partially unmappable path + * name is rejected with an InvalidPathException. + * + * @throws IOException if an unexpected IO error occurs + */ + @Test + void unmappableGetPathPartial() throws IOException { + try (FileSystem fs = createFileSystem(ZIP, CHARSET)) { + assertThrows(InvalidPathException.class, () -> fs.getPath("mappable", UNMAPPABLE)); + } + } + + /** + * Verify that calling ZipPath::resolve with an unmappable path + * name is rejected with an InvalidPathException. + * + * @throws IOException if an unexpected IO error occurs + */ + @Test + void unmappableResolve() throws IOException { + try (FileSystem fs = createFileSystem(ZIP, CHARSET)) { + Path path = fs.getPath("mappable"); + assertThrows(InvalidPathException.class, () -> path.resolve(UNMAPPABLE)); + } + } + + /** + * Verify that calling ZipPath::resolve with a partially unmappable path + * name is rejected with an InvalidPathException. + * + * @throws IOException if an unexpected IO error occurs + */ + @Test + void unmappableResolvePartial() throws IOException { + try (FileSystem fs = createFileSystem(ZIP, CHARSET)) { + Path path = fs.getPath("mappable"); + assertThrows(InvalidPathException.class, () -> path.resolve("mappable", UNMAPPABLE)); + } + } + + @AfterEach + void cleanup() throws IOException { + Files.deleteIfExists(ZIP); + } + + // Create a ZipFileSystem using the specified charset + private FileSystem createFileSystem(Path path, Charset charset) throws IOException { + URI uri = URI.create("jar:" + path.toUri()); + Map env = new HashMap(); + env.put("create", "true"); + env.put("encoding", charset.name()); + return FileSystems.newFileSystem(uri, env); + } +} From d471f474994b868bbfb2d18a10f6996c900a59bc Mon Sep 17 00:00:00 2001 From: Ashutosh Mehra Date: Thu, 9 Apr 2026 13:56:27 +0000 Subject: [PATCH 225/359] 8381807: AArch64: compiler/cpuflags/CPUFeaturesClearTest.java fails on SVE after JDK-8364584 Reviewed-by: kvn, haosun, adinn --- test/hotspot/jtreg/compiler/cpuflags/CPUFeaturesClearTest.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/hotspot/jtreg/compiler/cpuflags/CPUFeaturesClearTest.java b/test/hotspot/jtreg/compiler/cpuflags/CPUFeaturesClearTest.java index a0fb3525381..19768a8dc17 100644 --- a/test/hotspot/jtreg/compiler/cpuflags/CPUFeaturesClearTest.java +++ b/test/hotspot/jtreg/compiler/cpuflags/CPUFeaturesClearTest.java @@ -123,12 +123,10 @@ public class CPUFeaturesClearTest { if (isCpuFeatureSupported("sve2")) { outputAnalyzer = ProcessTools.executeTestJava(generateArgs(prepareNumericFlag("UseSVE", 1))); outputAnalyzer.shouldNotMatch("[os,cpu] CPU: .* sve2.*"); - verifyOutput(null, new String[]{"sve2"}, null, outputAnalyzer); } if (isCpuFeatureSupported("sve")) { outputAnalyzer = ProcessTools.executeTestJava(generateArgs(prepareNumericFlag("UseSVE", 0))); outputAnalyzer.shouldNotMatch("[os,cpu] CPU: .* sve.*"); - verifyOutput(null, new String[]{"sve"}, null, outputAnalyzer); } } From 9a1f7d4ae3eec63a0f156d9eaa922b590d6d6fb6 Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Thu, 9 Apr 2026 16:06:38 +0000 Subject: [PATCH 226/359] 8326205: Grouping frequently called C2 nmethods in CodeCache Co-authored-by: Evgeny Astigeevich Reviewed-by: kvn, cslucas, aph --- src/hotspot/share/code/codeBlob.hpp | 7 +- src/hotspot/share/code/codeCache.cpp | 95 +++++-- src/hotspot/share/code/codeCache.hpp | 8 +- src/hotspot/share/code/nmethod.cpp | 13 + .../share/compiler/compilerDefinitions.cpp | 32 ++- src/hotspot/share/logging/logTag.hpp | 1 + src/hotspot/share/opto/c2_globals.hpp | 38 +++ src/hotspot/share/runtime/globals.hpp | 4 + .../share/runtime/hotCodeCollector.cpp | 258 ++++++++++++++++++ .../share/runtime/hotCodeCollector.hpp | 56 ++++ src/hotspot/share/runtime/hotCodeSampler.cpp | 121 ++++++++ src/hotspot/share/runtime/hotCodeSampler.hpp | 104 +++++++ src/hotspot/share/runtime/threads.cpp | 7 + .../MHIntrinsicAllocFailureTest.java | 12 +- .../codecache/OverflowCodeCacheTest.java | 52 +++- .../cli/TestSegmentedCodeCacheOption.java | 56 +++- .../GenericCodeHeapSizeRunner.java | 10 +- .../codeheapsize/TestCodeHeapSizeOptions.java | 16 +- .../cli/common/CodeCacheCLITestBase.java | 10 +- .../cli/common/CodeCacheCLITestCase.java | 58 +++- .../cli/common/CodeCacheOptions.java | 34 ++- .../TestPrintCodeCacheOption.java | 14 +- .../compiler/codecache/jmx/BeanTypeTest.java | 22 +- .../jmx/CodeHeapBeanPresenceTest.java | 22 +- .../compiler/codecache/jmx/GetUsageTest.java | 24 +- .../codecache/jmx/InitialAndMaxUsageTest.java | 24 +- .../codecache/jmx/ManagerNamesTest.java | 22 +- .../jmx/MemoryPoolsPresenceTest.java | 22 +- .../compiler/codecache/jmx/PeakUsageTest.java | 23 +- .../codecache/jmx/PoolsIndependenceTest.java | 22 +- .../jmx/ThresholdNotificationsTest.java | 22 +- ...sageThresholdExceededSeveralTimesTest.java | 25 +- .../jmx/UsageThresholdExceededTest.java | 29 +- .../jmx/UsageThresholdIncreasedTest.java | 24 +- .../jmx/UsageThresholdNotExceededTest.java | 25 +- .../stress/RandomAllocationTest.java | 23 ++ .../hotcode/HotCodeCollectorMoveFunction.java | 88 ++++++ .../hotcode/StressHotCodeCollector.java | 167 ++++++++++++ .../jfr/event/compiler/TestCodeCacheFull.java | 6 + test/lib/jdk/test/whitebox/code/BlobType.java | 16 +- 40 files changed, 1537 insertions(+), 75 deletions(-) create mode 100644 src/hotspot/share/runtime/hotCodeCollector.cpp create mode 100644 src/hotspot/share/runtime/hotCodeCollector.hpp create mode 100644 src/hotspot/share/runtime/hotCodeSampler.cpp create mode 100644 src/hotspot/share/runtime/hotCodeSampler.hpp create mode 100644 test/hotspot/jtreg/compiler/hotcode/HotCodeCollectorMoveFunction.java create mode 100644 test/hotspot/jtreg/compiler/hotcode/StressHotCodeCollector.java diff --git a/src/hotspot/share/code/codeBlob.hpp b/src/hotspot/share/code/codeBlob.hpp index 6a1686b80e2..1c6904e7446 100644 --- a/src/hotspot/share/code/codeBlob.hpp +++ b/src/hotspot/share/code/codeBlob.hpp @@ -45,9 +45,10 @@ class OopMapSet; enum class CodeBlobType { MethodNonProfiled = 0, // Execution level 1 and 4 (non-profiled) nmethods (including native nmethods) MethodProfiled = 1, // Execution level 2 and 3 (profiled) nmethods - NonNMethod = 2, // Non-nmethods like Buffers, Adapters and Runtime Stubs - All = 3, // All types (No code cache segmentation) - NumTypes = 4 // Number of CodeBlobTypes + MethodHot = 2, // Nmethods predicted to be always hot + NonNMethod = 3, // Non-nmethods like Buffers, Adapters and Runtime Stubs + All = 4, // All types (No code cache segmentation) + NumTypes = 5 // Number of CodeBlobTypes }; // CodeBlob - superclass for all entries in the CodeCache. diff --git a/src/hotspot/share/code/codeCache.cpp b/src/hotspot/share/code/codeCache.cpp index 2a0256cc316..c0b4918102e 100644 --- a/src/hotspot/share/code/codeCache.cpp +++ b/src/hotspot/share/code/codeCache.cpp @@ -201,6 +201,7 @@ void CodeCache::initialize_heaps() { CodeHeapInfo non_nmethod = {NonNMethodCodeHeapSize, FLAG_IS_CMDLINE(NonNMethodCodeHeapSize), true}; CodeHeapInfo profiled = {ProfiledCodeHeapSize, FLAG_IS_CMDLINE(ProfiledCodeHeapSize), true}; CodeHeapInfo non_profiled = {NonProfiledCodeHeapSize, FLAG_IS_CMDLINE(NonProfiledCodeHeapSize), true}; + CodeHeapInfo hot = {HotCodeHeapSize, FLAG_IS_CMDLINE(HotCodeHeapSize), true}; const bool cache_size_set = FLAG_IS_CMDLINE(ReservedCodeCacheSize); const size_t ps = page_size(false, 8); @@ -219,6 +220,12 @@ void CodeCache::initialize_heaps() { profiled.enabled = false; } + if (!heap_available(CodeBlobType::MethodHot)) { + hot.size = 0; + hot.set = true; + hot.enabled = false; + } + assert(heap_available(CodeBlobType::MethodNonProfiled), "MethodNonProfiled heap is always available for segmented code heap"); size_t compiler_buffer_size = 0; @@ -238,14 +245,36 @@ void CodeCache::initialize_heaps() { set_size_of_unset_code_heap(&non_profiled, cache_size, non_nmethod.size + profiled.size, min_size); } - if (!profiled.set && non_profiled.set) { - set_size_of_unset_code_heap(&profiled, cache_size, non_nmethod.size + non_profiled.size, min_size); + if (!profiled.set && non_profiled.set && hot.set) { + set_size_of_unset_code_heap(&profiled, cache_size, non_nmethod.size + non_profiled.size + hot.size, min_size); + } + + if (hot.enabled) { + if (!hot.set) { + assert(hot.size == 0, "must be calculated during heaps initialization"); + // An application usually has ~20% hot code which is mostly non-profiled code. + // We set the hot code heap size to 20% of the non-profiled code heap. + hot.size = MAX2(non_profiled.size / 5, min_size); + + if (non_profiled.set) { + err_msg msg("Must manually set HotCodeHeapSize when NonProfiledCodeHeapSize is set"); + vm_exit_during_initialization("Invalid code heap sizes", msg); + } + + non_profiled.size -= hot.size; + } + + if (hot.size > non_profiled.size) { + err_msg msg("Hot (%zuK) exceeds NonProfiled (%zuK).", + hot.size / K, non_profiled.size / K); + vm_exit_during_initialization("Invalid code heap sizes", msg); + } } // Compatibility. size_t non_nmethod_min_size = min_cache_size + compiler_buffer_size; - if (!non_nmethod.set && profiled.set && non_profiled.set) { - set_size_of_unset_code_heap(&non_nmethod, cache_size, profiled.size + non_profiled.size, non_nmethod_min_size); + if (!non_nmethod.set && profiled.set && non_profiled.set && hot.set) { + set_size_of_unset_code_heap(&non_nmethod, cache_size, profiled.size + non_profiled.size + hot.size, non_nmethod_min_size); } // Note: if large page support is enabled, min_size is at least the large @@ -253,8 +282,9 @@ void CodeCache::initialize_heaps() { non_nmethod.size = align_up(non_nmethod.size, min_size); profiled.size = align_up(profiled.size, min_size); non_profiled.size = align_up(non_profiled.size, min_size); + hot.size = align_up(hot.size, min_size); - size_t aligned_total = non_nmethod.size + profiled.size + non_profiled.size; + size_t aligned_total = non_nmethod.size + profiled.size + non_profiled.size + hot.size; if (!cache_size_set) { // If ReservedCodeCacheSize is explicitly set and exceeds CODE_CACHE_SIZE_LIMIT, // it is rejected by flag validation elsewhere. Here we only handle the case @@ -262,15 +292,15 @@ void CodeCache::initialize_heaps() { // sizes (after alignment) exceed the platform limit. if (aligned_total > CODE_CACHE_SIZE_LIMIT) { err_msg message("ReservedCodeCacheSize (%zuK), Max (%zuK)." - "Segments: NonNMethod (%zuK), NonProfiled (%zuK), Profiled (%zuK).", + "Segments: NonNMethod (%zuK), NonProfiled (%zuK), Profiled (%zuK), Hot (%zuK).", aligned_total/K, CODE_CACHE_SIZE_LIMIT/K, - non_nmethod.size/K, non_profiled.size/K, profiled.size/K); + non_nmethod.size/K, non_profiled.size/K, profiled.size/K, hot.size/K); vm_exit_during_initialization("Code cache size exceeds platform limit", message); } if (aligned_total != cache_size) { log_info(codecache)("ReservedCodeCache size %zuK changed to total segments size NonNMethod " - "%zuK NonProfiled %zuK Profiled %zuK = %zuK", - cache_size/K, non_nmethod.size/K, non_profiled.size/K, profiled.size/K, aligned_total/K); + "%zuK NonProfiled %zuK Profiled %zuK Hot %zuK = %zuK", + cache_size/K, non_nmethod.size/K, non_profiled.size/K, profiled.size/K, hot.size/K, aligned_total/K); // Adjust ReservedCodeCacheSize as necessary because it was not set explicitly cache_size = aligned_total; } @@ -295,19 +325,23 @@ void CodeCache::initialize_heaps() { } if (profiled.enabled && !profiled.set && profiled.size > min_size) { profiled.size -= min_size; + if (--delta == 0) break; + } + if (hot.enabled && !hot.set && hot.size > min_size) { + hot.size -= min_size; delta--; } if (delta == start_delta) { break; } } - aligned_total = non_nmethod.size + profiled.size + non_profiled.size; + aligned_total = non_nmethod.size + profiled.size + non_profiled.size + hot.size; } } log_debug(codecache)("Initializing code heaps ReservedCodeCache %zuK NonNMethod %zuK" - " NonProfiled %zuK Profiled %zuK", - cache_size/K, non_nmethod.size/K, non_profiled.size/K, profiled.size/K); + " NonProfiled %zuK Profiled %zuK Hot %zuK", + cache_size/K, non_nmethod.size/K, non_profiled.size/K, profiled.size/K, hot.size/K); // Validation // Check minimal required sizes @@ -318,6 +352,9 @@ void CodeCache::initialize_heaps() { if (non_profiled.enabled) { // non_profiled.enabled is always ON for segmented code heap, leave it checked for clarity check_min_size("non-profiled code heap", non_profiled.size, min_size); } + if (hot.enabled) { + check_min_size("hot code heap", hot.size, min_size); + } // ReservedCodeCacheSize was set explicitly, so report an error and abort if it doesn't match the segment sizes if (aligned_total != cache_size && cache_size_set) { @@ -328,6 +365,9 @@ void CodeCache::initialize_heaps() { if (non_profiled.enabled) { message.append(" + NonProfiledCodeHeapSize (%zuK)", non_profiled.size/K); } + if (hot.enabled) { + message.append(" + HotCodeHeapSize (%zuK)", hot.size/K); + } message.append(" = %zuK", aligned_total/K); message.append((aligned_total > cache_size) ? " is greater than " : " is less than "); message.append("ReservedCodeCacheSize (%zuK).", cache_size/K); @@ -348,6 +388,7 @@ void CodeCache::initialize_heaps() { FLAG_SET_ERGO(NonNMethodCodeHeapSize, non_nmethod.size); FLAG_SET_ERGO(ProfiledCodeHeapSize, profiled.size); FLAG_SET_ERGO(NonProfiledCodeHeapSize, non_profiled.size); + FLAG_SET_ERGO(HotCodeHeapSize, hot.size); FLAG_SET_ERGO(ReservedCodeCacheSize, cache_size); ReservedSpace rs = reserve_heap_memory(cache_size, ps); @@ -368,6 +409,13 @@ void CodeCache::initialize_heaps() { // Non-nmethods (stubs, adapters, ...) add_heap(non_method_space, "CodeHeap 'non-nmethods'", CodeBlobType::NonNMethod); + if (hot.enabled) { + ReservedSpace hot_space = rs.partition(offset, hot.size); + offset += hot.size; + // Nmethods known to be always hot. + add_heap(hot_space, "CodeHeap 'hot nmethods'", CodeBlobType::MethodHot); + } + if (non_profiled.enabled) { ReservedSpace non_profiled_space = rs.partition(offset, non_profiled.size); // Tier 1 and tier 4 (non-profiled) methods and native methods @@ -406,16 +454,25 @@ bool CodeCache::heap_available(CodeBlobType code_blob_type) { // Interpreter only: we don't need any method code heaps return (code_blob_type == CodeBlobType::NonNMethod); } else if (CompilerConfig::is_c1_profiling()) { - // Tiered compilation: use all code heaps + // Tiered compilation: use all code heaps including + // the hot code heap when it is present. + + if (COMPILER2_PRESENT(!HotCodeHeap &&) (code_blob_type == CodeBlobType::MethodHot)) { + return false; + } + return (code_blob_type < CodeBlobType::All); } else { // No TieredCompilation: we only need the non-nmethod and non-profiled code heap + // and the hot code heap if it is requested. return (code_blob_type == CodeBlobType::NonNMethod) || - (code_blob_type == CodeBlobType::MethodNonProfiled); + (code_blob_type == CodeBlobType::MethodNonProfiled) + COMPILER2_PRESENT(|| ((code_blob_type == CodeBlobType::MethodHot) && HotCodeHeap)); } } -const char* CodeCache::get_code_heap_flag_name(CodeBlobType code_blob_type) { +// Returns the name of the VM option to set the size of the corresponding CodeHeap +static const char* get_code_heap_flag_name(CodeBlobType code_blob_type) { switch(code_blob_type) { case CodeBlobType::NonNMethod: return "NonNMethodCodeHeapSize"; @@ -426,6 +483,9 @@ const char* CodeCache::get_code_heap_flag_name(CodeBlobType code_blob_type) { case CodeBlobType::MethodProfiled: return "ProfiledCodeHeapSize"; break; + case CodeBlobType::MethodHot: + return "HotCodeHeapSize"; + break; default: ShouldNotReachHere(); return nullptr; @@ -542,7 +602,7 @@ CodeBlob* CodeCache::allocate(uint size, CodeBlobType code_blob_type, bool handl // Get CodeHeap for the given CodeBlobType CodeHeap* heap = get_code_heap(code_blob_type); - assert(heap != nullptr, "heap is null"); + assert(heap != nullptr, "No heap for given code_blob_type (%d), heap is null", (int)code_blob_type); while (true) { cb = (CodeBlob*)heap->allocate(size); @@ -570,6 +630,9 @@ CodeBlob* CodeCache::allocate(uint size, CodeBlobType code_blob_type, bool handl type = CodeBlobType::MethodNonProfiled; } break; + case CodeBlobType::MethodHot: + type = CodeBlobType::MethodNonProfiled; + break; default: break; } diff --git a/src/hotspot/share/code/codeCache.hpp b/src/hotspot/share/code/codeCache.hpp index 349cc652bf4..6384cb397b8 100644 --- a/src/hotspot/share/code/codeCache.hpp +++ b/src/hotspot/share/code/codeCache.hpp @@ -118,10 +118,6 @@ class CodeCache : AllStatic { // Creates a new heap with the given name and size, containing CodeBlobs of the given type static void add_heap(ReservedSpace rs, const char* name, CodeBlobType code_blob_type); static CodeHeap* get_code_heap_containing(void* p); // Returns the CodeHeap containing the given pointer, or nullptr - static CodeHeap* get_code_heap(const void* cb); // Returns the CodeHeap for the given CodeBlob - static CodeHeap* get_code_heap(CodeBlobType code_blob_type); // Returns the CodeHeap for the given CodeBlobType - // Returns the name of the VM option to set the size of the corresponding CodeHeap - static const char* get_code_heap_flag_name(CodeBlobType code_blob_type); static ReservedSpace reserve_heap_memory(size_t size, size_t rs_ps); // Reserves one continuous chunk of memory for the CodeHeaps // Iteration @@ -145,6 +141,8 @@ class CodeCache : AllStatic { static int code_heap_compare(CodeHeap* const &lhs, CodeHeap* const &rhs); static void add_heap(CodeHeap* heap); + static CodeHeap* get_code_heap(const void* cb); // Returns the CodeHeap for the given CodeBlob + static CodeHeap* get_code_heap(CodeBlobType code_blob_type); // Returns the CodeHeap for the given CodeBlobType static const GrowableArray* heaps() { return _heaps; } static const GrowableArray* nmethod_heaps() { return _nmethod_heaps; } @@ -264,7 +262,7 @@ class CodeCache : AllStatic { } static bool code_blob_type_accepts_nmethod(CodeBlobType type) { - return type == CodeBlobType::All || type <= CodeBlobType::MethodProfiled; + return type == CodeBlobType::All || type <= CodeBlobType::MethodHot; } static bool code_blob_type_accepts_allocable(CodeBlobType type) { diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index a302df418d7..815c0c7b4b0 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -66,6 +66,9 @@ #include "runtime/flags/flagSetting.hpp" #include "runtime/frame.inline.hpp" #include "runtime/handles.inline.hpp" +#ifdef COMPILER2 +#include "runtime/hotCodeCollector.hpp" +#endif // COMPILER2 #include "runtime/icache.hpp" #include "runtime/jniHandles.inline.hpp" #include "runtime/orderAccess.hpp" @@ -1258,6 +1261,11 @@ void nmethod::post_init() { ICache::invalidate_range(code_begin(), code_size()); Universe::heap()->register_nmethod(this); + +#ifdef COMPILER2 + HotCodeCollector::register_nmethod(this); +#endif // COMPILER2 + DEBUG_ONLY(Universe::heap()->verify_nmethod(this)); CodeCache::commit(this); @@ -2476,6 +2484,11 @@ void nmethod::purge(bool unregister_nmethod) { if (unregister_nmethod) { Universe::heap()->unregister_nmethod(this); } + +#ifdef COMPILER2 + HotCodeCollector::unregister_nmethod(this); +#endif // COMPILER2 + CodeCache::unregister_old_nmethod(this); JVMCI_ONLY( _metadata_size = 0; ) diff --git a/src/hotspot/share/compiler/compilerDefinitions.cpp b/src/hotspot/share/compiler/compilerDefinitions.cpp index 0e4e211453b..cf7744cfe03 100644 --- a/src/hotspot/share/compiler/compilerDefinitions.cpp +++ b/src/hotspot/share/compiler/compilerDefinitions.cpp @@ -286,8 +286,38 @@ void CompilerConfig::set_compilation_policy_flags() { } } +#ifdef COMPILER2 + if (HotCodeHeap) { + if (FLAG_IS_DEFAULT(SegmentedCodeCache)) { + FLAG_SET_ERGO(SegmentedCodeCache, true); + } else if (!SegmentedCodeCache) { + vm_exit_during_initialization("HotCodeHeap requires SegmentedCodeCache enabled"); + } + + if (FLAG_IS_DEFAULT(NMethodRelocation)) { + FLAG_SET_ERGO(NMethodRelocation, true); + } else if (!NMethodRelocation) { + vm_exit_during_initialization("HotCodeHeap requires NMethodRelocation enabled"); + } + + if (!is_c2_enabled()) { + vm_exit_during_initialization("HotCodeHeap requires C2 enabled"); + } + + if (HotCodeMinSamplingMs > HotCodeMaxSamplingMs) { + vm_exit_during_initialization("HotCodeMinSamplingMs cannot be larger than HotCodeMaxSamplingMs"); + } + } else if (HotCodeHeapSize > 0) { + vm_exit_during_initialization("HotCodeHeapSize requires HotCodeHeap enabled"); + } +#else + if (HotCodeHeapSize > 0) { + vm_exit_during_initialization("HotCodeHeapSize requires C2 present"); + } +#endif // COMPILER2 + if (CompileThresholdScaling < 0) { - vm_exit_during_initialization("Negative value specified for CompileThresholdScaling", nullptr); + vm_exit_during_initialization("Negative value specified for CompileThresholdScaling"); } if (CompilationModeFlag::disable_intermediate()) { diff --git a/src/hotspot/share/logging/logTag.hpp b/src/hotspot/share/logging/logTag.hpp index 20d61b542b0..2b8d6a72be4 100644 --- a/src/hotspot/share/logging/logTag.hpp +++ b/src/hotspot/share/logging/logTag.hpp @@ -96,6 +96,7 @@ class outputStream; LOG_TAG(heap) \ LOG_TAG(heapdump) \ NOT_PRODUCT(LOG_TAG(heapsampling)) \ + COMPILER2_PRESENT(LOG_TAG(hotcode)) \ LOG_TAG(humongous) \ LOG_TAG(ihop) \ LOG_TAG(iklass) \ diff --git a/src/hotspot/share/opto/c2_globals.hpp b/src/hotspot/share/opto/c2_globals.hpp index 983ac8a32c6..6974d50741e 100644 --- a/src/hotspot/share/opto/c2_globals.hpp +++ b/src/hotspot/share/opto/c2_globals.hpp @@ -914,6 +914,44 @@ \ develop(bool, StressCountedLoop, false, \ "Randomly delay conversion to counted loops") \ + \ + product(bool, HotCodeHeap, false, EXPERIMENTAL, \ + "Enable the code heap for hot C2 nmethods") \ + \ + product(double, HotCodeSamplePercent, 80, EXPERIMENTAL, \ + "Minimum percentage of profiling samples that must be in " \ + "the MethodHot heap before stopping hot code collection") \ + range(0, 100) \ + \ + product(double, HotCodeStablePercent, 5, EXPERIMENTAL, \ + "Maximum percentage of newly compiled to total C2 nmethods " \ + "to treat nmethod count as stable. " \ + "Values less than zero disable the stable check") \ + range(-1, DBL_MAX) \ + \ + product(uint, HotCodeIntervalSeconds, 300, EXPERIMENTAL, \ + "Seconds between hot code grouping attempts") \ + range(0, max_juint) \ + \ + product(uint, HotCodeSampleSeconds, 120, EXPERIMENTAL, \ + "Seconds to sample application threads per grouping attempt") \ + range(0, max_juint) \ + \ + product(uint, HotCodeStartupDelaySeconds, 120, EXPERIMENTAL, \ + "Seconds to delay before starting hot code grouping thread") \ + range(0, max_juint) \ + \ + product(uint, HotCodeMinSamplingMs, 5, EXPERIMENTAL, \ + "Minimum sampling interval in milliseconds") \ + range(0, max_juint) \ + \ + product(uint, HotCodeMaxSamplingMs, 15, EXPERIMENTAL, \ + "Maximum sampling interval in milliseconds") \ + range(0, max_juint) \ + \ + product(uint, HotCodeCallLevel, 1, EXPERIMENTAL, \ + "Number of levels of callees to relocate per candidate") \ + range(0, max_juint) \ // end of C2_FLAGS diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp index b5c19d8aa36..ac1ddec7cbc 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -1514,6 +1514,10 @@ const int ObjectAlignmentInBytes = 8; "Size of code heap with non-nmethods (in bytes)") \ constraint(VMPageSizeConstraintFunc, AtParse) \ \ + product(size_t, HotCodeHeapSize, 0, EXPERIMENTAL, \ + "Size of code heap with predicted hot methods (in bytes)") \ + range(0, SIZE_MAX) \ + \ product_pd(size_t, CodeCacheExpansionSize, \ "Code cache expansion size (in bytes)") \ range(32*K, SIZE_MAX) \ diff --git a/src/hotspot/share/runtime/hotCodeCollector.cpp b/src/hotspot/share/runtime/hotCodeCollector.cpp new file mode 100644 index 00000000000..643cf3a8bbb --- /dev/null +++ b/src/hotspot/share/runtime/hotCodeCollector.cpp @@ -0,0 +1,258 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifdef COMPILER2 + +#include "code/codeCache.hpp" +#include "code/compiledIC.hpp" +#include "compiler/compilerDefinitions.inline.hpp" +#include "logging/log.hpp" +#include "memory/resourceArea.hpp" +#include "runtime/hotCodeCollector.hpp" +#include "runtime/hotCodeSampler.hpp" +#include "runtime/java.hpp" +#include "runtime/javaThread.inline.hpp" + +// Initialize static variables +bool HotCodeCollector::_is_initialized = false; +int HotCodeCollector::_new_c2_nmethods_count = 0; +int HotCodeCollector::_total_c2_nmethods_count = 0; + +HotCodeCollector::HotCodeCollector() : JavaThread(thread_entry) {} + +void HotCodeCollector::initialize() { + EXCEPTION_MARK; + + assert(HotCodeHeap, "HotCodeCollector requires HotCodeHeap enabled"); + assert(CompilerConfig::is_c2_enabled(), "HotCodeCollector requires C2 enabled"); + assert(NMethodRelocation, "HotCodeCollector requires NMethodRelocation enabled"); + assert(HotCodeHeapSize > 0, "HotCodeHeapSize must be non-zero to use HotCodeCollector"); + assert(CodeCache::get_code_heap(CodeBlobType::MethodHot) != nullptr, "MethodHot code heap not found"); + + Handle thread_oop = JavaThread::create_system_thread_object("HotCodeCollectorThread", CHECK); + HotCodeCollector* thread = new HotCodeCollector(); + JavaThread::vm_exit_on_osthread_failure(thread); + JavaThread::start_internal_daemon(THREAD, thread, thread_oop, NormPriority); + + _is_initialized = true; +} + +bool HotCodeCollector::is_nmethod_count_stable() { + if (HotCodeStablePercent < 0) { + log_info(hotcode)("HotCodeStablePercent is less than zero, stable check disabled"); + return true; + } + + MutexLocker ml_CodeCache_lock(CodeCache_lock, Mutex::_no_safepoint_check_flag); + + if (_total_c2_nmethods_count <= 0) { + log_info(hotcode)("No registered C2 nmethods"); + return false; + } + + const double percent_new = 100.0 * _new_c2_nmethods_count / _total_c2_nmethods_count; + bool is_stable_nmethod_count = percent_new <= HotCodeStablePercent; + + log_info(hotcode)("C2 nmethod count %s", is_stable_nmethod_count ? "stable" : "not stable"); + log_debug(hotcode)("C2 nmethod stats: New: %d, Total: %d, Percent new: %f", _new_c2_nmethods_count, _total_c2_nmethods_count, percent_new); + + _new_c2_nmethods_count = 0; + + return is_stable_nmethod_count; +} + +void HotCodeCollector::thread_entry(JavaThread* thread, TRAPS) { + // Initial sleep to allow JVM to warm up + thread->sleep(HotCodeStartupDelaySeconds * 1000); + + while (true) { + ResourceMark rm; + + // Sample application and group hot nmethods if nmethod count is stable + if (is_nmethod_count_stable()) { + log_info(hotcode)("Sampling..."); + + ThreadSampler sampler; + uint64_t start_time = os::javaTimeMillis(); + while (os::javaTimeMillis() - start_time <= HotCodeSampleSeconds * 1000) { + sampler.sample_all_java_threads(); + thread->sleep(rand_sampling_period_ms()); + } + + Candidates candidates(sampler); + do_grouping(candidates); + } + + thread->sleep(HotCodeIntervalSeconds * 1000); + } +} + +void HotCodeCollector::do_grouping(Candidates& candidates) { + int num_relocated = 0; + + // Sort nmethods by increasing sample count so pop() returns the hottest + candidates.sort(); + + while (candidates.has_candidates()) { + + double percent_from_hot = candidates.get_hot_sample_percent(); + log_debug(hotcode)("Percentage of samples from hot code heap: %f", percent_from_hot); + if (percent_from_hot >= HotCodeSamplePercent) { + log_info(hotcode)("Percentage of samples from hot nmethods over threshold. Done collecting hot code"); + break; + } + + nmethod* candidate = candidates.get_candidate(); + + MutexLocker ml_Compile_lock(Compile_lock); + MutexLocker ml_CompiledIC_lock(CompiledIC_lock, Mutex::_no_safepoint_check_flag); + MutexLocker ml_CodeCache_lock(CodeCache_lock, Mutex::_no_safepoint_check_flag); + + num_relocated += do_relocation(candidate, 0); + } + + log_info(hotcode)("Collection done. Relocated %d nmethods to the MethodHot heap", num_relocated); +} + +int HotCodeCollector::do_relocation(void* candidate, uint call_level) { + if (candidate == nullptr) { + return 0; + } + + // Verify that address still points to CodeBlob + CodeBlob* blob = CodeCache::find_blob(candidate); + if (blob == nullptr) { + return 0; + } + + // Verify that blob is nmethod + nmethod* nm = blob->as_nmethod_or_null(); + if (nm == nullptr || nm->method() == nullptr) { + return 0; + } + + // The candidate may have been recompiled or already relocated. + // Retrieve the latest nmethod from the Method + nm = nm->method()->code(); + + // Verify the nmethod is still valid for relocation + if (nm == nullptr || !nm->is_in_use() || !nm->is_compiled_by_c2()) { + return 0; + } + + // Verify code heap has space + if (CodeCache::get_code_heap(CodeBlobType::MethodHot)->unallocated_capacity() < (size_t)nm->size()) { + log_info(hotcode)("Not enough free space in MethodHot heap (%zd bytes) to relocate nm (%d bytes). Bailing out", + CodeCache::get_code_heap(CodeBlobType::MethodHot)->unallocated_capacity(), nm->size()); + return 0; + } + + // Number of nmethods relocated (candidate + callees) + int num_relocated = 0; + + // Pointer to nmethod in hot heap + nmethod* hot_nm = nullptr; + + if (CodeCache::get_code_blob_type(nm) != CodeBlobType::MethodHot) { + CompiledICLocker ic_locker(nm); + hot_nm = nm->relocate(CodeBlobType::MethodHot); + + if (hot_nm != nullptr) { + // Successfully relocated nmethod. Update counts and proceed to callee relocation. + log_debug(hotcode)("Successful relocation: nmethod (%p), method (%s), call level (%d)", nm, hot_nm->method()->name_and_sig_as_C_string(), call_level); + num_relocated++; + } else { + // Relocation failed so return and do not attempt to relocate callees + log_debug(hotcode)("Failed relocation: nmethod (%p), call level (%d)", nm, call_level); + return 0; + } + } else { + // Skip relocation since already in hot heap, but still relocate callees + // since they may not have been compiled when this method was first relocated + log_debug(hotcode)("Already relocated: nmethod (%p), method (%s), call level (%d)", nm, nm->method()->name_and_sig_as_C_string(), call_level); + hot_nm = nm; + } + + assert(hot_nm != nullptr, "unable to relocate callees"); + + if (call_level < HotCodeCallLevel) { + // Loop over relocations to relocate callees + RelocIterator relocIter(hot_nm); + while (relocIter.next()) { + // Check if this is a call + Relocation* reloc = relocIter.reloc(); + if (!reloc->is_call()) { + continue; + } + + // Find the call destination address + address dest = ((CallRelocation*) reloc)->destination(); + + // Recursively relocate callees + num_relocated += do_relocation(dest, call_level + 1); + } + } + + return num_relocated; +} + +void HotCodeCollector::unregister_nmethod(nmethod* nm) { + assert_lock_strong(CodeCache_lock); + if (!_is_initialized) { + return; + } + + if (!nm->is_compiled_by_c2()) { + return; + } + + if (CodeCache::get_code_blob_type(nm) == CodeBlobType::MethodHot) { + // Nmethods in the hot code heap do not count towards total C2 nmethods. + return; + } + + // CodeCache_lock is held, so we can safely decrement the count. + _total_c2_nmethods_count--; +} + +void HotCodeCollector::register_nmethod(nmethod* nm) { + assert_lock_strong(CodeCache_lock); + if (!_is_initialized) { + return; + } + + if (!nm->is_compiled_by_c2()) { + return; // Only C2 nmethods are relocated to HotCodeHeap. + } + + if (CodeCache::get_code_blob_type(nm) == CodeBlobType::MethodHot) { + // Nmethods in the hot code heap do not count towards total C2 nmethods. + return; + } + + // CodeCache_lock is held, so we can safely increment the count. + _new_c2_nmethods_count++; + _total_c2_nmethods_count++; +} +#endif // COMPILER2 diff --git a/src/hotspot/share/runtime/hotCodeCollector.hpp b/src/hotspot/share/runtime/hotCodeCollector.hpp new file mode 100644 index 00000000000..dbefa3dc788 --- /dev/null +++ b/src/hotspot/share/runtime/hotCodeCollector.hpp @@ -0,0 +1,56 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifdef COMPILER2 +#ifndef SHARE_RUNTIME_HOTCODECOLLECTOR_HPP +#define SHARE_RUNTIME_HOTCODECOLLECTOR_HPP + +#include "runtime/javaThread.hpp" + +class Candidates; + +class HotCodeCollector : public JavaThread { + private: + static bool _is_initialized; + + static int _new_c2_nmethods_count; + static int _total_c2_nmethods_count; + + HotCodeCollector(); + + static void do_grouping(Candidates& candidates); + + static int do_relocation(void* candidate, uint call_level); + + public: + static void initialize(); + static void thread_entry(JavaThread* thread, TRAPS); + static void unregister_nmethod(nmethod* nm); + static void register_nmethod(nmethod* nm); + + static bool is_nmethod_count_stable(); +}; + +#endif // SHARE_RUNTIME_HOTCODECOLLECTOR_HPP +#endif // COMPILER2 diff --git a/src/hotspot/share/runtime/hotCodeSampler.cpp b/src/hotspot/share/runtime/hotCodeSampler.cpp new file mode 100644 index 00000000000..730a47d238a --- /dev/null +++ b/src/hotspot/share/runtime/hotCodeSampler.cpp @@ -0,0 +1,121 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifdef COMPILER2 + +#include "code/codeCache.hpp" +#include "logging/log.hpp" +#include "runtime/hotCodeSampler.hpp" +#include "runtime/javaThread.inline.hpp" + +void ThreadSampler::sample_all_java_threads() { + // Collect samples for each JavaThread + for (JavaThreadIteratorWithHandle jtiwh; JavaThread *jt = jtiwh.next(); ) { + if (jt->is_hidden_from_external_view() || + jt->in_deopt_handler() || + (jt->thread_state() != _thread_in_native && jt->thread_state() != _thread_in_Java)) { + continue; + } + + GetPCTask task(jt); + task.run(); + address pc = task.pc(); + if (pc == nullptr) { + continue; + } + + if (CodeCache::contains(pc)) { + nmethod* nm = CodeCache::find_blob(pc)->as_nmethod_or_null(); + if (nm != nullptr) { + bool created = false; + int *count = _samples.put_if_absent(nm, 0, &created); + (*count)++; + if (created) { + _samples.maybe_grow(); + } + } + } + } +} + +Candidates::Candidates(ThreadSampler& sampler) + : _hot_sample_count(0), _non_profiled_sample_count(0) { + auto func = [&](nmethod* nm, int count) { + if (CodeCache::get_code_blob_type(nm) == CodeBlobType::MethodNonProfiled) { + _candidates.append(Pair(nm, count)); + add_non_profiled_sample_count(count); + } else if (CodeCache::get_code_blob_type(nm) == CodeBlobType::MethodHot) { + add_hot_sample_count(count); + } + }; + sampler.iterate_samples(func); + + log_info(hotcode)("Generated candidate list from %d samples corresponding to %d nmethods", _non_profiled_sample_count + _hot_sample_count, _candidates.length()); +} + +void Candidates::add_candidate(nmethod* nm, int count) { + _candidates.append(Pair(nm, count)); +} + +void Candidates::add_hot_sample_count(int count) { + _hot_sample_count += count; +} + +void Candidates::add_non_profiled_sample_count(int count) { + _non_profiled_sample_count += count; +} + +void Candidates::sort() { + _candidates.sort( + [](Pair* a, Pair* b) { + if (a->second > b->second) return 1; + if (a->second < b->second) return -1; + return 0; + } + ); +} + +bool Candidates::has_candidates() { + return !_candidates.is_empty(); +} + +nmethod* Candidates::get_candidate() { + assert(has_candidates(), "must not be empty"); + Pair candidate = _candidates.pop(); + + _hot_sample_count += candidate.second; + _non_profiled_sample_count -= candidate.second; + + return candidate.first; +} + +double Candidates::get_hot_sample_percent() { + if (_hot_sample_count + _non_profiled_sample_count == 0) { + return 0; + } + + return 100.0 * _hot_sample_count / (_hot_sample_count + _non_profiled_sample_count); +} + +#endif // COMPILER2 diff --git a/src/hotspot/share/runtime/hotCodeSampler.hpp b/src/hotspot/share/runtime/hotCodeSampler.hpp new file mode 100644 index 00000000000..d61cac791e1 --- /dev/null +++ b/src/hotspot/share/runtime/hotCodeSampler.hpp @@ -0,0 +1,104 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifdef COMPILER2 +#ifndef SHARE_RUNTIME_HOTCODESAMPLER_HPP +#define SHARE_RUNTIME_HOTCODESAMPLER_HPP + +#include "runtime/javaThread.hpp" +#include "runtime/suspendedThreadTask.hpp" +#include "runtime/threadSMR.hpp" +#include "utilities/pair.hpp" +#include "utilities/resizableHashTable.hpp" + +// Generate a random sampling period between min and max +static inline uint rand_sampling_period_ms() { + assert(HotCodeMaxSamplingMs >= HotCodeMinSamplingMs, "max cannot be smaller than min"); + julong range = (julong)HotCodeMaxSamplingMs - (julong)HotCodeMinSamplingMs + 1; + return (uint)(os::random() % range) + HotCodeMinSamplingMs; +} + +class ThreadSampler; + +class Candidates : public StackObj { + private: + GrowableArray> _candidates; + int _hot_sample_count; + int _non_profiled_sample_count; + + public: + Candidates(ThreadSampler& sampler); + + void add_candidate(nmethod* nm, int count); + void add_hot_sample_count(int count); + void add_non_profiled_sample_count(int count); + void sort(); + + bool has_candidates(); + nmethod* get_candidate(); + double get_hot_sample_percent(); +}; + +class GetPCTask : public SuspendedThreadTask { + private: + address _pc; + + void do_task(const SuspendedThreadTaskContext& context) override { + JavaThread* jt = JavaThread::cast(context.thread()); + if (jt->thread_state() != _thread_in_native && jt->thread_state() != _thread_in_Java) { + return; + } + _pc = os::fetch_frame_from_context(context.ucontext(), nullptr, nullptr); + } + + public: + GetPCTask(JavaThread* thread) : SuspendedThreadTask(thread), _pc(nullptr) {} + + address pc() const { + return _pc; + } +}; + +class ThreadSampler : public StackObj { + private: + static const int INITIAL_TABLE_SIZE = 109; + + // Table of nmethods found during profiling with sample count + ResizeableHashTable _samples; + + public: + ThreadSampler() : _samples(INITIAL_TABLE_SIZE, HotCodeSampleSeconds * 1000 / HotCodeMaxSamplingMs) {} + + // Iterate over and sample all Java threads + void sample_all_java_threads(); + + // Iterate over all samples with a callback function + template + void iterate_samples(Function func) { + _samples.iterate_all(func); + } +}; + +#endif // SHARE_RUNTIME_HOTCODESAMPLER_HPP +#endif // COMPILER2 diff --git a/src/hotspot/share/runtime/threads.cpp b/src/hotspot/share/runtime/threads.cpp index 442b68e596a..b83389a1929 100644 --- a/src/hotspot/share/runtime/threads.cpp +++ b/src/hotspot/share/runtime/threads.cpp @@ -113,6 +113,7 @@ #endif #ifdef COMPILER2 #include "opto/idealGraphPrinter.hpp" +#include "runtime/hotCodeCollector.hpp" #endif #if INCLUDE_JFR #include "jfr/jfr.hpp" @@ -798,6 +799,12 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { StringDedup::start(); } +#ifdef COMPILER2 + if (HotCodeHeap) { + HotCodeCollector::initialize(); + } +#endif // COMPILER2 + // Pre-initialize some JSR292 core classes to avoid deadlock during class loading. // It is done after compilers are initialized, because otherwise compilations of // signature polymorphic MH intrinsics can be missed diff --git a/test/hotspot/jtreg/compiler/codecache/MHIntrinsicAllocFailureTest.java b/test/hotspot/jtreg/compiler/codecache/MHIntrinsicAllocFailureTest.java index 1cbaaf0f52d..c1638a27fd7 100644 --- a/test/hotspot/jtreg/compiler/codecache/MHIntrinsicAllocFailureTest.java +++ b/test/hotspot/jtreg/compiler/codecache/MHIntrinsicAllocFailureTest.java @@ -1,6 +1,6 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2022 SAP SE. All rights reserved.ights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 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 @@ -28,6 +28,7 @@ * @requires vm.compMode == "Xmixed" * @requires vm.opt.TieredCompilation == null | vm.opt.TieredCompilation == true * @requires vm.opt.TieredStopAtLevel == null | vm.opt.TieredStopAtLevel == 4 + * @requires vm.compiler2.enabled * @summary test allocation failure of method handle intrinsic in profiled/non-profiled space * @library /test/lib * @modules java.base/jdk.internal.misc @@ -39,6 +40,11 @@ * -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,null::* * -XX:ReservedCodeCacheSize=16m -XX:+SegmentedCodeCache * compiler.codecache.MHIntrinsicAllocFailureTest + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,null::* + * -XX:ReservedCodeCacheSize=20m -XX:+SegmentedCodeCache + * -XX:+TieredCompilation -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=4M + * compiler.codecache.MHIntrinsicAllocFailureTest */ package compiler.codecache; @@ -73,7 +79,7 @@ public class MHIntrinsicAllocFailureTest { // JIT compilers should be off, now. Asserts.assertNotEquals(WHITE_BOX.getCompilationActivityMode(), 1); System.out.println("Code cache segments for non-profiled and profiled nmethods are full."); - // Generate and use a MH itrinsic. Should not trigger one of the following: + // Generate and use a MH intrinsic. Should not trigger one of the following: // - VirtualMachineError: Out of space in CodeCache for method handle intrinsic // - InternalError: java.lang.NoSuchMethodException: no such method: // java.lang.invoke.MethodHandle.linkToStatic(int,int,Object,MemberName)int/invokeStatic diff --git a/test/hotspot/jtreg/compiler/codecache/OverflowCodeCacheTest.java b/test/hotspot/jtreg/compiler/codecache/OverflowCodeCacheTest.java index cf993237a32..e0a45e4cba6 100644 --- a/test/hotspot/jtreg/compiler/codecache/OverflowCodeCacheTest.java +++ b/test/hotspot/jtreg/compiler/codecache/OverflowCodeCacheTest.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 @@ -44,6 +44,27 @@ * compiler.codecache.OverflowCodeCacheTest */ +/* + * @test OverflowCodeCacheTest + * @bug 8059550 8279356 8326205 + * @requires vm.compiler2.enabled + * @summary testing of code cache segments overflow + * @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 main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:+TieredCompilation -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=8M + * -Xmixed -XX:TieredStopAtLevel=4 + * compiler.codecache.OverflowCodeCacheTest + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:-TieredCompilation -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=8M + * -Xmixed -XX:TieredStopAtLevel=4 + * compiler.codecache.OverflowCodeCacheTest + */ + package compiler.codecache; import jdk.test.lib.Asserts; @@ -85,6 +106,7 @@ public class OverflowCodeCacheTest { System.out.println("allocating till possible..."); ArrayList blobs = new ArrayList<>(); int compilationActivityMode = -1; + CodeCacheConstraints constraints = getCodeCacheConstraints(type); // Lock compilation to be able to better control code cache space WHITE_BOX.lockCompilation(); try { @@ -115,6 +137,7 @@ public class OverflowCodeCacheTest { } catch (VirtualMachineError e) { // Expected } + constraints.check(); // Free code cache space for (Long blob : blobs) { WHITE_BOX.freeCodeBlob(blob); @@ -143,4 +166,31 @@ public class OverflowCodeCacheTest { return bean.getUsage().getMax(); } + class CodeCacheConstraints { + void check() {} + } + + CodeCacheConstraints getCodeCacheConstraints(final BlobType type) { + if (Long.valueOf(0).equals(WHITE_BOX.getVMFlag("HotCodeHeapSize"))) { + return new CodeCacheConstraints(); + } else if (BlobType.MethodHot == type) { + // NonProfiledHeap is used when HotCodeHeap runs out of space. + return new CodeCacheConstraints() { + final int nonProfiledCount = WHITE_BOX.getCodeHeapEntries(BlobType.MethodNonProfiled.id).length; + @Override + void check() { + Asserts.assertLT(nonProfiledCount, WHITE_BOX.getCodeHeapEntries(BlobType.MethodNonProfiled.id).length); + } + }; + } else { + // HotCodeHeap should not be used when other heap runs out of space. + return new CodeCacheConstraints() { + final int hotCount = WHITE_BOX.getCodeHeapEntries(BlobType.MethodHot.id).length; + @Override + void check() { + Asserts.assertEQ(hotCount, WHITE_BOX.getCodeHeapEntries(BlobType.MethodHot.id).length); + } + }; + } + } } diff --git a/test/hotspot/jtreg/compiler/codecache/cli/TestSegmentedCodeCacheOption.java b/test/hotspot/jtreg/compiler/codecache/cli/TestSegmentedCodeCacheOption.java index a5068b47454..e54fad3517e 100644 --- a/test/hotspot/jtreg/compiler/codecache/cli/TestSegmentedCodeCacheOption.java +++ b/test/hotspot/jtreg/compiler/codecache/cli/TestSegmentedCodeCacheOption.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 @@ -50,10 +50,16 @@ public class TestSegmentedCodeCacheOption { private static final String USE_SEGMENTED_CODE_CACHE = CommandLineOptionTest.prepareBooleanFlag(SEGMENTED_CODE_CACHE, true); + private static final String UNLOCK_EXPERIMENTAL_VM_OPTIONS + = CommandLineOptionTest.prepareBooleanFlag("UnlockExperimentalVMOptions", true); + private static final String HOT_CODE_HEAP + = CommandLineOptionTest.prepareBooleanFlag("HotCodeHeap", true); private static final long THRESHOLD_CC_SIZE_VALUE = CodeCacheOptions.mB(240); private static final long BELOW_THRESHOLD_CC_SIZE = THRESHOLD_CC_SIZE_VALUE - CodeCacheOptions.mB(1); + private static final long HOT_CODE_HEAP_SIZE + = CodeCacheOptions.mB(8); private static final String[] UNEXPECTED_MESSAGES = new String[] { ".*" + SEGMENTED_CODE_CACHE + ".*" }; @@ -104,7 +110,7 @@ public class TestSegmentedCodeCacheOption { public void run() throws Throwable { // SCC is disabled w/o TieredCompilation by default String errorMessage = SEGMENTED_CODE_CACHE - + " should be disabled by default when tiered " + + " should be disabled by default when tiered " + "compilation is disabled"; CommandLineOptionTest.verifyOptionValueForSameVM( @@ -162,6 +168,52 @@ public class TestSegmentedCodeCacheOption { CommandLineOptionTest.prepareBooleanFlag( TIERED_COMPILATION, true)); } + }, + OPTION_VALUES_HOT { + @Override + public boolean isApplicable() { + return Platform.isServer(); + } + + @Override + public void run() throws Throwable { + // SCC is enabled w hot code heap w/o TieredCompilation + String errorMessage = SEGMENTED_CODE_CACHE + + " should be enabled when the hot code heap " + + "is enabled"; + + CommandLineOptionTest.verifyOptionValueForSameVM( + SEGMENTED_CODE_CACHE, "true", errorMessage, + UNLOCK_EXPERIMENTAL_VM_OPTIONS, + HOT_CODE_HEAP, + CommandLineOptionTest.prepareNumericFlag( + BlobType.MethodHot.sizeOptionName, + HOT_CODE_HEAP_SIZE), + CommandLineOptionTest.prepareBooleanFlag( + TIERED_COMPILATION, false)); + + // Hot code heap could be explicitly enabled w/ SegmentedCodeCache + // and w/ ReservedCodeCacheSize value below the threshold + errorMessage = String.format("It should be possible to explicitly " + + "enable %s and %s with %s below threshold %d.", + BlobType.MethodHot.sizeOptionName, + SEGMENTED_CODE_CACHE, + BlobType.All.sizeOptionName, + THRESHOLD_CC_SIZE_VALUE); + + CommandLineOptionTest.verifyOptionValueForSameVM( + BlobType.MethodHot.sizeOptionName, String.valueOf(HOT_CODE_HEAP_SIZE), + errorMessage, + UNLOCK_EXPERIMENTAL_VM_OPTIONS, + HOT_CODE_HEAP, + CommandLineOptionTest.prepareNumericFlag( + BlobType.All.sizeOptionName, + BELOW_THRESHOLD_CC_SIZE), + CommandLineOptionTest.prepareNumericFlag( + BlobType.MethodHot.sizeOptionName, + HOT_CODE_HEAP_SIZE), + USE_SEGMENTED_CODE_CACHE); + } }; TestCase() { diff --git a/test/hotspot/jtreg/compiler/codecache/cli/codeheapsize/GenericCodeHeapSizeRunner.java b/test/hotspot/jtreg/compiler/codecache/cli/codeheapsize/GenericCodeHeapSizeRunner.java index e7c68e71ab3..aa7e9e67f37 100644 --- a/test/hotspot/jtreg/compiler/codecache/cli/codeheapsize/GenericCodeHeapSizeRunner.java +++ b/test/hotspot/jtreg/compiler/codecache/cli/codeheapsize/GenericCodeHeapSizeRunner.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 @@ -69,5 +69,13 @@ public class GenericCodeHeapSizeRunner implements CodeCacheCLITestCase.Runner { BlobType.MethodProfiled.sizeOptionName, expectedValues.profiled), testCaseDescription.getTestOptions(options)); + + CommandLineOptionTest.verifyOptionValueForSameVM( + BlobType.MethodHot.sizeOptionName, + Long.toString(expectedValues.hot), + String.format("%s should have value %d.", + BlobType.MethodHot.sizeOptionName, + expectedValues.hot), + testCaseDescription.getTestOptions(options)); } } diff --git a/test/hotspot/jtreg/compiler/codecache/cli/codeheapsize/TestCodeHeapSizeOptions.java b/test/hotspot/jtreg/compiler/codecache/cli/codeheapsize/TestCodeHeapSizeOptions.java index 4d52f470645..b5ae98bc79f 100644 --- a/test/hotspot/jtreg/compiler/codecache/cli/codeheapsize/TestCodeHeapSizeOptions.java +++ b/test/hotspot/jtreg/compiler/codecache/cli/codeheapsize/TestCodeHeapSizeOptions.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 @@ -48,13 +48,15 @@ import java.util.EnumSet; public class TestCodeHeapSizeOptions extends CodeCacheCLITestBase { private static final CodeCacheCLITestCase JVM_STARTUP = new CodeCacheCLITestCase(new CodeCacheCLITestCase.Description( - options -> options.segmented, + options -> options.segmented + && options.hot == 0, EnumSet.noneOf(BlobType.class)), new JVMStartupRunner()); private static final CodeCacheCLITestCase CODE_CACHE_FREE_SPACE = new CodeCacheCLITestCase(new CodeCacheCLITestCase.Description( options -> options.segmented + && options.hot == 0 && Platform.isDebugBuild(), EnumSet.noneOf(BlobType.class)), new CodeCacheFreeSpaceRunner()); @@ -65,13 +67,19 @@ public class TestCodeHeapSizeOptions extends CodeCacheCLITestBase { private TestCodeHeapSizeOptions() { super(CodeCacheCLITestBase.OPTIONS_SET, new CodeCacheCLITestCase(CodeCacheCLITestCase - .CommonDescriptions.NON_TIERED.description, + .CommonDescriptions.NON_TIERED_WO_HOT.description, GENERIC_RUNNER), new CodeCacheCLITestCase(CodeCacheCLITestCase .CommonDescriptions.TIERED_LEVEL_1.description, GENERIC_RUNNER), new CodeCacheCLITestCase(CodeCacheCLITestCase - .CommonDescriptions.TIERED_LEVEL_4.description, + .CommonDescriptions.TIERED_LEVEL_4_WO_HOT.description, + GENERIC_RUNNER), + new CodeCacheCLITestCase(CodeCacheCLITestCase + .CommonDescriptions.NON_TIERED_W_HOT.description, + GENERIC_RUNNER), + new CodeCacheCLITestCase(CodeCacheCLITestCase + .CommonDescriptions.TIERED_LEVEL_4_W_HOT.description, GENERIC_RUNNER), JVM_STARTUP, CODE_CACHE_FREE_SPACE); diff --git a/test/hotspot/jtreg/compiler/codecache/cli/common/CodeCacheCLITestBase.java b/test/hotspot/jtreg/compiler/codecache/cli/common/CodeCacheCLITestBase.java index f1f18956f05..12a1a0c42cd 100644 --- a/test/hotspot/jtreg/compiler/codecache/cli/common/CodeCacheCLITestBase.java +++ b/test/hotspot/jtreg/compiler/codecache/cli/common/CodeCacheCLITestBase.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 @@ -40,7 +40,13 @@ public class CodeCacheCLITestBase { CodeCacheOptions.mB(100)), new CodeCacheOptions(CodeCacheOptions.mB(60)), new CodeCacheOptions(CodeCacheOptions.mB(200)), - new CodeCacheOptions(CodeCacheOptions.mB(300)) + new CodeCacheOptions(CodeCacheOptions.mB(300)), + new CodeCacheOptions(CodeCacheOptions.mB(250), + CodeCacheOptions.mB(50), CodeCacheOptions.mB(75), + CodeCacheOptions.mB(75), CodeCacheOptions.mB(50)), + new CodeCacheOptions(CodeCacheOptions.mB(200), + CodeCacheOptions.mB(50), CodeCacheOptions.mB(100), + CodeCacheOptions.mB(0), CodeCacheOptions.mB(50)) }; private final CodeCacheCLITestCase[] testCases; diff --git a/test/hotspot/jtreg/compiler/codecache/cli/common/CodeCacheCLITestCase.java b/test/hotspot/jtreg/compiler/codecache/cli/common/CodeCacheCLITestCase.java index eca5c70e091..0f5af1c0a93 100644 --- a/test/hotspot/jtreg/compiler/codecache/cli/common/CodeCacheCLITestCase.java +++ b/test/hotspot/jtreg/compiler/codecache/cli/common/CodeCacheCLITestCase.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 @@ -39,15 +39,24 @@ import java.util.function.Function; * description. */ public class CodeCacheCLITestCase { - private static final Function ONLY_SEGMENTED - = options -> options.segmented; - private static final Function SEGMENTED_SERVER - = ONLY_SEGMENTED.andThen(isSegmented -> isSegmented + private static final Function SEGMENTED_WO_HOT + = options -> options.segmented && options.hot == 0; + private static final Function SEGMENTED_SERVER_WO_HOT + = SEGMENTED_WO_HOT.andThen(isSegmented -> isSegmented && Platform.isServer() && Platform.isTieredSupported()); + private static final Function SEGMENTED_W_HOT + = options -> options.segmented && options.hot > 0 + && options.profiled > 0 && Platform.isTieredSupported(); + private static final Function SEGMENTED_W_HOT_WO_PROFILED + = options -> options.segmented && options.hot > 0 + && options.profiled == 0 && Platform.isTieredSupported(); + private static final String USE_INT_MODE = "-Xint"; private static final String SEGMENTED_CODE_CACHE = "SegmentedCodeCache"; private static final String TIERED_COMPILATION = "TieredCompilation"; private static final String TIERED_STOP_AT = "TieredStopAtLevel"; + private static final String UNLOCK_EXPERIMENTAL_VM_OPTIONS = "UnlockExperimentalVMOptions"; + private static final String HOT_CODE_HEAP = "HotCodeHeap"; private final Description description; private final Runner runner; @@ -68,7 +77,7 @@ public class CodeCacheCLITestCase { * Verifies that in interpreted mode PrintCodeCache output contains * the whole code cache. Int mode disables SegmentedCodeCache with a warning. */ - INT_MODE(ONLY_SEGMENTED, EnumSet.of(BlobType.All), USE_INT_MODE), + INT_MODE(options -> options.hot == 0, EnumSet.of(BlobType.All), USE_INT_MODE), /** * Verifies that with disabled SegmentedCodeCache PrintCodeCache output * contains only CodeCache's entry. @@ -81,7 +90,7 @@ public class CodeCacheCLITestCase { * code cache PrintCodeCache output does not contain information about * profiled-nmethods heap and non-segmented CodeCache. */ - NON_TIERED(ONLY_SEGMENTED, + NON_TIERED_WO_HOT(SEGMENTED_WO_HOT, EnumSet.of(BlobType.NonNMethod, BlobType.MethodNonProfiled), CommandLineOptionTest.prepareBooleanFlag(TIERED_COMPILATION, false)), @@ -90,7 +99,7 @@ public class CodeCacheCLITestCase { * warn about SegmentedCodeCache and contain information about all * heaps only. */ - TIERED_LEVEL_0(SEGMENTED_SERVER, + TIERED_LEVEL_0(SEGMENTED_SERVER_WO_HOT, EnumSet.of(BlobType.All), CommandLineOptionTest.prepareBooleanFlag(TIERED_COMPILATION, true), @@ -100,19 +109,44 @@ public class CodeCacheCLITestCase { * contain information about non-nmethods and non-profiled nmethods * heaps only. */ - TIERED_LEVEL_1(SEGMENTED_SERVER, + TIERED_LEVEL_1(SEGMENTED_SERVER_WO_HOT, EnumSet.of(BlobType.NonNMethod, BlobType.MethodNonProfiled), CommandLineOptionTest.prepareBooleanFlag(TIERED_COMPILATION, true), CommandLineOptionTest.prepareNumericFlag(TIERED_STOP_AT, 1)), /** * Verifies that with TieredStopAtLevel=4 PrintCodeCache output will - * contain information about all three code heaps. + * contain information about non-nmethods, non-profiled nmethods + * and profiled nmethods heaps only. */ - TIERED_LEVEL_4(SEGMENTED_SERVER, - EnumSet.complementOf(EnumSet.of(BlobType.All)), + TIERED_LEVEL_4_WO_HOT(SEGMENTED_SERVER_WO_HOT, + EnumSet.complementOf(EnumSet.of(BlobType.MethodHot, BlobType.All)), CommandLineOptionTest.prepareBooleanFlag(TIERED_COMPILATION, true), + CommandLineOptionTest.prepareNumericFlag(TIERED_STOP_AT, 4)), + + /** + * Verifies that with disabled tiered compilation and enabled hot code + * cache PrintCodeCache output does not contain information about + * profiled-nmethods heap and non-segmented CodeCache. + */ + NON_TIERED_W_HOT(SEGMENTED_W_HOT_WO_PROFILED, + EnumSet.of(BlobType.NonNMethod, BlobType.MethodNonProfiled, BlobType.MethodHot), + CommandLineOptionTest.prepareBooleanFlag(UNLOCK_EXPERIMENTAL_VM_OPTIONS, true), + CommandLineOptionTest.prepareBooleanFlag(HOT_CODE_HEAP, true), + CommandLineOptionTest.prepareBooleanFlag(TIERED_COMPILATION, + false)), + + /** + * Verifies that with TieredStopAtLevel=4 and hot code heap + * PrintCodeCache output will contain information about non-nmethods, + * non-profiled nmethods, profiled nmethods, and hot code heaps only. + */ + TIERED_LEVEL_4_W_HOT(SEGMENTED_W_HOT, + EnumSet.complementOf(EnumSet.of(BlobType.All)), + CommandLineOptionTest.prepareBooleanFlag(UNLOCK_EXPERIMENTAL_VM_OPTIONS, true), + CommandLineOptionTest.prepareBooleanFlag(HOT_CODE_HEAP, true), + CommandLineOptionTest.prepareBooleanFlag(TIERED_COMPILATION, true), CommandLineOptionTest.prepareNumericFlag(TIERED_STOP_AT, 4)); CommonDescriptions(Function predicate, diff --git a/test/hotspot/jtreg/compiler/codecache/cli/common/CodeCacheOptions.java b/test/hotspot/jtreg/compiler/codecache/cli/common/CodeCacheOptions.java index f5243aaa493..b8e386f4f7d 100644 --- a/test/hotspot/jtreg/compiler/codecache/cli/common/CodeCacheOptions.java +++ b/test/hotspot/jtreg/compiler/codecache/cli/common/CodeCacheOptions.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 @@ -37,15 +37,20 @@ public class CodeCacheOptions { = EnumSet.of(BlobType.All); private static final EnumSet ALL_SEGMENTED_HEAPS = EnumSet.complementOf(NON_SEGMENTED_HEAPS); - private static final EnumSet SEGMENTED_HEAPS_WO_PROFILED + private static final EnumSet NON_NMETHOD_AND_NON_PROFILED_HEAPS = EnumSet.of(BlobType.NonNMethod, BlobType.MethodNonProfiled); + private static final EnumSet SEGMENTED_HEAPS_WO_HOT + = EnumSet.of(BlobType.NonNMethod, BlobType.MethodProfiled, BlobType.MethodNonProfiled); private static final EnumSet ONLY_NON_METHODS_HEAP = EnumSet.of(BlobType.NonNMethod); + private static final EnumSet NON_NMETHOD_AND_NON_PROFILED_AND_HOT_HEAPS + = EnumSet.of(BlobType.NonNMethod, BlobType.MethodNonProfiled, BlobType.MethodHot); public final long reserved; public final long nonNmethods; public final long nonProfiled; public final long profiled; + public final long hot; public final boolean segmented; public static long mB(long val) { @@ -61,6 +66,7 @@ public class CodeCacheOptions { this.nonNmethods = 0; this.nonProfiled = 0; this.profiled = 0; + this.hot = 0; this.segmented = false; } @@ -70,6 +76,17 @@ public class CodeCacheOptions { this.nonNmethods = nonNmethods; this.nonProfiled = nonProfiled; this.profiled = profiled; + this.hot = 0; + this.segmented = true; + } + + public CodeCacheOptions(long reserved, long nonNmethods, long nonProfiled, + long profiled, long hot) { + this.reserved = reserved; + this.nonNmethods = nonNmethods; + this.nonProfiled = nonProfiled; + this.profiled = profiled; + this.hot = hot; this.segmented = true; } @@ -83,6 +100,8 @@ public class CodeCacheOptions { return this.nonProfiled; case MethodProfiled: return this.profiled; + case MethodHot: + return this.hot; default: throw new Error("Unknown heap: " + heap.name()); } @@ -106,6 +125,11 @@ public class CodeCacheOptions { nonProfiled), CommandLineOptionTest.prepareNumericFlag( BlobType.MethodProfiled.sizeOptionName, profiled)); + if (hot > 0) { + Collections.addAll(options, + CommandLineOptionTest.prepareNumericFlag( + BlobType.MethodHot.sizeOptionName, hot)); + } } return options.toArray(new String[options.size()]); } @@ -113,9 +137,11 @@ public class CodeCacheOptions { public CodeCacheOptions mapOptions(EnumSet involvedCodeHeaps) { if (involvedCodeHeaps.isEmpty() || involvedCodeHeaps.equals(NON_SEGMENTED_HEAPS) - || involvedCodeHeaps.equals(ALL_SEGMENTED_HEAPS)) { + || involvedCodeHeaps.equals(SEGMENTED_HEAPS_WO_HOT) + || involvedCodeHeaps.equals(ALL_SEGMENTED_HEAPS) + || involvedCodeHeaps.equals(NON_NMETHOD_AND_NON_PROFILED_AND_HOT_HEAPS)) { return this; - } else if (involvedCodeHeaps.equals(SEGMENTED_HEAPS_WO_PROFILED)) { + } else if (involvedCodeHeaps.equals(NON_NMETHOD_AND_NON_PROFILED_HEAPS)) { return new CodeCacheOptions(reserved, nonNmethods, profiled + nonProfiled, 0L); } else if (involvedCodeHeaps.equals(ONLY_NON_METHODS_HEAP)) { diff --git a/test/hotspot/jtreg/compiler/codecache/cli/printcodecache/TestPrintCodeCacheOption.java b/test/hotspot/jtreg/compiler/codecache/cli/printcodecache/TestPrintCodeCacheOption.java index c0d826e59ec..2e994336f54 100644 --- a/test/hotspot/jtreg/compiler/codecache/cli/printcodecache/TestPrintCodeCacheOption.java +++ b/test/hotspot/jtreg/compiler/codecache/cli/printcodecache/TestPrintCodeCacheOption.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 @@ -46,7 +46,7 @@ import java.util.EnumSet; public class TestPrintCodeCacheOption extends CodeCacheCLITestBase { private static final CodeCacheCLITestCase DISABLED_PRINT_CODE_CACHE = new CodeCacheCLITestCase(new CodeCacheCLITestCase.Description( - options -> true, EnumSet.noneOf(BlobType.class)), + options -> options.hot == 0, EnumSet.noneOf(BlobType.class)), new PrintCodeCacheRunner(false)); private static final CodeCacheCLITestCase.Runner DEFAULT_RUNNER @@ -61,7 +61,7 @@ public class TestPrintCodeCacheOption extends CodeCacheCLITestBase { .CommonDescriptions.NON_SEGMENTED.description, DEFAULT_RUNNER), new CodeCacheCLITestCase(CodeCacheCLITestCase - .CommonDescriptions.NON_TIERED.description, + .CommonDescriptions.NON_TIERED_WO_HOT.description, DEFAULT_RUNNER), new CodeCacheCLITestCase(CodeCacheCLITestCase .CommonDescriptions.TIERED_LEVEL_0.description, @@ -70,7 +70,13 @@ public class TestPrintCodeCacheOption extends CodeCacheCLITestBase { .CommonDescriptions.TIERED_LEVEL_1.description, DEFAULT_RUNNER), new CodeCacheCLITestCase(CodeCacheCLITestCase - .CommonDescriptions.TIERED_LEVEL_4.description, + .CommonDescriptions.TIERED_LEVEL_4_WO_HOT.description, + DEFAULT_RUNNER), + new CodeCacheCLITestCase(CodeCacheCLITestCase + .CommonDescriptions.NON_TIERED_W_HOT.description, + DEFAULT_RUNNER), + new CodeCacheCLITestCase(CodeCacheCLITestCase + .CommonDescriptions.TIERED_LEVEL_4_W_HOT.description, DEFAULT_RUNNER), DISABLED_PRINT_CODE_CACHE); } diff --git a/test/hotspot/jtreg/compiler/codecache/jmx/BeanTypeTest.java b/test/hotspot/jtreg/compiler/codecache/jmx/BeanTypeTest.java index 5bc10071b4d..c669a7ece7d 100644 --- a/test/hotspot/jtreg/compiler/codecache/jmx/BeanTypeTest.java +++ b/test/hotspot/jtreg/compiler/codecache/jmx/BeanTypeTest.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 @@ -40,6 +40,26 @@ * compiler.codecache.jmx.BeanTypeTest */ +/** + * @test BeanTypeTest + * @requires vm.compiler2.enabled + * @summary verify types of code cache memory pool bean + * @modules java.base/jdk.internal.misc + * java.management + * @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 + * -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=8M -XX:+TieredCompilation -XX:TieredStopAtLevel=4 + * compiler.codecache.jmx.BeanTypeTest + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI + * -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=8M -XX:-TieredCompilation -XX:TieredStopAtLevel=4 + * compiler.codecache.jmx.BeanTypeTest + */ + package compiler.codecache.jmx; import jdk.test.lib.Asserts; diff --git a/test/hotspot/jtreg/compiler/codecache/jmx/CodeHeapBeanPresenceTest.java b/test/hotspot/jtreg/compiler/codecache/jmx/CodeHeapBeanPresenceTest.java index d379296d561..462d03ddcdf 100644 --- a/test/hotspot/jtreg/compiler/codecache/jmx/CodeHeapBeanPresenceTest.java +++ b/test/hotspot/jtreg/compiler/codecache/jmx/CodeHeapBeanPresenceTest.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 @@ -40,6 +40,26 @@ * compiler.codecache.jmx.CodeHeapBeanPresenceTest */ +/** + * @test CodeHeapBeanPresenceTest + * @requires vm.compiler2.enabled + * @summary verify CodeHeap bean presence + * @modules java.base/jdk.internal.misc + * java.management + * @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 + * -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=8M -XX:+TieredCompilation -XX:TieredStopAtLevel=4 + * compiler.codecache.jmx.CodeHeapBeanPresenceTest + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI + * -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=8M -XX:-TieredCompilation -XX:TieredStopAtLevel=4 + * compiler.codecache.jmx.CodeHeapBeanPresenceTest + */ + package compiler.codecache.jmx; import jdk.test.lib.Asserts; diff --git a/test/hotspot/jtreg/compiler/codecache/jmx/GetUsageTest.java b/test/hotspot/jtreg/compiler/codecache/jmx/GetUsageTest.java index 873b0494424..704236a3a85 100644 --- a/test/hotspot/jtreg/compiler/codecache/jmx/GetUsageTest.java +++ b/test/hotspot/jtreg/compiler/codecache/jmx/GetUsageTest.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 @@ -42,6 +42,28 @@ * compiler.codecache.jmx.GetUsageTest */ +/* + * @test GetUsageTest + * @requires vm.compiler2.enabled + * @summary testing of getUsage() for segmented code cache + * @modules java.base/jdk.internal.misc + * java.management + * @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 -XX:CompileCommand=compileonly,null::* + * -XX:-UseCodeCacheFlushing -XX:-MethodFlushing + * -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=8M -XX:+TieredCompilation -XX:TieredStopAtLevel=4 + * compiler.codecache.jmx.GetUsageTest + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,null::* + * -XX:-UseCodeCacheFlushing -XX:-MethodFlushing + * -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=8M -XX:-TieredCompilation -XX:TieredStopAtLevel=4 + * compiler.codecache.jmx.GetUsageTest + */ + package compiler.codecache.jmx; import jdk.test.lib.Asserts; diff --git a/test/hotspot/jtreg/compiler/codecache/jmx/InitialAndMaxUsageTest.java b/test/hotspot/jtreg/compiler/codecache/jmx/InitialAndMaxUsageTest.java index a2343c23694..ad12a828fef 100644 --- a/test/hotspot/jtreg/compiler/codecache/jmx/InitialAndMaxUsageTest.java +++ b/test/hotspot/jtreg/compiler/codecache/jmx/InitialAndMaxUsageTest.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 @@ -42,6 +42,28 @@ * compiler.codecache.jmx.InitialAndMaxUsageTest */ +/* + * @test InitialAndMaxUsageTest + * @requires vm.compiler2.enabled + * @summary testing of initial and max usage + * @modules java.base/jdk.internal.misc + * java.management + * @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:-UseCodeCacheFlushing + * -XX:-MethodFlushing -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -XX:CompileCommand=compileonly,null::* -XX:-UseLargePages + * -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=8M -XX:+TieredCompilation -XX:TieredStopAtLevel=4 + * compiler.codecache.jmx.InitialAndMaxUsageTest + * @run main/othervm -Xbootclasspath/a:. -XX:-UseCodeCacheFlushing + * -XX:-MethodFlushing -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -XX:CompileCommand=compileonly,null::* -XX:-UseLargePages + * -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=8M -XX:-TieredCompilation -XX:TieredStopAtLevel=4 + * compiler.codecache.jmx.InitialAndMaxUsageTest + */ + package compiler.codecache.jmx; import jdk.test.lib.Asserts; diff --git a/test/hotspot/jtreg/compiler/codecache/jmx/ManagerNamesTest.java b/test/hotspot/jtreg/compiler/codecache/jmx/ManagerNamesTest.java index b482cd4e559..f04cd695f4f 100644 --- a/test/hotspot/jtreg/compiler/codecache/jmx/ManagerNamesTest.java +++ b/test/hotspot/jtreg/compiler/codecache/jmx/ManagerNamesTest.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 @@ -40,6 +40,26 @@ * compiler.codecache.jmx.ManagerNamesTest */ +/** + * @test ManagerNamesTest + * @requires vm.compiler2.enabled + * @summary verify getMemoryManageNames calls in case of segmented code cache + * @modules java.base/jdk.internal.misc + * java.management + * @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 + * -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=8M -XX:+TieredCompilation -XX:TieredStopAtLevel=4 + * compiler.codecache.jmx.ManagerNamesTest + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI + * -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=8M -XX:-TieredCompilation -XX:TieredStopAtLevel=4 + * compiler.codecache.jmx.ManagerNamesTest + */ + package compiler.codecache.jmx; import jdk.test.lib.Asserts; diff --git a/test/hotspot/jtreg/compiler/codecache/jmx/MemoryPoolsPresenceTest.java b/test/hotspot/jtreg/compiler/codecache/jmx/MemoryPoolsPresenceTest.java index b91b7fa228d..83215bce8ad 100644 --- a/test/hotspot/jtreg/compiler/codecache/jmx/MemoryPoolsPresenceTest.java +++ b/test/hotspot/jtreg/compiler/codecache/jmx/MemoryPoolsPresenceTest.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 @@ -40,6 +40,26 @@ * compiler.codecache.jmx.MemoryPoolsPresenceTest */ +/** + * @test MemoryPoolsPresenceTest + * @requires vm.compiler2.enabled + * @summary verify that MemoryManagerMXBean exists for every code cache segment + * @modules java.base/jdk.internal.misc + * java.management + * @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 + * -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=8M -XX:+TieredCompilation -XX:TieredStopAtLevel=4 + * compiler.codecache.jmx.MemoryPoolsPresenceTest + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI + * -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=8M -XX:-TieredCompilation -XX:TieredStopAtLevel=4 + * compiler.codecache.jmx.MemoryPoolsPresenceTest + */ + package compiler.codecache.jmx; import jdk.test.lib.Asserts; diff --git a/test/hotspot/jtreg/compiler/codecache/jmx/PeakUsageTest.java b/test/hotspot/jtreg/compiler/codecache/jmx/PeakUsageTest.java index b808a661904..ecd9db3a6c4 100644 --- a/test/hotspot/jtreg/compiler/codecache/jmx/PeakUsageTest.java +++ b/test/hotspot/jtreg/compiler/codecache/jmx/PeakUsageTest.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 @@ -23,6 +23,8 @@ /* * @test PeakUsageTest + * @summary testing of getPeakUsage() and resetPeakUsage for + * segmented code cache * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management @@ -37,8 +39,27 @@ * -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,null::* * -XX:-SegmentedCodeCache * compiler.codecache.jmx.PeakUsageTest + */ + +/* + * @test PeakUsageTest + * @requires vm.compiler2.enabled * @summary testing of getPeakUsage() and resetPeakUsage for * segmented code cache + * @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 main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,null::* + * -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=8M -XX:+TieredCompilation -XX:TieredStopAtLevel=4 + * compiler.codecache.jmx.PeakUsageTest + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,null::* + * -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=8M -XX:-TieredCompilation -XX:TieredStopAtLevel=4 + * compiler.codecache.jmx.PeakUsageTest */ package compiler.codecache.jmx; diff --git a/test/hotspot/jtreg/compiler/codecache/jmx/PoolsIndependenceTest.java b/test/hotspot/jtreg/compiler/codecache/jmx/PoolsIndependenceTest.java index 07a5ec94c87..98959f284a0 100644 --- a/test/hotspot/jtreg/compiler/codecache/jmx/PoolsIndependenceTest.java +++ b/test/hotspot/jtreg/compiler/codecache/jmx/PoolsIndependenceTest.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 @@ -40,6 +40,26 @@ * compiler.codecache.jmx.PoolsIndependenceTest */ +/* + * @test PoolsIndependenceTest + * @requires vm.compiler2.enabled + * @summary testing of getUsageThreshold() + * @modules java.base/jdk.internal.misc + * java.management + * @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 -XX:-UseCodeCacheFlushing -XX:-MethodFlushing + * -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=8M -XX:+TieredCompilation -XX:TieredStopAtLevel=4 + * compiler.codecache.jmx.PoolsIndependenceTest + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:-UseCodeCacheFlushing -XX:-MethodFlushing + * -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=8M -XX:-TieredCompilation -XX:TieredStopAtLevel=4 + * compiler.codecache.jmx.PoolsIndependenceTest + */ + package compiler.codecache.jmx; import jdk.test.lib.Asserts; diff --git a/test/hotspot/jtreg/compiler/codecache/jmx/ThresholdNotificationsTest.java b/test/hotspot/jtreg/compiler/codecache/jmx/ThresholdNotificationsTest.java index a71a01a555c..5c1624eeb18 100644 --- a/test/hotspot/jtreg/compiler/codecache/jmx/ThresholdNotificationsTest.java +++ b/test/hotspot/jtreg/compiler/codecache/jmx/ThresholdNotificationsTest.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 @@ -40,6 +40,26 @@ * compiler.codecache.jmx.ThresholdNotificationsTest */ +/* + * @test ThresholdNotificationsTest + * @requires vm.compiler2.enabled + * @summary testing of getUsageThreshold() + * @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 main/othervm -XX:+UnlockDiagnosticVMOptions -Xbootclasspath/a:. -XX:-UseCodeCacheFlushing + * -XX:+WhiteBoxAPI -XX:-MethodFlushing -XX:CompileCommand=compileonly,null::* + * -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=8M -XX:+TieredCompilation -XX:TieredStopAtLevel=4 + * compiler.codecache.jmx.ThresholdNotificationsTest + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -Xbootclasspath/a:. -XX:-UseCodeCacheFlushing + * -XX:+WhiteBoxAPI -XX:-MethodFlushing -XX:CompileCommand=compileonly,null::* + * -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=8M -XX:-TieredCompilation -XX:TieredStopAtLevel=4 + * compiler.codecache.jmx.ThresholdNotificationsTest + */ + package compiler.codecache.jmx; import jdk.test.lib.Asserts; diff --git a/test/hotspot/jtreg/compiler/codecache/jmx/UsageThresholdExceededSeveralTimesTest.java b/test/hotspot/jtreg/compiler/codecache/jmx/UsageThresholdExceededSeveralTimesTest.java index 6f3402848f8..cffe5cc8774 100644 --- a/test/hotspot/jtreg/compiler/codecache/jmx/UsageThresholdExceededSeveralTimesTest.java +++ b/test/hotspot/jtreg/compiler/codecache/jmx/UsageThresholdExceededSeveralTimesTest.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 @@ -42,3 +42,26 @@ * -XX:-SegmentedCodeCache * compiler.codecache.jmx.UsageThresholdExceededTest */ + +/* + * @test UsageThresholdExceededSeveralTimesTest + * @requires vm.compiler2.enabled + * @summary verifying that getUsageThresholdCount() returns correct value + * after threshold has been hit several times + * @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 main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:-UseCodeCacheFlushing -XX:-MethodFlushing + * -XX:CompileCommand=compileonly,null::* -Djdk.test.lib.iterations=10 + * -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=8M -XX:+TieredCompilation -XX:TieredStopAtLevel=4 + * compiler.codecache.jmx.UsageThresholdExceededTest + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:-UseCodeCacheFlushing -XX:-MethodFlushing + * -XX:CompileCommand=compileonly,null::* -Djdk.test.lib.iterations=10 + * -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=8M -XX:-TieredCompilation -XX:TieredStopAtLevel=4 + * compiler.codecache.jmx.UsageThresholdExceededTest + */ diff --git a/test/hotspot/jtreg/compiler/codecache/jmx/UsageThresholdExceededTest.java b/test/hotspot/jtreg/compiler/codecache/jmx/UsageThresholdExceededTest.java index 1dae00b0035..7dd70bd0d04 100644 --- a/test/hotspot/jtreg/compiler/codecache/jmx/UsageThresholdExceededTest.java +++ b/test/hotspot/jtreg/compiler/codecache/jmx/UsageThresholdExceededTest.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 @@ -32,17 +32,40 @@ * @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 -XX:-UseCodeCacheFlushing -XX:-MethodFlushing + * -XX:+WhiteBoxAPI -XX:-UseCodeCacheFlushing -XX:-MethodFlushing * -XX:CompileCommand=compileonly,null::* * -XX:+SegmentedCodeCache * compiler.codecache.jmx.UsageThresholdExceededTest * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions - * -XX:+WhiteBoxAPI -XX:-UseCodeCacheFlushing -XX:-MethodFlushing + * -XX:+WhiteBoxAPI -XX:-UseCodeCacheFlushing -XX:-MethodFlushing * -XX:CompileCommand=compileonly,null::* * -XX:-SegmentedCodeCache * compiler.codecache.jmx.UsageThresholdExceededTest */ +/* + * @test UsageThresholdExceededTest + * @requires vm.compiler2.enabled + * @summary verifying that getUsageThresholdCount() returns correct value + * after threshold has been hit + * @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 main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:-UseCodeCacheFlushing -XX:-MethodFlushing + * -XX:CompileCommand=compileonly,null::* + * -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=8M -XX:+TieredCompilation -XX:TieredStopAtLevel=4 + * compiler.codecache.jmx.UsageThresholdExceededTest + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:-UseCodeCacheFlushing -XX:-MethodFlushing + * -XX:CompileCommand=compileonly,null::* + * -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=8M -XX:-TieredCompilation -XX:TieredStopAtLevel=4 + * compiler.codecache.jmx.UsageThresholdExceededTest + */ + package compiler.codecache.jmx; import jdk.test.whitebox.code.BlobType; diff --git a/test/hotspot/jtreg/compiler/codecache/jmx/UsageThresholdIncreasedTest.java b/test/hotspot/jtreg/compiler/codecache/jmx/UsageThresholdIncreasedTest.java index cb3f2c90364..a49a27a4d20 100644 --- a/test/hotspot/jtreg/compiler/codecache/jmx/UsageThresholdIncreasedTest.java +++ b/test/hotspot/jtreg/compiler/codecache/jmx/UsageThresholdIncreasedTest.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 @@ -42,6 +42,28 @@ * compiler.codecache.jmx.UsageThresholdIncreasedTest */ +/* + * @test UsageThresholdIncreasedTest + * @requires vm.compiler2.enabled + * @summary verifying that threshold hasn't been hit after allocation smaller + * than threshold value and that threshold value can be changed + * @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 main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:-UseCodeCacheFlushing -XX:-MethodFlushing + * -XX:CompileCommand=compileonly,null::* + * -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=8M -XX:+TieredCompilation -XX:TieredStopAtLevel=4 + * compiler.codecache.jmx.UsageThresholdIncreasedTest + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:-UseCodeCacheFlushing -XX:-MethodFlushing + * -XX:CompileCommand=compileonly,null::* + * -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=8M -XX:-TieredCompilation -XX:TieredStopAtLevel=4 + * compiler.codecache.jmx.UsageThresholdIncreasedTest + */ + package compiler.codecache.jmx; import jdk.test.whitebox.code.BlobType; diff --git a/test/hotspot/jtreg/compiler/codecache/jmx/UsageThresholdNotExceededTest.java b/test/hotspot/jtreg/compiler/codecache/jmx/UsageThresholdNotExceededTest.java index 1c13c89884b..0d75beb78da 100644 --- a/test/hotspot/jtreg/compiler/codecache/jmx/UsageThresholdNotExceededTest.java +++ b/test/hotspot/jtreg/compiler/codecache/jmx/UsageThresholdNotExceededTest.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 @@ -43,6 +43,29 @@ * compiler.codecache.jmx.UsageThresholdNotExceededTest */ +/* + * @test UsageThresholdNotExceededTest + * @requires vm.compiler2.enabled + * @summary verifying that usage threshold not exceeded while allocating less + * than usage threshold + * @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 main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:-UseCodeCacheFlushing -XX:-MethodFlushing + * -XX:CompileCommand=compileonly,null::* + * -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=8M -XX:+TieredCompilation -XX:TieredStopAtLevel=4 + * compiler.codecache.jmx.UsageThresholdNotExceededTest + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:-UseCodeCacheFlushing -XX:-MethodFlushing + * -XX:CompileCommand=compileonly,null::* + * -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=8M -XX:-TieredCompilation -XX:TieredStopAtLevel=4 + * compiler.codecache.jmx.UsageThresholdNotExceededTest + */ + package compiler.codecache.jmx; import jdk.test.whitebox.code.BlobType; diff --git a/test/hotspot/jtreg/compiler/codecache/stress/RandomAllocationTest.java b/test/hotspot/jtreg/compiler/codecache/stress/RandomAllocationTest.java index 26d3556d10e..d1d2da8523b 100644 --- a/test/hotspot/jtreg/compiler/codecache/stress/RandomAllocationTest.java +++ b/test/hotspot/jtreg/compiler/codecache/stress/RandomAllocationTest.java @@ -43,6 +43,29 @@ * compiler.codecache.stress.RandomAllocationTest */ +/* + * @test RandomAllocationTest + * @key stress randomness + * @requires vm.compiler2.enabled + * @summary stressing code cache by allocating randomly sized "dummy" code blobs + * @library /test/lib / + * @modules java.base/jdk.internal.misc + * java.management + * + * @build jdk.test.whitebox.WhiteBox compiler.codecache.stress.Helper compiler.codecache.stress.TestCaseImpl + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI + * -XX:CompileCommand=dontinline,compiler.codecache.stress.Helper$TestCase::method + * -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=8M -XX:+TieredCompilation -XX:TieredStopAtLevel=4 + * compiler.codecache.stress.RandomAllocationTest + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI + * -XX:CompileCommand=dontinline,compiler.codecache.stress.Helper$TestCase::method + * -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=8M -XX:-TieredCompilation -XX:TieredStopAtLevel=4 + * compiler.codecache.stress.RandomAllocationTest + */ + package compiler.codecache.stress; import jdk.test.whitebox.code.BlobType; diff --git a/test/hotspot/jtreg/compiler/hotcode/HotCodeCollectorMoveFunction.java b/test/hotspot/jtreg/compiler/hotcode/HotCodeCollectorMoveFunction.java new file mode 100644 index 00000000000..dd02de66881 --- /dev/null +++ b/test/hotspot/jtreg/compiler/hotcode/HotCodeCollectorMoveFunction.java @@ -0,0 +1,88 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * @test + * @library /test/lib / + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -Xbatch -XX:-TieredCompilation -XX:+SegmentedCodeCache -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap + * -XX:+NMethodRelocation -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:HotCodeIntervalSeconds=0 -XX:HotCodeCallLevel=0 + * -XX:HotCodeSampleSeconds=5 -XX:HotCodeStablePercent=-1 -XX:HotCodeSamplePercent=100 -XX:HotCodeStartupDelaySeconds=0 + * -XX:CompileCommand=compileonly,compiler.hotcode.HotCodeCollectorMoveFunction::func + * compiler.hotcode.HotCodeCollectorMoveFunction + */ + +package compiler.hotcode; + +import java.lang.reflect.Method; + +import jdk.test.lib.Asserts; +import jdk.test.whitebox.WhiteBox; +import jdk.test.whitebox.code.BlobType; +import jdk.test.whitebox.code.NMethod; + +public class HotCodeCollectorMoveFunction { + + private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); + private static final Method method; + private static final int C2_LEVEL = 4; + private static final int FUNC_RUN_MILLIS = 60_000; + + static { + try { + method = HotCodeCollectorMoveFunction.class.getMethod("func"); + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } + } + + public static void main(String[] args) throws Exception { + WHITE_BOX.testSetDontInlineMethod(method, true); + + compileFunc(); + + // Call function so collector samples and relocates + func(); + + // Function should now be in the Hot code heap after collector has had time to relocate + NMethod reloc_nm = NMethod.get(method, false); + Asserts.assertNotEquals(reloc_nm, null); + Asserts.assertEQ(reloc_nm.code_blob_type, BlobType.MethodHot); + } + + public static void compileFunc() { + WHITE_BOX.enqueueMethodForCompilation(method, C2_LEVEL); + + if (WHITE_BOX.getMethodCompilationLevel(method) != C2_LEVEL) { + throw new IllegalStateException("Method " + method + " is not compiled by C2."); + } + } + + public static void func() { + long start = System.currentTimeMillis(); + while (System.currentTimeMillis() - start < FUNC_RUN_MILLIS) {} + } + +} diff --git a/test/hotspot/jtreg/compiler/hotcode/StressHotCodeCollector.java b/test/hotspot/jtreg/compiler/hotcode/StressHotCodeCollector.java new file mode 100644 index 00000000000..4a7f9d2cc21 --- /dev/null +++ b/test/hotspot/jtreg/compiler/hotcode/StressHotCodeCollector.java @@ -0,0 +1,167 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * @test + * @library /test/lib / + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -Xcomp -XX:-TieredCompilation -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:+NMethodRelocation + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:HotCodeIntervalSeconds=0 -XX:HotCodeSampleSeconds=10 + * -XX:HotCodeStablePercent=-1 -XX:HotCodeSamplePercent=100 -XX:HotCodeStartupDelaySeconds=0 + * compiler.hotcode.StressHotCodeCollector + */ + +package compiler.hotcode; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Random; + +import jdk.test.lib.compiler.InMemoryJavaCompiler; +import jdk.test.whitebox.WhiteBox; + +public class StressHotCodeCollector { + + private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); + private static final double RUN_MILLIS = 60_000; + + private static TestMethod[] methods = new TestMethod[100]; + + private static byte[] num1; + private static byte[] num2; + + private static byte[] genNum(Random random, int digitCount) { + byte[] num = new byte[digitCount]; + int d; + do { + d = random.nextInt(10); + } while (d == 0); + + num[0] = (byte)d; + for (int i = 1; i < digitCount; ++i) { + num[i] = (byte)random.nextInt(10); + } + return num; + } + + private static void initNums() { + final long seed = 8374592837465123L; + Random random = new Random(seed); + + final int digitCount = 40; + num1 = genNum(random, digitCount); + num2 = genNum(random, digitCount); + } + + private static void generateCode() throws Exception { + byte[] result = new byte[num1.length + 1]; + + for (int i = 0; i < methods.length; i++) { + methods[i] = new TestMethod(); + } + } + + public static void main(String[] args) throws Exception { + + initNums(); + generateCode(); + + long start = System.currentTimeMillis(); + Random random = new Random(); + + while (System.currentTimeMillis() - start < RUN_MILLIS) { + for (TestMethod m : methods) { + if (random.nextInt(100) < 10) { + m.deoptimize(); + } + + byte[] result = new byte[num1.length + 1]; + m.invoke(num1, num2, result); + } + } + } + + private static final class TestMethod { + private static final String CLASS_NAME = "A"; + private static final String METHOD_TO_COMPILE = "sum"; + private static final String JAVA_CODE = """ + public class A { + + public static void sum(byte[] n1, byte[] n2, byte[] out) { + long start = System.currentTimeMillis(); + while (System.currentTimeMillis() - start < 100) {} + + final int digitCount = n1.length; + int carry = 0; + for (int i = digitCount - 1; i >= 0; --i) { + int sum = n1[i] + n2[i] + carry; + out[i] = (byte)(sum % 10); + carry = sum / 10; + } + if (carry != 0) { + for (int i = digitCount; i > 0; --i) { + out[i] = out[i - 1]; + } + out[0] = (byte)carry; + } + } + }"""; + + private static final byte[] BYTE_CODE; + + static { + BYTE_CODE = InMemoryJavaCompiler.compile(CLASS_NAME, JAVA_CODE); + } + + private final Method method; + + private static ClassLoader createClassLoaderFor() { + return new ClassLoader() { + @Override + public Class loadClass(String name) throws ClassNotFoundException { + if (!name.equals(CLASS_NAME)) { + return super.loadClass(name); + } + + return defineClass(name, BYTE_CODE, 0, BYTE_CODE.length); + } + }; + } + + public TestMethod() throws Exception { + var cl = createClassLoaderFor().loadClass(CLASS_NAME); + method = cl.getMethod(METHOD_TO_COMPILE, byte[].class, byte[].class, byte[].class); + WHITE_BOX.testSetDontInlineMethod(method, true); + } + + public void invoke(byte[] num1, byte[] num2, byte[] result) throws Exception { + method.invoke(null, num1, num2, result); + } + + public void deoptimize() { + WHITE_BOX.deoptimizeMethod(method); + } + } +} diff --git a/test/jdk/jdk/jfr/event/compiler/TestCodeCacheFull.java b/test/jdk/jdk/jfr/event/compiler/TestCodeCacheFull.java index 3d9cd083204..12c9d6c40fa 100644 --- a/test/jdk/jdk/jfr/event/compiler/TestCodeCacheFull.java +++ b/test/jdk/jdk/jfr/event/compiler/TestCodeCacheFull.java @@ -50,6 +50,12 @@ import jdk.test.whitebox.code.BlobType; * @run main/othervm -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:-SegmentedCodeCache jdk.jfr.event.compiler.TestCodeCacheFull + * @run main/othervm -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -XX:+TieredCompilation -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=8M jdk.jfr.event.compiler.TestCodeCacheFull + * @run main/othervm -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -XX:-TieredCompilation -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=8M jdk.jfr.event.compiler.TestCodeCacheFull */ public class TestCodeCacheFull { diff --git a/test/lib/jdk/test/whitebox/code/BlobType.java b/test/lib/jdk/test/whitebox/code/BlobType.java index a2290acc7b6..e2d57f79484 100644 --- a/test/lib/jdk/test/whitebox/code/BlobType.java +++ b/test/lib/jdk/test/whitebox/code/BlobType.java @@ -46,8 +46,16 @@ public enum BlobType { || type == BlobType.MethodNonProfiled; } }, + MethodHot(2, "CodeHeap 'hot nmethods'", "HotCodeHeapSize") { + @Override + public boolean allowTypeWhenOverflow(BlobType type) { + return super.allowTypeWhenOverflow(type) + || type == BlobType.MethodNonProfiled + || type == BlobType.MethodProfiled; + } + }, // Non-nmethods like Buffers, Adapters and Runtime Stubs - NonNMethod(2, "CodeHeap 'non-nmethods'", "NonNMethodCodeHeapSize") { + NonNMethod(3, "CodeHeap 'non-nmethods'", "NonNMethodCodeHeapSize") { @Override public boolean allowTypeWhenOverflow(BlobType type) { return super.allowTypeWhenOverflow(type) @@ -56,7 +64,7 @@ public enum BlobType { } }, // All types (No code cache segmentation) - All(3, "CodeCache", "ReservedCodeCacheSize"); + All(4, "CodeCache", "ReservedCodeCacheSize"); public final int id; public final String sizeOptionName; @@ -99,6 +107,10 @@ public enum BlobType { // there is no MethodProfiled in non tiered world or pure C1 result.remove(MethodProfiled); } + + if (Long.valueOf(0).equals(whiteBox.getVMFlag("HotCodeHeapSize"))) { + result.remove(MethodHot); + } return result; } From d68065e7474c07233cf1752c2a6efcaf9d35066d Mon Sep 17 00:00:00 2001 From: Erik Gahlin Date: Thu, 9 Apr 2026 16:20:56 +0000 Subject: [PATCH 227/359] 8365498: jdk/jfr/event/os/TestCPULoad.java fails with Expected at least one event Reviewed-by: mgronlun --- test/jdk/jdk/jfr/event/os/TestCPULoad.java | 72 ++++++---------------- 1 file changed, 18 insertions(+), 54 deletions(-) diff --git a/test/jdk/jdk/jfr/event/os/TestCPULoad.java b/test/jdk/jdk/jfr/event/os/TestCPULoad.java index 09ceb0a79b7..f3f30f15b2b 100644 --- a/test/jdk/jdk/jfr/event/os/TestCPULoad.java +++ b/test/jdk/jdk/jfr/event/os/TestCPULoad.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,10 +23,12 @@ package jdk.jfr.event.os; -import java.util.List; +import java.time.Duration; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; -import jdk.jfr.Recording; import jdk.jfr.consumer.RecordedEvent; +import jdk.jfr.consumer.RecordingStream; import jdk.test.lib.jfr.EventNames; import jdk.test.lib.jfr.Events; @@ -40,56 +42,18 @@ import jdk.test.lib.jfr.Events; public class TestCPULoad { private final static String EVENT_NAME = EventNames.CPULoad; - public static boolean isPrime(int num) { - if (num <= 1) return false; - for (int i = 2; i <= Math.sqrt(num); i++) { - if (num % i == 0) return false; - } - return true; - } - - public static int burnCpuCycles(int limit) { - int primeCount = 0; - for (int i = 2; i < limit; i++) { - if (isPrime(i)) { - primeCount++; - } - } - return primeCount; - } - - public static void main(String[] args) throws Throwable { - Recording recording = new Recording(); - recording.enable(EVENT_NAME); - recording.start(); - // burn some cycles to check increase of CPU related counters - int pn = burnCpuCycles(2500000); - recording.stop(); - System.out.println("Found " + pn + " primes while burning cycles"); - - List events = Events.fromRecording(recording); - if (events.isEmpty()) { - // CPU Load events are unreliable on Windows because - // the way processes are identified with perf. counters. - // See BUG 8010378. - // Workaround is to detect Windows and allow - // test to pass if events are missing. - if (isWindows()) { - return; - } - throw new AssertionError("Expected at least one event"); - } - for (RecordedEvent event : events) { - System.out.println("Event: " + event); - for (String loadName : loadNames) { - Events.assertField(event, loadName).atLeast(0.0f).atMost(1.0f); - } + public static void main(String... args) throws Exception { + try (RecordingStream rs = new RecordingStream()) { + BlockingQueue cpuEvent = new ArrayBlockingQueue<>(1); + rs.setReuse(false); + rs.enable(EVENT_NAME).withPeriod(Duration.ofMillis(100)); + rs.onEvent(cpuEvent::offer); + rs.startAsync(); + RecordedEvent event = cpuEvent.take(); + System.out.println(event); + Events.assertField(event, "jvmUser").atLeast(0.0f).atMost(1.0f); + Events.assertField(event, "jvmSystem").atLeast(0.0f).atMost(1.0f); + Events.assertField(event, "machineTotal").atLeast(0.0f).atMost(1.0f); } } - - private static final String[] loadNames = {"jvmUser", "jvmSystem", "machineTotal"}; - - private static boolean isWindows() { - return System.getProperty("os.name").startsWith("Windows"); - } -} +} \ No newline at end of file From e6bce14874a9243be461b058a696583dd6106ef3 Mon Sep 17 00:00:00 2001 From: Andrew Haley Date: Thu, 9 Apr 2026 17:01:16 +0000 Subject: [PATCH 228/359] 8381765: AArch32: Capstone hsdis does not build Reviewed-by: shade, erikj, jwaters --- make/Hsdis.gmk | 3 +++ src/utils/hsdis/capstone/hsdis-capstone.c | 5 +++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/make/Hsdis.gmk b/make/Hsdis.gmk index 469cc488f16..76695fc8dde 100644 --- a/make/Hsdis.gmk +++ b/make/Hsdis.gmk @@ -44,6 +44,9 @@ ifeq ($(HSDIS_BACKEND), capstone) else ifeq ($(call isTargetCpuArch, aarch64), true) CAPSTONE_ARCH := CS_ARCH_$(CAPSTONE_ARCH_AARCH64_NAME) CAPSTONE_MODE := CS_MODE_ARM + else ifeq ($(call isTargetCpuArch, arm), true) + CAPSTONE_ARCH := CS_ARCH_ARM + CAPSTONE_MODE := CS_MODE_ARM else $(error No support for Capstone on this platform) endif diff --git a/src/utils/hsdis/capstone/hsdis-capstone.c b/src/utils/hsdis/capstone/hsdis-capstone.c index d8a8719778d..7a17d150f40 100644 --- a/src/utils/hsdis/capstone/hsdis-capstone.c +++ b/src/utils/hsdis/capstone/hsdis-capstone.c @@ -58,6 +58,7 @@ and that causes invalid macro expansion. */ #undef aarch64 +#undef arm #include #include "hsdis.h" @@ -163,9 +164,9 @@ void* decode_instructions_virtual(uintptr_t start_va, uintptr_t end_va, size_t count = cs_disasm(cs_handle, buffer, length, (uintptr_t) buffer, 0 , &insn); if (count) { for (unsigned int j = 0; j < count; j++) { - (*event_callback)(event_stream, "insn", (void*) insn[j].address); + (*event_callback)(event_stream, "insn", (void*)(uintptr_t) insn[j].address); print("%s\t\t%s", insn[j].mnemonic, insn[j].op_str); - (*event_callback)(event_stream, "/insn", (void*) (insn[j].address + insn[j].size)); + (*event_callback)(event_stream, "/insn", (void*)(uintptr_t) (insn[j].address + insn[j].size)); if (newline) { /* follow each complete insn by a nice newline */ print("\n"); From 20387ffafcd6d45de8b8ee254da3a04702ad0752 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Thu, 9 Apr 2026 18:28:09 +0000 Subject: [PATCH 229/359] 8381879: JDK-8372617 has broken the Zero build Reviewed-by: kvn --- src/hotspot/share/code/aotCodeCache.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/hotspot/share/code/aotCodeCache.cpp b/src/hotspot/share/code/aotCodeCache.cpp index d3888d1b7eb..6594d94fa91 100644 --- a/src/hotspot/share/code/aotCodeCache.cpp +++ b/src/hotspot/share/code/aotCodeCache.cpp @@ -1905,9 +1905,6 @@ void AOTCodeAddressTable::init_extrs() { ADD_EXTERNAL_ADDRESS(SharedRuntime::handle_wrong_method_ic_miss); #if defined(AARCH64) && !defined(ZERO) ADD_EXTERNAL_ADDRESS(JavaThread::aarch64_get_thread_helper); -#endif - -#if defined(AARCH64) ADD_EXTERNAL_ADDRESS(BarrierSetAssembler::patching_epoch_addr()); #endif From df09910ec879dc628484588a3137298504fceaf1 Mon Sep 17 00:00:00 2001 From: Erik Joelsson Date: Thu, 9 Apr 2026 18:33:47 +0000 Subject: [PATCH 230/359] 8380947: Add pull request template Reviewed-by: mr --- .github/pull_request_template.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .github/pull_request_template.md diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 00000000000..d3f63784ece --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,5 @@ + + + +--------- +- [ ] I confirm that I make this contribution in accordance with the [OpenJDK Interim AI Policy](https://openjdk.org/legal/ai). From 24f7945779c810671d545ed0a618485a313134b0 Mon Sep 17 00:00:00 2001 From: Yasumasa Suenaga Date: Thu, 9 Apr 2026 23:49:11 +0000 Subject: [PATCH 231/359] 8377946: Use DWARF in mixed jstack on Linux AArch64 Reviewed-by: cjplummer, kevinw, erikj --- make/modules/jdk.hotspot.agent/Lib.gmk | 9 +- .../linux/native/libsaproc/DwarfParser.cpp | 180 ++++++++------- .../native/libsaproc/LinuxDebuggerLocal.cpp | 18 +- .../linux/native/libsaproc/dwarf.cpp | 14 ++ .../linux/native/libsaproc/dwarf.hpp | 38 ++-- .../native/libsaproc/dwarf_regs_aarch64.h | 78 +++++++ .../linux/native/libsaproc/dwarf_regs_amd64.h | 61 ++++++ .../linux/native/libsaproc/libproc.h | 6 +- .../linux/native/libsaproc/libproc_impl.c | 6 + .../linux/native/libsaproc/libproc_impl.h | 4 + .../linux/native/libsaproc/ps_core.c | 44 +++- .../linux/native/libsaproc/ps_proc.c | 17 +- .../linux/native/libsaproc/symtab.c | 8 +- .../sun/jvm/hotspot/debugger/cdbg/CFrame.java | 4 +- .../hotspot/debugger/linux/DwarfCFrame.java | 187 ++++++++++++++++ .../linux/{amd64 => }/DwarfParser.java | 4 +- .../debugger/linux/LinuxCDebugger.java | 8 +- .../hotspot/debugger/linux/LinuxDebugger.java | 11 +- .../debugger/linux/LinuxDebuggerLocal.java | 2 +- .../linux/aarch64/LinuxAARCH64CFrame.java | 179 ++++++++++----- .../aarch64/LinuxAARCH64ThreadContext.java | 23 +- .../linux/amd64/LinuxAMD64CFrame.java | 206 ++++-------------- .../sa/TestJhsdbJstackMixedWithXComp.java | 6 +- 23 files changed, 754 insertions(+), 359 deletions(-) create mode 100644 src/jdk.hotspot.agent/linux/native/libsaproc/dwarf_regs_aarch64.h create mode 100644 src/jdk.hotspot.agent/linux/native/libsaproc/dwarf_regs_amd64.h create mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/DwarfCFrame.java rename src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/{amd64 => }/DwarfParser.java (95%) diff --git a/make/modules/jdk.hotspot.agent/Lib.gmk b/make/modules/jdk.hotspot.agent/Lib.gmk index ed8de631dc3..da02e0dab39 100644 --- a/make/modules/jdk.hotspot.agent/Lib.gmk +++ b/make/modules/jdk.hotspot.agent/Lib.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -55,6 +55,12 @@ else LIBSAPROC_LINK_TYPE := C endif +# DWARF related sources would be included on supported platforms only. +LIBSAPROC_EXCLUDE_FILES := +ifneq ($(call And, $(call isTargetOs, linux) $(call isTargetCpu, x86_64 aarch64)), true) + LIBSAPROC_EXCLUDE_FILES := DwarfParser.cpp dwarf.cpp +endif + $(eval $(call SetupJdkLibrary, BUILD_LIBSAPROC, \ NAME := saproc, \ LINK_TYPE := $(LIBSAPROC_LINK_TYPE), \ @@ -70,6 +76,7 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBSAPROC, \ CFLAGS := $(LIBSAPROC_CFLAGS), \ CXXFLAGS := $(LIBSAPROC_CFLAGS) $(LIBSAPROC_CXXFLAGS), \ EXTRA_SRC := $(LIBSAPROC_EXTRA_SRC), \ + EXCLUDE_FILES := $(LIBSAPROC_EXCLUDE_FILES), \ JDK_LIBS := java.base:libjava, \ LIBS_linux := $(LIBDL), \ LIBS_macosx := \ diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/DwarfParser.cpp b/src/jdk.hotspot.agent/linux/native/libsaproc/DwarfParser.cpp index 62dbc84f88c..cc03f3fc832 100644 --- a/src/jdk.hotspot.agent/linux/native/libsaproc/DwarfParser.cpp +++ b/src/jdk.hotspot.agent/linux/native/libsaproc/DwarfParser.cpp @@ -31,73 +31,54 @@ #define CHECK_EXCEPTION if (env->ExceptionCheck()) { return; } static jfieldID p_dwarf_context_ID = 0; -static jint sa_RAX = -1; -static jint sa_RDX = -1; -static jint sa_RCX = -1; -static jint sa_RBX = -1; -static jint sa_RSI = -1; -static jint sa_RDI = -1; -static jint sa_RBP = -1; -static jint sa_RSP = -1; -static jint sa_R8 = -1; -static jint sa_R9 = -1; -static jint sa_R10 = -1; -static jint sa_R11 = -1; -static jint sa_R12 = -1; -static jint sa_R13 = -1; -static jint sa_R14 = -1; -static jint sa_R15 = -1; + +// DWARF_REG macro is used by DWARF_REGLIST. +#define DWARF_REG(reg, _) \ + static jint sa_##reg = -1; + +DWARF_REGLIST + +#undef DWARF_REG static jlong get_dwarf_context(JNIEnv *env, jobject obj) { return env->GetLongField(obj, p_dwarf_context_ID); } -#define SET_REG(env, reg, reg_cls) \ +/* + * Class: sun_jvm_hotspot_debugger_linux_DwarfParser + * Method: init0 + * Signature: ()V + */ +extern "C" +JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_linux_DwarfParser_init0 + (JNIEnv *env, jclass this_cls) { + jclass cls = env->FindClass("sun/jvm/hotspot/debugger/linux/DwarfParser"); + CHECK_EXCEPTION + p_dwarf_context_ID = env->GetFieldID(cls, "p_dwarf_context", "J"); + CHECK_EXCEPTION + + jclass reg_cls = env->FindClass(THREAD_CONTEXT_CLASS); + CHECK_EXCEPTION + +// DWARF_REG macro is used by DWARF_REGLIST. +#define DWARF_REG(reg, _) \ jfieldID reg##_ID = env->GetStaticFieldID(reg_cls, #reg, "I"); \ CHECK_EXCEPTION \ sa_##reg = env->GetStaticIntField(reg_cls, reg##_ID); \ CHECK_EXCEPTION -/* - * Class: sun_jvm_hotspot_debugger_linux_amd64_DwarfParser - * Method: init0 - * Signature: ()V - */ -extern "C" -JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_linux_amd64_DwarfParser_init0 - (JNIEnv *env, jclass this_cls) { - jclass cls = env->FindClass("sun/jvm/hotspot/debugger/linux/amd64/DwarfParser"); - CHECK_EXCEPTION - p_dwarf_context_ID = env->GetFieldID(cls, "p_dwarf_context", "J"); - CHECK_EXCEPTION + DWARF_REGLIST - jclass reg_cls = env->FindClass("sun/jvm/hotspot/debugger/amd64/AMD64ThreadContext"); - CHECK_EXCEPTION - SET_REG(env, RAX, reg_cls); - SET_REG(env, RDX, reg_cls); - SET_REG(env, RCX, reg_cls); - SET_REG(env, RBX, reg_cls); - SET_REG(env, RSI, reg_cls); - SET_REG(env, RDI, reg_cls); - SET_REG(env, RBP, reg_cls); - SET_REG(env, RSP, reg_cls); - SET_REG(env, R8, reg_cls); - SET_REG(env, R9, reg_cls); - SET_REG(env, R10, reg_cls); - SET_REG(env, R11, reg_cls); - SET_REG(env, R12, reg_cls); - SET_REG(env, R13, reg_cls); - SET_REG(env, R14, reg_cls); - SET_REG(env, R15, reg_cls); +#undef DWARF_REG } /* - * Class: sun_jvm_hotspot_debugger_linux_amd64_DwarfParser + * Class: sun_jvm_hotspot_debugger_linux_DwarfParser * Method: createDwarfContext * Signature: (J)J */ extern "C" -JNIEXPORT jlong JNICALL Java_sun_jvm_hotspot_debugger_linux_amd64_DwarfParser_createDwarfContext +JNIEXPORT jlong JNICALL Java_sun_jvm_hotspot_debugger_linux_DwarfParser_createDwarfContext (JNIEnv *env, jclass this_cls, jlong lib) { DwarfParser *parser = new DwarfParser(reinterpret_cast(lib)); if (!parser->is_parseable()) { @@ -113,36 +94,36 @@ JNIEXPORT jlong JNICALL Java_sun_jvm_hotspot_debugger_linux_amd64_DwarfParser_cr } /* - * Class: sun_jvm_hotspot_debugger_linux_amd64_DwarfParser + * Class: sun_jvm_hotspot_debugger_linux_DwarfParser * Method: destroyDwarfContext * Signature: (J)V */ extern "C" -JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_linux_amd64_DwarfParser_destroyDwarfContext +JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_linux_DwarfParser_destroyDwarfContext (JNIEnv *env, jclass this_cls, jlong context) { DwarfParser *parser = reinterpret_cast(context); delete parser; } /* - * Class: sun_jvm_hotspot_debugger_linux_amd64_DwarfParser + * Class: sun_jvm_hotspot_debugger_linux_DwarfParser * Method: isIn0 * Signature: (J)Z */ extern "C" -JNIEXPORT jboolean JNICALL Java_sun_jvm_hotspot_debugger_linux_amd64_DwarfParser_isIn0 +JNIEXPORT jboolean JNICALL Java_sun_jvm_hotspot_debugger_linux_DwarfParser_isIn0 (JNIEnv *env, jobject this_obj, jlong pc) { DwarfParser *parser = reinterpret_cast(get_dwarf_context(env, this_obj)); return static_cast(parser->is_in(pc)); } /* - * Class: sun_jvm_hotspot_debugger_linux_amd64_DwarfParser + * Class: sun_jvm_hotspot_debugger_linux_DwarfParser * Method: processDwarf0 * Signature: (J)V */ extern "C" -JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_linux_amd64_DwarfParser_processDwarf0 +JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_linux_DwarfParser_processDwarf0 (JNIEnv *env, jobject this_obj, jlong pc) { DwarfParser *parser = reinterpret_cast(get_dwarf_context(env, this_obj)); if (!parser->process_dwarf(pc)) { @@ -155,67 +136,106 @@ JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_linux_amd64_DwarfParser_pro } /* - * Class: sun_jvm_hotspot_debugger_linux_amd64_DwarfParser + * Class: sun_jvm_hotspot_debugger_linux_DwarfParser * Method: getCFARegister * Signature: ()I */ extern "C" -JNIEXPORT jint JNICALL Java_sun_jvm_hotspot_debugger_linux_amd64_DwarfParser_getCFARegister +JNIEXPORT jint JNICALL Java_sun_jvm_hotspot_debugger_linux_DwarfParser_getCFARegister (JNIEnv *env, jobject this_obj) { DwarfParser *parser = reinterpret_cast(get_dwarf_context(env, this_obj)); + switch (parser->get_cfa_register()) { - case RAX: return sa_RAX; - case RDX: return sa_RDX; - case RCX: return sa_RCX; - case RBX: return sa_RBX; - case RSI: return sa_RSI; - case RDI: return sa_RDI; - case RBP: return sa_RBP; - case RSP: return sa_RSP; - case R8: return sa_R8; - case R9: return sa_R9; - case R10: return sa_R10; - case R11: return sa_R11; - case R12: return sa_R12; - case R13: return sa_R13; - case R14: return sa_R14; - case R15: return sa_R15; +// DWARF_REG macro is used by DWARF_REGLIST. +#define DWARF_REG(reg, _) \ + case reg: return sa_##reg; + + DWARF_REGLIST + +#undef DWARF_REG + default: return -1; } } /* - * Class: sun_jvm_hotspot_debugger_linux_amd64_DwarfParser + * Class: sun_jvm_hotspot_debugger_linux_DwarfParser * Method: getCFAOffset * Signature: ()I */ extern "C" -JNIEXPORT jint JNICALL Java_sun_jvm_hotspot_debugger_linux_amd64_DwarfParser_getCFAOffset +JNIEXPORT jint JNICALL Java_sun_jvm_hotspot_debugger_linux_DwarfParser_getCFAOffset (JNIEnv *env, jobject this_obj) { DwarfParser *parser = reinterpret_cast(get_dwarf_context(env, this_obj)); return parser->get_cfa_offset(); } /* - * Class: sun_jvm_hotspot_debugger_linux_amd64_DwarfParser + * Class: sun_jvm_hotspot_debugger_linux_DwarfParser + * Method: getOffsetFromCFA + * Signature: (I)I + */ +extern "C" +JNIEXPORT jint JNICALL Java_sun_jvm_hotspot_debugger_linux_DwarfParser_getOffsetFromCFA + (JNIEnv *env, jobject this_obj, jint sareg) { + DwarfParser *parser = reinterpret_cast(get_dwarf_context(env, this_obj)); + +// DWARF_REG macro is used by DWARF_REGLIST. +#define DWARF_REG(reg, dwreg) \ + if (sareg == sa_##reg) { \ + return parser->get_offset_from_cfa(static_cast(dwreg)); \ + } else + + DWARF_REGLIST + +#undef DWARF_REG + + return INT_MAX; +} + +/* + * Class: sun_jvm_hotspot_debugger_linux_DwarfParser + * Method: getRARegister + * Signature: ()I + */ +extern "C" +JNIEXPORT jint JNICALL Java_sun_jvm_hotspot_debugger_linux_DwarfParser_getRARegister + (JNIEnv *env, jobject this_obj) { + DwarfParser *parser = reinterpret_cast(get_dwarf_context(env, this_obj)); + + switch (parser->get_ra_register()) { +// DWARF_REG macro is used by DWARF_REGLIST. +#define DWARF_REG(reg, _) \ + case reg: return sa_##reg; + + DWARF_REGLIST + +#undef DWARF_REG + + default: return -1; + } +} + +/* + * Class: sun_jvm_hotspot_debugger_linux_DwarfParser * Method: getReturnAddressOffsetFromCFA * Signature: ()I */ extern "C" -JNIEXPORT jint JNICALL Java_sun_jvm_hotspot_debugger_linux_amd64_DwarfParser_getReturnAddressOffsetFromCFA +JNIEXPORT jint JNICALL Java_sun_jvm_hotspot_debugger_linux_DwarfParser_getReturnAddressOffsetFromCFA (JNIEnv *env, jobject this_obj) { DwarfParser *parser = reinterpret_cast(get_dwarf_context(env, this_obj)); return parser->get_offset_from_cfa(RA); } /* - * Class: sun_jvm_hotspot_debugger_linux_amd64_DwarfParser + * Class: sun_jvm_hotspot_debugger_linux_DwarfParser * Method: getBasePointerOffsetFromCFA * Signature: ()I */ extern "C" -JNIEXPORT jint JNICALL Java_sun_jvm_hotspot_debugger_linux_amd64_DwarfParser_getBasePointerOffsetFromCFA +JNIEXPORT jint JNICALL Java_sun_jvm_hotspot_debugger_linux_DwarfParser_getBasePointerOffsetFromCFA (JNIEnv *env, jobject this_obj) { DwarfParser *parser = reinterpret_cast(get_dwarf_context(env, this_obj)); - return parser->get_offset_from_cfa(RBP); + return parser->get_offset_from_cfa(BP); } diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/LinuxDebuggerLocal.cpp b/src/jdk.hotspot.agent/linux/native/libsaproc/LinuxDebuggerLocal.cpp index caf948019af..214e2f21ac6 100644 --- a/src/jdk.hotspot.agent/linux/native/libsaproc/LinuxDebuggerLocal.cpp +++ b/src/jdk.hotspot.agent/linux/native/libsaproc/LinuxDebuggerLocal.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2019, 2021, NTT DATA. + * Copyright (c) 2002, 2026, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, 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 @@ -289,6 +289,13 @@ JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal_at snprintf(msg, sizeof(msg), "Can't attach to the process: %s", err_buf); THROW_NEW_DEBUGGER_EXCEPTION(msg); } + +#ifdef __aarch64__ + if (pac_enabled(ph)) { + printf("WARNING: PAC is enabled. Stack traces might be incomplete.\n"); + } +#endif + env->SetLongField(this_obj, p_ps_prochandle_ID, (jlong)(intptr_t)ph); fillThreadsAndLoadObjects(env, this_obj, ph); } @@ -313,6 +320,13 @@ JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal_at if ( (ph = Pgrab_core(execName_cstr, coreName_cstr)) == NULL) { THROW_NEW_DEBUGGER_EXCEPTION("Can't attach to the core file. For more information, export LIBSAPROC_DEBUG=1 and try again."); } + +#ifdef __aarch64__ + if (pac_enabled(ph)) { + printf("WARNING: PAC is enabled. Stack traces might be incomplete.\n"); + } +#endif + env->SetLongField(this_obj, p_ps_prochandle_ID, (jlong)(intptr_t)ph); fillThreadsAndLoadObjects(env, this_obj, ph); } diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/dwarf.cpp b/src/jdk.hotspot.agent/linux/native/libsaproc/dwarf.cpp index 459e3cc57e9..28eb92a285f 100644 --- a/src/jdk.hotspot.agent/linux/native/libsaproc/dwarf.cpp +++ b/src/jdk.hotspot.agent/linux/native/libsaproc/dwarf.cpp @@ -217,6 +217,20 @@ void DwarfParser::parse_dwarf_instructions(uintptr_t begin, uintptr_t pc, const _state.offset_from_cfa[reg] = _initial_state.offset_from_cfa[reg]; break; } +#ifdef __aarch64__ + // SA hasn't yet supported Pointer Authetication Code (PAC), so following + // instructions would be ignored with warning message. + // https://github.com/ARM-software/abi-aa/blob/2025Q4/aadwarf64/aadwarf64.rst + case 0x2d: // DW_CFA_AARCH64_negate_ra_state + print_debug("DWARF: DW_CFA_AARCH64_negate_ra_state is unimplemented.\n", op); + break; + case 0x2c: // DW_CFA_AARCH64_negate_ra_state_with_pc + print_debug("DWARF: DW_CFA_AARCH64_negate_ra_state_with_pc is unimplemented.\n", op); + break; + case 0x2b: // DW_CFA_AARCH64_set_ra_state + print_debug("DWARF: DW_CFA_AARCH64_set_ra_state is unimplemented.\n", op); + break; +#endif default: print_debug("DWARF: Unknown opcode: 0x%x\n", op); return; diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/dwarf.hpp b/src/jdk.hotspot.agent/linux/native/libsaproc/dwarf.hpp index 0a38c9a0f2e..2bfdba65a78 100644 --- a/src/jdk.hotspot.agent/linux/native/libsaproc/dwarf.hpp +++ b/src/jdk.hotspot.agent/linux/native/libsaproc/dwarf.hpp @@ -30,30 +30,21 @@ #include "libproc_impl.h" -/* - * from System V Application Binary Interface - * AMD64 Architecture Processor Supplement - * Figure 3.38: DWARF Register Number Mapping - * https://software.intel.com/sites/default/files/article/402129/mpx-linux64-abi.pdf - */ +#ifdef __x86_64__ +#include "dwarf_regs_amd64.h" +#elif defined(__aarch64__) +#include "dwarf_regs_aarch64.h" +#endif + enum DWARF_Register { - RAX, - RDX, - RCX, - RBX, - RSI, - RDI, - RBP, - RSP, - R8, - R9, - R10, - R11, - R12, - R13, - R14, - R15, - RA, +// DWARF_REG macro is used by DWARF_REGLIST and DWARF_PSEUDO_REGLIST. +#define DWARF_REG(reg, no) \ + reg = no, + + DWARF_REGLIST + DWARF_PSEUDO_REGLIST + +#undef DWARF_REG MAX_VALUE }; @@ -94,6 +85,7 @@ class DwarfParser { bool process_dwarf(const uintptr_t pc); enum DWARF_Register get_cfa_register() { return _state.cfa_reg; } int get_cfa_offset() { return _state.cfa_offset; } + enum DWARF_Register get_ra_register() { return _state.return_address_reg; } int get_offset_from_cfa(enum DWARF_Register reg) { return _state.offset_from_cfa[reg]; } bool is_in(long pc) { diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/dwarf_regs_aarch64.h b/src/jdk.hotspot.agent/linux/native/libsaproc/dwarf_regs_aarch64.h new file mode 100644 index 00000000000..5a95e9405e1 --- /dev/null +++ b/src/jdk.hotspot.agent/linux/native/libsaproc/dwarf_regs_aarch64.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2026, 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. + * + */ + +#ifndef DWARF_REGS_AARCH64_H +#define DWARF_REGS_AARCH64_H + +#define THREAD_CONTEXT_CLASS "sun/jvm/hotspot/debugger/aarch64/AARCH64ThreadContext" + +/* + * from DWARF for the Arm (R) 64-bit Architecture (AArch64) + * https://github.com/ARM-software/abi-aa/blob/2025Q4/aadwarf64/aadwarf64.rst + * 4.1 DWARF register names + */ +#define DWARF_REGLIST \ + DWARF_REG(R0, 0) \ + DWARF_REG(R1, 1) \ + DWARF_REG(R2, 2) \ + DWARF_REG(R3, 3) \ + DWARF_REG(R4, 4) \ + DWARF_REG(R5, 5) \ + DWARF_REG(R6, 6) \ + DWARF_REG(R7, 7) \ + DWARF_REG(R8, 8) \ + DWARF_REG(R9, 9) \ + DWARF_REG(R10, 10) \ + DWARF_REG(R11, 11) \ + DWARF_REG(R12, 12) \ + DWARF_REG(R13, 13) \ + DWARF_REG(R14, 14) \ + DWARF_REG(R15, 15) \ + DWARF_REG(R16, 16) \ + DWARF_REG(R17, 17) \ + DWARF_REG(R18, 18) \ + DWARF_REG(R19, 19) \ + DWARF_REG(R20, 20) \ + DWARF_REG(R21, 21) \ + DWARF_REG(R22, 22) \ + DWARF_REG(R23, 23) \ + DWARF_REG(R24, 24) \ + DWARF_REG(R25, 25) \ + DWARF_REG(R26, 26) \ + DWARF_REG(R27, 27) \ + DWARF_REG(R28, 28) \ + DWARF_REG(FP, 29) \ + DWARF_REG(LR, 30) \ + DWARF_REG(SP, 31) \ + DWARF_REG(PC, 32) + +// RA_SIGN_STATE might be needed in future to handle PAC. +#define DWARF_PSEUDO_REGLIST + +/* Aliases */ +#define BP FP +#define RA LR + +#endif diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/dwarf_regs_amd64.h b/src/jdk.hotspot.agent/linux/native/libsaproc/dwarf_regs_amd64.h new file mode 100644 index 00000000000..8226bc0864c --- /dev/null +++ b/src/jdk.hotspot.agent/linux/native/libsaproc/dwarf_regs_amd64.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2026, 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. + * + */ + +#ifndef DWARF_REGS_AMD64_H +#define DWARF_REGS_AMD64_H + +#define THREAD_CONTEXT_CLASS "sun/jvm/hotspot/debugger/amd64/AMD64ThreadContext" + +/* + * from System V Application Binary Interface + * AMD64 Architecture Processor Supplement + * https://refspecs.linuxbase.org/elf/x86_64-abi-0.99.pdf + * Figure 3.36: DWARF Register Number Mapping + */ +#define DWARF_REGLIST \ + DWARF_REG(RAX, 0) \ + DWARF_REG(RDX, 1) \ + DWARF_REG(RCX, 2) \ + DWARF_REG(RBX, 3) \ + DWARF_REG(RSI, 4) \ + DWARF_REG(RDI, 5) \ + DWARF_REG(RBP, 6) \ + DWARF_REG(RSP, 7) \ + DWARF_REG(R8, 8) \ + DWARF_REG(R9, 9) \ + DWARF_REG(R10, 10) \ + DWARF_REG(R11, 11) \ + DWARF_REG(R12, 12) \ + DWARF_REG(R13, 13) \ + DWARF_REG(R14, 14) \ + DWARF_REG(R15, 15) + +#define DWARF_PSEUDO_REGLIST \ + DWARF_REG(RA, 16) + +/* Aliases */ +#define BP RBP + +#endif diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/libproc.h b/src/jdk.hotspot.agent/linux/native/libsaproc/libproc.h index a69496e77a4..c584131e285 100644 --- a/src/jdk.hotspot.agent/linux/native/libsaproc/libproc.h +++ b/src/jdk.hotspot.agent/linux/native/libsaproc/libproc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -119,6 +119,10 @@ struct ps_prochandle* get_proc_handle(JNIEnv* env, jobject this_obj); void throw_new_debugger_exception(JNIEnv* env, const char* errMsg); +#ifdef __aarch64__ +bool pac_enabled(struct ps_prochandle* ph); +#endif + #ifdef __cplusplus } #endif diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/libproc_impl.c b/src/jdk.hotspot.agent/linux/native/libsaproc/libproc_impl.c index 029aac1f107..815902045cf 100644 --- a/src/jdk.hotspot.agent/linux/native/libsaproc/libproc_impl.c +++ b/src/jdk.hotspot.agent/linux/native/libsaproc/libproc_impl.c @@ -478,6 +478,12 @@ struct lib_info *find_lib_by_address(struct ps_prochandle* ph, uintptr_t pc) { return NULL; } +#ifdef __aarch64__ +bool pac_enabled(struct ps_prochandle* ph) { + return ph->pac_enabled; +} +#endif + //-------------------------------------------------------------------------- // proc service functions diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/libproc_impl.h b/src/jdk.hotspot.agent/linux/native/libsaproc/libproc_impl.h index 62b1b4d0d6b..d5aa74e73ad 100644 --- a/src/jdk.hotspot.agent/linux/native/libsaproc/libproc_impl.h +++ b/src/jdk.hotspot.agent/linux/native/libsaproc/libproc_impl.h @@ -115,6 +115,10 @@ struct ps_prochandle { int num_threads; thread_info* threads; // head of thread list struct core_data* core; // data only used for core dumps, NULL for process +#ifdef __aarch64__ + // true if the HWCAP_PACA variant of Pointer Authentication Code (PAC) is enabled. + bool pac_enabled; +#endif }; #ifdef __cplusplus diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/ps_core.c b/src/jdk.hotspot.agent/linux/native/libsaproc/ps_core.c index 6298f569aaf..c500360f39d 100644 --- a/src/jdk.hotspot.agent/linux/native/libsaproc/ps_core.c +++ b/src/jdk.hotspot.agent/linux/native/libsaproc/ps_core.c @@ -39,6 +39,12 @@ #include "proc_service.h" #include "salibelf.h" +// HWCAP_PACA was introduced in glibc 2.30 +// https://sourceware.org/git/?p=glibc.git;a=commit;h=a2e57f89a35e6056c9488428e68c4889e114ef71 +#if defined(__aarch64__) && !defined(HWCAP_PACA) +#define HWCAP_PACA (1 << 30) +#endif + // This file has the libproc implementation to read core files. // For live processes, refer to ps_proc.c. Portions of this is adapted // /modelled after Solaris libproc.so (in particular Pcore.c) @@ -290,6 +296,10 @@ static bool core_handle_note(struct ps_prochandle* ph, ELF_PHDR* note_phdr) { break; } else if (auxv->a_type == AT_SYSINFO_EHDR) { ph->core->vdso_addr = auxv->a_un.a_val; +#ifdef __aarch64__ + } else if (auxv->a_type == AT_HWCAP) { + ph->pac_enabled = auxv->a_un.a_val & HWCAP_PACA; +#endif } auxv++; } @@ -610,23 +620,38 @@ static uintptr_t calc_prelinked_load_address(struct ps_prochandle* ph, int lib_f return load_addr; } +static int handle_vdso_internal(struct ps_prochandle* ph, char* vdso_name, char* lib_name, size_t lib_name_len) { + int lib_fd; + struct utsname uts; + uname(&uts); + + char *vdso_path = (char*)malloc(lib_name_len); + snprintf(vdso_path, lib_name_len, "/lib/modules/%s/vdso/%s", uts.release, vdso_name); + print_debug("Try to open vDSO: %s\n", vdso_path); + lib_fd = pathmap_open(vdso_path); + if (lib_fd != -1) { + print_debug("replace vDSO: %s -> %s\n", lib_name, vdso_path); + strncpy(lib_name, vdso_path, lib_name_len); + } + + free(vdso_path); + return lib_fd; +} + // Check for vDSO binary in kernel directory (/lib/modules//vdso), // rewrite the given lib_name string if found. // Otherwise copy vDSO memory in coredump to temporal file generated by tmpfile(). // Returns FD for vDSO (should be closed by caller), or -1 on error. static int handle_vdso(struct ps_prochandle* ph, char* lib_name, size_t lib_name_len) { int lib_fd; - struct utsname uts; - uname(&uts); // Check vDSO binary first (for referring debuginfo if possible). - char *vdso_path = (char*)malloc(lib_name_len); - snprintf(vdso_path, lib_name_len, "/lib/modules/%s/vdso/vdso64.so", uts.release); - lib_fd = pathmap_open(vdso_path); - if (lib_fd != -1) { - print_debug("replace vDSO: %s -> %s\n", lib_name, vdso_path); - strncpy(lib_name, vdso_path, lib_name_len); - } else { + lib_fd = handle_vdso_internal(ph, "vdso64.so", lib_name, lib_name_len); + if (lib_fd == -1) { + // Try again with vdso.so + lib_fd = handle_vdso_internal(ph, "vdso.so", lib_name, lib_name_len); + } + if (lib_fd == -1) { // Copy vDSO memory segment from core to temporal memory // if vDSO binary is not available. FILE* tmpf = tmpfile(); @@ -644,7 +669,6 @@ static int handle_vdso(struct ps_prochandle* ph, char* lib_name, size_t lib_name } } - free(vdso_path); return lib_fd; } diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/ps_proc.c b/src/jdk.hotspot.agent/linux/native/libsaproc/ps_proc.c index fdaa30c3f5d..9cbde7319f0 100644 --- a/src/jdk.hotspot.agent/linux/native/libsaproc/ps_proc.c +++ b/src/jdk.hotspot.agent/linux/native/libsaproc/ps_proc.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * 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,17 @@ #include #include "libproc_impl.h" +#ifdef __aarch64__ +#include + +// HWCAP_PACA was introduced in glibc 2.30 +// https://sourceware.org/git/?p=glibc.git;a=commit;h=a2e57f89a35e6056c9488428e68c4889e114ef71 +#ifndef HWCAP_PACA +#define HWCAP_PACA (1 << 30) +#endif + +#endif + #if defined(x86_64) && !defined(amd64) #define amd64 1 #endif @@ -460,6 +471,10 @@ Pgrab(pid_t pid, char* err_buf, size_t err_buf_len) { return NULL; } +#ifdef __aarch64__ + ph->pac_enabled = HWCAP_PACA & getauxval(AT_HWCAP); +#endif + // initialize ps_prochandle ph->pid = pid; if (add_thread_info(ph, ph->pid) == NULL) { diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/symtab.c b/src/jdk.hotspot.agent/linux/native/libsaproc/symtab.c index c8f3fb2ed4c..8f8ce28be1e 100644 --- a/src/jdk.hotspot.agent/linux/native/libsaproc/symtab.c +++ b/src/jdk.hotspot.agent/linux/native/libsaproc/symtab.c @@ -417,10 +417,14 @@ static struct symtab* build_symtab_internal(int fd, const char *filename, bool t uintptr_t sym_value; char *sym_name = symtab->strs + syms->st_name; - // skip non-object and non-function symbols + // skip non-object and non-function symbols, but STT_NOTYPE is allowed for + // signal trampoline. int st_type = ELF_ST_TYPE(syms->st_info); - if ( st_type != STT_FUNC && st_type != STT_OBJECT) + if (st_type != STT_FUNC && + st_type != STT_OBJECT && + st_type != STT_NOTYPE) { continue; + } // skip empty strings and undefined symbols if (*sym_name == '\0' || syms->st_shndx == SHN_UNDEF) continue; diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/CFrame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/CFrame.java index bc366ef02b5..86f9e990af8 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/CFrame.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/CFrame.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * 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 interface CFrame { public CFrame sender(ThreadProxy th); /** Find sender frame with given FP and PC */ - public default CFrame sender(ThreadProxy th, Address sp, Address fp, Address pc) { + public default CFrame sender(ThreadProxy th, Address senderSP, Address senderFP, Address senderPC) { return sender(th); } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/DwarfCFrame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/DwarfCFrame.java new file mode 100644 index 00000000000..7baa399ea75 --- /dev/null +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/DwarfCFrame.java @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2026, 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.debugger.linux; + +import sun.jvm.hotspot.debugger.Address; +import sun.jvm.hotspot.debugger.ThreadProxy; +import sun.jvm.hotspot.debugger.UnalignedAddressException; +import sun.jvm.hotspot.debugger.UnmappedAddressException; +import sun.jvm.hotspot.debugger.cdbg.CFrame; +import sun.jvm.hotspot.debugger.cdbg.ClosestSymbol; +import sun.jvm.hotspot.debugger.cdbg.basic.BasicCFrame; +import sun.jvm.hotspot.runtime.VM; + +public class DwarfCFrame extends BasicCFrame { + + private Address sp; + private Address fp; + private Address pc; + private Address cfa; + private LinuxDebugger linuxDbg; + private DwarfParser dwarf; + private boolean use1ByteBeforeToLookup; + + /** + * @return DwarfParser instance for the PC, null if native library relates to the pc not found. + * @throws DebuggerException if DWARF processing is failed. + * For example: pc is not covered in this DWARF, Common Information Entry (CIE) has + * language personality routine and/or Language Data Area (LSDA). + */ + protected static DwarfParser createDwarfParser(LinuxDebugger linuxDbg, Address pc) { + Address libptr = linuxDbg.findLibPtrByAddress(pc); + if (libptr != null) { + DwarfParser dwarf = new DwarfParser(libptr); + dwarf.processDwarf(pc); + return dwarf; + } + return null; + } + + protected DwarfCFrame(LinuxDebugger linuxDbg, Address sp, Address fp, Address cfa, Address pc, DwarfParser dwarf) { + this(linuxDbg, sp, fp, cfa, pc, dwarf, false); + } + + protected DwarfCFrame(LinuxDebugger linuxDbg, Address sp, Address fp, Address cfa, Address pc, DwarfParser dwarf, boolean use1ByteBeforeToLookup) { + super(linuxDbg.getCDebugger()); + this.sp = sp; + this.fp = fp; + this.cfa = cfa; + this.pc = pc; + this.linuxDbg = linuxDbg; + this.dwarf = dwarf; + this.use1ByteBeforeToLookup = use1ByteBeforeToLookup; + } + + public Address sp() { + return sp; + } + + public Address fp() { + return fp; + } + + public Address pc() { + return pc; + } + + public LinuxDebugger linuxDbg() { + return linuxDbg; + } + + public DwarfParser dwarf() { + return dwarf; + } + + // override base class impl to avoid ELF parsing + @Override + public ClosestSymbol closestSymbolToPC() { + Address symAddr = use1ByteBeforeToLookup ? pc.addOffsetTo(-1) : pc; + var sym = linuxDbg.lookup(linuxDbg.getAddressValue(symAddr)); + + // Returns a special symbol if the address is signal trampoline, + // otherwise returns closest symbol generated by LinuxDebugger. + return linuxDbg.isSignalTrampoline(symAddr) + ? new ClosestSymbol(sym.getName() + " ", 0) + : sym; + } + + @Override + public Address localVariableBase() { + return (dwarf != null && dwarf.isBPOffsetAvailable()) + ? cfa.addOffsetTo(dwarf.getBasePointerOffsetFromCFA()) + : fp; + } + + protected boolean isValidFrame(Address senderCFA, Address senderFP) { + // Both CFA and FP must not be null. + if (senderCFA == null && senderFP == null) { + return false; + } + + // FP must not be null if CFA is null - it happens between Java frame and Native frame. + // We cannot validate FP value because it might be used as GPR. Thus returns true + // if FP is not null. + if (senderCFA == null && senderFP != null) { + return true; + } + + // senderCFA must be greater than current CFA. + if (senderCFA != null && senderCFA.greaterThanOrEqual(cfa)) { + return true; + } + + // Otherwise, the frame is not valid. + return false; + } + + protected Address getSenderPC(Address senderPC) { + if (senderPC != null) { + return senderPC; + } + + try { + return dwarf == null + ? fp.getAddressAt(VM.getVM().getAddressSize()) // Current frame is Java + : cfa.getAddressAt(dwarf.getReturnAddressOffsetFromCFA()); // current frame is Native + } catch (UnmappedAddressException | UnalignedAddressException _) { + // Sender PC is invalid - maybe bottom of stack + return null; + } + } + + protected Address getSenderSP(Address senderSP) { + if (senderSP != null) { + return senderSP; + } else if (dwarf == null) { + // Current frame is Java - skip saved BP and RA + return fp.addOffsetTo(2 * VM.getVM().getAddressSize()); + } else { + // Current frame is Native + // CFA points SP at the call site in the previous frame. + // See 6.4 Call Frame Information in DWARF Debugging Information Format + // https://dwarfstd.org/dwarf4std.html + return cfa; + } + } + + protected Address getSenderFP(Address senderFP) { + if (senderFP != null) { + return senderFP; + } else if (dwarf == null) { // Current frame is Java + return fp.getAddressAt(0); + } else { // Current frame is Native + return dwarf.isBPOffsetAvailable() + ? cfa.getAddressAt(dwarf.getBasePointerOffsetFromCFA()) + : fp; + } + } + + @Override + public CFrame sender(ThreadProxy th) { + return sender(th, null, null, null); + } + +} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/amd64/DwarfParser.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/DwarfParser.java similarity index 95% rename from src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/amd64/DwarfParser.java rename to src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/DwarfParser.java index 53351c918d3..3e8099cf75b 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/amd64/DwarfParser.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/DwarfParser.java @@ -23,7 +23,7 @@ * */ -package sun.jvm.hotspot.debugger.linux.amd64; +package sun.jvm.hotspot.debugger.linux; import java.lang.ref.Cleaner; import sun.jvm.hotspot.debugger.Address; @@ -75,6 +75,8 @@ public class DwarfParser { public native int getCFARegister(); public native int getCFAOffset(); + public native int getOffsetFromCFA(int sareg); + public native int getRARegister(); public native int getReturnAddressOffsetFromCFA(); public native int getBasePointerOffsetFromCFA(); } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxCDebugger.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxCDebugger.java index 15f6615421c..57ba419aa9d 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxCDebugger.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxCDebugger.java @@ -91,13 +91,7 @@ class LinuxCDebugger implements CDebugger { return new LinuxPPC64CFrame(dbg, sp, pc, LinuxDebuggerLocal.getAddressSize()); } else if (cpu.equals("aarch64")) { AARCH64ThreadContext context = (AARCH64ThreadContext) thread.getContext(); - Address sp = context.getRegisterAsAddress(AARCH64ThreadContext.SP); - if (sp == null) return null; - Address fp = context.getRegisterAsAddress(AARCH64ThreadContext.FP); - if (fp == null) return null; - Address pc = context.getRegisterAsAddress(AARCH64ThreadContext.PC); - if (pc == null) return null; - return new LinuxAARCH64CFrame(dbg, sp, fp, pc); + return LinuxAARCH64CFrame.getTopFrame(dbg, context); } else if (cpu.equals("riscv64")) { RISCV64ThreadContext context = (RISCV64ThreadContext) thread.getContext(); Address sp = context.getRegisterAsAddress(RISCV64ThreadContext.SP); diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxDebugger.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxDebugger.java index a53b8a0a282..c09af9881dd 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxDebugger.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxDebugger.java @@ -33,12 +33,17 @@ import sun.jvm.hotspot.debugger.cdbg.*; by the architecture-specific subpackages. */ public interface LinuxDebugger extends JVMDebugger { - // SIGHANDLER_NAMES holds the name of signal handler. - public static final List SIGHANDLER_NAMES = List.of( + // SIGTRAMP_NAMES holds the name of signal trampoline. + public static final List SIGTRAMP_NAMES = List.of( // For AMD64 // - sysdeps/unix/sysv/linux/x86_64/libc_sigaction.c in glibc // - gdb/amd64-linux-tdep.c in GDB - "__restore_rt" + "__restore_rt", + + // For AArch64 + // - arch/arm64/kernel/vdso/vdso.lds.S in Linux kernel + "__kernel_rt_sigreturn", + "VDSO_sigtramp" ); public String addressValueToString(long address) throws DebuggerException; diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxDebuggerLocal.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxDebuggerLocal.java index 9a75511e44d..856981bb73c 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxDebuggerLocal.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxDebuggerLocal.java @@ -133,7 +133,7 @@ public class LinuxDebuggerLocal extends DebuggerBase implements LinuxDebugger { @Override public boolean isSignalTrampoline(Address pc) { var sym = lookup(getAddressValue(pc)); - return sym == null ? false : SIGHANDLER_NAMES.contains(sym.getName()); + return sym == null ? false : SIGTRAMP_NAMES.contains(sym.getName()); } // Note on Linux threads are really processes. When target process is diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/aarch64/LinuxAARCH64CFrame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/aarch64/LinuxAARCH64CFrame.java index 5f76e6308e9..c55aca2155c 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/aarch64/LinuxAARCH64CFrame.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/aarch64/LinuxAARCH64CFrame.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2015, Red Hat Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -25,73 +25,109 @@ package sun.jvm.hotspot.debugger.linux.aarch64; +import java.util.function.Function; + import sun.jvm.hotspot.debugger.*; import sun.jvm.hotspot.debugger.aarch64.*; import sun.jvm.hotspot.debugger.linux.*; import sun.jvm.hotspot.debugger.cdbg.*; -import sun.jvm.hotspot.debugger.cdbg.basic.*; import sun.jvm.hotspot.code.*; import sun.jvm.hotspot.runtime.*; import sun.jvm.hotspot.runtime.aarch64.*; -public final class LinuxAARCH64CFrame extends BasicCFrame { - public LinuxAARCH64CFrame(LinuxDebugger dbg, Address sp, Address fp, Address pc) { - super(dbg.getCDebugger()); - this.sp = sp; - this.fp = fp; - this.pc = pc; - this.dbg = dbg; +public final class LinuxAARCH64CFrame extends DwarfCFrame { + + private Address lr; + + private static LinuxAARCH64CFrame getFrameFromReg(LinuxDebugger linuxDbg, Function getreg) { + Address pc = getreg.apply(AARCH64ThreadContext.PC); + Address sp = getreg.apply(AARCH64ThreadContext.SP); + Address fp = getreg.apply(AARCH64ThreadContext.FP); + Address lr = getreg.apply(AARCH64ThreadContext.LR); + Address cfa = null; + DwarfParser dwarf = createDwarfParser(linuxDbg, pc); + + if (dwarf != null) { // Native frame + cfa = getreg.apply(dwarf.getCFARegister()) + .addOffsetTo(dwarf.getCFAOffset()); + } + + return (fp == null && cfa == null) + ? null + : new LinuxAARCH64CFrame(linuxDbg, sp, fp, cfa, pc, lr, dwarf); } - // override base class impl to avoid ELF parsing - public ClosestSymbol closestSymbolToPC() { - // try native lookup in debugger. - return dbg.lookup(dbg.getAddressValue(pc())); + public static LinuxAARCH64CFrame getTopFrame(LinuxDebugger linuxDbg, ThreadContext context) { + return getFrameFromReg(linuxDbg, context::getRegisterAsAddress); } - public Address pc() { - return pc; + private LinuxAARCH64CFrame(LinuxDebugger linuxDbg, Address sp, Address fp, Address cfa, Address pc, Address lr, DwarfParser dwarf) { + this(linuxDbg, sp, fp, cfa, pc, lr, dwarf, false); } - public Address localVariableBase() { - return fp; + private LinuxAARCH64CFrame(LinuxDebugger linuxDbg, Address sp, Address fp, Address cfa, Address pc, DwarfParser dwarf) { + this(linuxDbg, sp, fp, cfa, pc, null, dwarf, false); } - @Override - public CFrame sender(ThreadProxy thread) { - return sender(thread, null, null, null); + private LinuxAARCH64CFrame(LinuxDebugger linuxDbg, Address sp, Address fp, Address cfa, Address pc, DwarfParser dwarf, boolean use1ByteBeforeToLookup) { + this(linuxDbg, sp, fp, cfa, pc, null, dwarf, use1ByteBeforeToLookup); } - @Override - public CFrame sender(ThreadProxy thread, Address nextSP, Address nextFP, Address nextPC) { - // Check fp - // Skip if both nextFP and nextPC are given - do not need to load from fp. - if (nextFP == null && nextPC == null) { - if (fp == null) { - return null; + private LinuxAARCH64CFrame(LinuxDebugger linuxDbg, Address sp, Address fp, Address cfa, Address pc, Address lr, DwarfParser dwarf, boolean use1ByteBeforeToLookup) { + super(linuxDbg, sp, fp, cfa, pc, dwarf, use1ByteBeforeToLookup); + + if (dwarf != null) { + // Prioritize to use RA from DWARF instead of LR + var senderPCFromDwarf = getSenderPC(null); + if (senderPCFromDwarf != null) { + lr = senderPCFromDwarf; + } else if (lr != null) { + // We should set passed lr to LR of this frame, + // but throws DebuggerException if lr is not used for RA. + var raReg = dwarf.getRARegister(); + if (raReg != AARCH64ThreadContext.LR) { + throw new DebuggerException("Unexpected RA register: " + raReg); + } } + } - // Check alignment of fp - if (dbg.getAddressValue(fp) % (2 * ADDRESS_SIZE) != 0) { + this.lr = lr; + } + + private Address getSenderCFA(DwarfParser senderDwarf, Address senderSP, Address senderFP) { + if (senderDwarf == null) { // Sender frame is Java + // CFA is not available on Java frame + return null; + } + + // Sender frame is Native + int senderCFAReg = senderDwarf.getCFARegister(); + return switch(senderCFAReg){ + case AARCH64ThreadContext.FP -> senderFP.addOffsetTo(senderDwarf.getCFAOffset()); + case AARCH64ThreadContext.SP -> senderSP.addOffsetTo(senderDwarf.getCFAOffset()); + default -> throw new DebuggerException("Unsupported CFA register: " + senderCFAReg); + }; + } + + @Override + public CFrame sender(ThreadProxy thread, Address senderSP, Address senderFP, Address senderPC) { + if (linuxDbg().isSignalTrampoline(pc())) { + // SP points signal context + // https://github.com/torvalds/linux/blob/v6.17/arch/arm64/kernel/signal.c#L1357 + return getFrameFromReg(linuxDbg(), r -> LinuxAARCH64ThreadContext.getRegFromSignalTrampoline(sp(), r.intValue())); + } + + if (senderPC == null) { + // Use getSenderPC() if current frame is Java because we cannot rely on lr in this case. + senderPC = dwarf() == null ? getSenderPC(null) : lr; + if (senderPC == null) { return null; } } - if (nextFP == null) { - nextFP = fp.getAddressAt(0 * ADDRESS_SIZE); - } - if (nextFP == null) { - return null; - } + senderFP = getSenderFP(senderFP); - if (nextPC == null) { - nextPC = fp.getAddressAt(1 * ADDRESS_SIZE); - } - if (nextPC == null) { - return null; - } - - if (nextSP == null) { + if (senderSP == null) { CodeCache cc = VM.getVM().getCodeCache(); CodeBlob currentBlob = cc.findBlobUnsafe(pc()); @@ -99,29 +135,62 @@ public final class LinuxAARCH64CFrame extends BasicCFrame { if (currentBlob != null && (currentBlob.isContinuationStub() || currentBlob.isNativeMethod())) { // Use FP since it should always be valid for these cases. // TODO: These should be walked as Frames not CFrames. - nextSP = fp.addOffsetTo(2 * ADDRESS_SIZE); + senderSP = fp().addOffsetTo(2 * VM.getVM().getAddressSize()); } else { - CodeBlob codeBlob = cc.findBlobUnsafe(nextPC); + CodeBlob codeBlob = cc.findBlobUnsafe(senderPC); boolean useCodeBlob = codeBlob != null && codeBlob.getFrameSize() > 0; - nextSP = useCodeBlob ? nextFP.addOffsetTo((2 * ADDRESS_SIZE) - codeBlob.getFrameSize()) : nextFP; + senderSP = useCodeBlob ? senderFP.addOffsetTo((2 * VM.getVM().getAddressSize()) - codeBlob.getFrameSize()) : getSenderSP(null); } } - if (nextSP == null) { + if (senderSP == null) { return null; } - return new LinuxAARCH64CFrame(dbg, nextSP, nextFP, nextPC); + DwarfParser senderDwarf = null; + boolean fallback = false; + try { + senderDwarf = createDwarfParser(linuxDbg(), senderPC); + } catch (DebuggerException _) { + // Try again with PC-1 in case PC is just outside function bounds, + // due to function ending with a `call` instruction. + try { + senderDwarf = createDwarfParser(linuxDbg(), senderPC.addOffsetTo(-1)); + fallback = true; + } catch (DebuggerException _) { + if (linuxDbg().isSignalTrampoline(senderPC)) { + // We can use the caller frame if it is a signal trampoline. + // DWARF processing might fail because vdso.so .eh_frame is not required on aarch64. + return new LinuxAARCH64CFrame(linuxDbg(), senderSP, senderFP, null, senderPC, senderDwarf); + } + + // DWARF processing should succeed when the frame is native + // but it might fail if Common Information Entry (CIE) has language + // personality routine and/or Language Specific Data Area (LSDA). + return null; + } + } + + try { + Address senderCFA = getSenderCFA(senderDwarf, senderSP, senderFP); + return isValidFrame(senderCFA, senderFP) + ? new LinuxAARCH64CFrame(linuxDbg(), senderSP, senderFP, senderCFA, senderPC, senderDwarf, fallback) + : null; + } catch (DebuggerException e) { + if (linuxDbg().isSignalTrampoline(senderPC)) { + // We can use the caller frame if it is a signal trampoline. + // getSenderCFA() might fail because DwarfParser cannot find out CFA register. + return new LinuxAARCH64CFrame(linuxDbg(), senderSP, senderFP, null, senderPC, senderDwarf, fallback); + } + + // Rethrow the original exception if getSenderCFA() failed + // and the caller is not signal trampoline. + throw e; + } } @Override public Frame toFrame() { - return new AARCH64Frame(sp, fp, pc); + return new AARCH64Frame(sp(), fp(), pc()); } - // package/class internals only - private static final int ADDRESS_SIZE = 8; - private Address pc; - private Address sp; - private Address fp; - private LinuxDebugger dbg; } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/aarch64/LinuxAARCH64ThreadContext.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/aarch64/LinuxAARCH64ThreadContext.java index 77003168671..422ca001624 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/aarch64/LinuxAARCH64ThreadContext.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/aarch64/LinuxAARCH64ThreadContext.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2015, Red Hat Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -28,6 +28,7 @@ package sun.jvm.hotspot.debugger.linux.aarch64; import sun.jvm.hotspot.debugger.*; import sun.jvm.hotspot.debugger.aarch64.*; import sun.jvm.hotspot.debugger.linux.*; +import sun.jvm.hotspot.runtime.*; public class LinuxAARCH64ThreadContext extends AARCH64ThreadContext { private LinuxDebugger debugger; @@ -44,4 +45,24 @@ public class LinuxAARCH64ThreadContext extends AARCH64ThreadContext { public Address getRegisterAsAddress(int index) { return debugger.newAddress(getRegister(index)); } + + public static Address getRegFromSignalTrampoline(Address sp, int index) { + // ucontext_t locates at 2nd element of rt_sigframe. + // See definition of rt_sigframe in arch/arm/kernel/signal.h + // in Linux Kernel. + Address addrUContext = sp.addOffsetTo(128); // sizeof(siginfo_t) = 128 + Address addrUCMContext = addrUContext.addOffsetTo(176); // offsetof(ucontext_t, uc_mcontext) = 176 + + Address ptrCallerSP = addrUCMContext.addOffsetTo(256); // offsetof(uc_mcontext, sp) = 256 + Address ptrCallerPC = addrUCMContext.addOffsetTo(264); // offsetof(uc_mcontext, pc) = 264 + Address ptrCallerRegs = addrUCMContext.addOffsetTo(8); // offsetof(uc_mcontext, regs) = 8 + + return switch(index) { + case AARCH64ThreadContext.FP -> ptrCallerRegs.getAddressAt(AARCH64ThreadContext.FP * VM.getVM().getAddressSize()); + case AARCH64ThreadContext.LR -> ptrCallerRegs.getAddressAt(AARCH64ThreadContext.LR * VM.getVM().getAddressSize()); + case AARCH64ThreadContext.SP -> ptrCallerSP.getAddressAt(0); + case AARCH64ThreadContext.PC -> ptrCallerPC.getAddressAt(0); + default -> throw new IllegalArgumentException("Unsupported register index: " + index); + }; + } } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64CFrame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64CFrame.java index 4d3d9d5998d..e58e2facdd7 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64CFrame.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64CFrame.java @@ -29,181 +29,82 @@ import java.util.function.Function; import sun.jvm.hotspot.debugger.*; import sun.jvm.hotspot.debugger.amd64.*; import sun.jvm.hotspot.debugger.linux.*; -import sun.jvm.hotspot.debugger.linux.amd64.*; import sun.jvm.hotspot.debugger.cdbg.*; -import sun.jvm.hotspot.debugger.cdbg.basic.*; import sun.jvm.hotspot.runtime.*; import sun.jvm.hotspot.runtime.amd64.*; -public final class LinuxAMD64CFrame extends BasicCFrame { +public final class LinuxAMD64CFrame extends DwarfCFrame { - private static LinuxAMD64CFrame getFrameFromReg(LinuxDebugger dbg, Function getreg) { + private static LinuxAMD64CFrame getFrameFromReg(LinuxDebugger linuxDbg, Function getreg) { Address rip = getreg.apply(AMD64ThreadContext.RIP); Address rsp = getreg.apply(AMD64ThreadContext.RSP); Address rbp = getreg.apply(AMD64ThreadContext.RBP); - Address libptr = dbg.findLibPtrByAddress(rip); Address cfa = null; - DwarfParser dwarf = null; - - if (libptr != null) { // Native frame - dwarf = new DwarfParser(libptr); - try { - dwarf.processDwarf(rip); - } catch (DebuggerException e) { - // DWARF processing should succeed when the frame is native - // but it might fail if Common Information Entry (CIE) has language - // personality routine and/or Language Specific Data Area (LSDA). - return new LinuxAMD64CFrame(dbg, rsp, rbp, cfa, rip, dwarf, true); - } + DwarfParser dwarf = createDwarfParser(linuxDbg, rip); + if (dwarf != null) { // Native frame cfa = getreg.apply(dwarf.getCFARegister()) .addOffsetTo(dwarf.getCFAOffset()); } return (rbp == null && cfa == null) ? null - : new LinuxAMD64CFrame(dbg, rsp, rbp, cfa, rip, dwarf); + : new LinuxAMD64CFrame(linuxDbg, rsp, rbp, cfa, rip, dwarf); } - public static LinuxAMD64CFrame getTopFrame(LinuxDebugger dbg, ThreadContext context) { - return getFrameFromReg(dbg, context::getRegisterAsAddress); + public static LinuxAMD64CFrame getTopFrame(LinuxDebugger linuxDbg, ThreadContext context) { + return getFrameFromReg(linuxDbg, context::getRegisterAsAddress); } - private LinuxAMD64CFrame(LinuxDebugger dbg, Address rsp, Address rbp, Address cfa, Address rip, DwarfParser dwarf) { - this(dbg, rsp, rbp, cfa, rip, dwarf, false); + private LinuxAMD64CFrame(LinuxDebugger linuxDbg, Address rsp, Address rbp, Address cfa, Address rip, DwarfParser dwarf) { + this(linuxDbg, rsp, rbp, cfa, rip, dwarf, false); } - private LinuxAMD64CFrame(LinuxDebugger dbg, Address rsp, Address rbp, Address cfa, Address rip, DwarfParser dwarf, boolean use1ByteBeforeToLookup) { - super(dbg.getCDebugger()); - this.rsp = rsp; - this.rbp = rbp; - this.cfa = cfa; - this.rip = rip; - this.dbg = dbg; - this.dwarf = dwarf; - this.use1ByteBeforeToLookup = use1ByteBeforeToLookup; + private LinuxAMD64CFrame(LinuxDebugger linuxDbg, Address rsp, Address rbp, Address cfa, Address rip, DwarfParser dwarf, boolean use1ByteBeforeToLookup) { + super(linuxDbg, rsp, rbp, cfa, rip, dwarf, use1ByteBeforeToLookup); } - // override base class impl to avoid ELF parsing - public ClosestSymbol closestSymbolToPC() { - Address symAddr = use1ByteBeforeToLookup ? pc().addOffsetTo(-1) : pc(); - var sym = dbg.lookup(dbg.getAddressValue(symAddr)); - - // Returns a special symbol if the address is signal handler, - // otherwise returns closest symbol generated by LinuxDebugger. - return dbg.isSignalTrampoline(symAddr) - ? new ClosestSymbol(sym.getName() + " ", 0) - : sym; - } - - public Address pc() { - return rip; - } - - public Address localVariableBase() { - return (dwarf != null && dwarf.isBPOffsetAvailable()) - ? cfa.addOffsetTo(dwarf.getBasePointerOffsetFromCFA()) - : rbp; - } - - private Address getNextPC() { - try { - return dwarf == null - ? rbp.getAddressAt(ADDRESS_SIZE) // Java frame - : cfa.getAddressAt(dwarf.getReturnAddressOffsetFromCFA()); // Native frame - } catch (UnmappedAddressException | UnalignedAddressException e) { - return null; - } - } - - private boolean isValidFrame(Address nextCFA, Address nextRBP) { - // Both CFA and RBP must not be null. - if (nextCFA == null && nextRBP == null) { - return false; - } - - // RBP must not be null if CFA is null - it happens between Java frame and Native frame. - // We cannot validate RBP value because it might be used as GPR. Thus returns true - // if RBP is not null. - if (nextCFA == null && nextRBP != null) { - return true; - } - - // nextCFA must be greater than current CFA. - if (nextCFA != null && nextCFA.greaterThanOrEqual(cfa)) { - return true; - } - - // Otherwise, the frame is not valid. - return false; - } - - private Address getNextRSP() { - return dwarf == null ? rbp.addOffsetTo(2 * ADDRESS_SIZE) // Java frame - skip saved BP and RA - : cfa.addOffsetTo(dwarf.getReturnAddressOffsetFromCFA()) - .addOffsetTo(ADDRESS_SIZE); // Native frame - } - - private Address getNextRBP(Address senderFP) { - if (senderFP != null) { - return senderFP; - } else if (dwarf == null) { // Current frame is Java - return rbp.getAddressAt(0); - } else { // Current frame is Native - return dwarf.isBPOffsetAvailable() - ? cfa.getAddressAt(dwarf.getBasePointerOffsetFromCFA()) - : rbp; - } - } - - private Address getNextCFA(DwarfParser nextDwarf, Address senderFP, Address senderPC) { - if (nextDwarf == null) { // Next frame is Java + private Address getSenderCFA(DwarfParser senderDwarf, Address senderSP, Address senderFP) { + if (senderDwarf == null) { // Sender frame is Java // CFA is not available on Java frame return null; } - // Next frame is Native - int nextCFAReg = nextDwarf.getCFARegister(); - return switch(nextCFAReg){ - case AMD64ThreadContext.RBP -> getNextRBP(senderFP).addOffsetTo(nextDwarf.getCFAOffset()); - case AMD64ThreadContext.RSP -> getNextRSP().addOffsetTo(nextDwarf.getCFAOffset()); - default -> throw new DebuggerException("Unsupported CFA register: " + nextCFAReg); + // Sender frame is Native + int senderCFAReg = senderDwarf.getCFARegister(); + return switch(senderCFAReg){ + case AMD64ThreadContext.RBP -> senderFP.addOffsetTo(senderDwarf.getCFAOffset()); + case AMD64ThreadContext.RSP -> senderSP.addOffsetTo(senderDwarf.getCFAOffset()); + default -> throw new DebuggerException("Unsupported CFA register: " + senderCFAReg); }; } @Override - public CFrame sender(ThreadProxy th) { - return sender(th, null, null, null); - } - - @Override - public CFrame sender(ThreadProxy th, Address sp, Address fp, Address pc) { - if (dbg.isSignalTrampoline(pc())) { + public CFrame sender(ThreadProxy th, Address senderSP, Address senderFP, Address senderPC) { + if (linuxDbg().isSignalTrampoline(pc())) { // RSP points signal context // https://github.com/torvalds/linux/blob/v6.17/arch/x86/kernel/signal.c#L94 - return getFrameFromReg(dbg, r -> LinuxAMD64ThreadContext.getRegFromSignalTrampoline(this.rsp, r.intValue())); + return getFrameFromReg(linuxDbg(), r -> LinuxAMD64ThreadContext.getRegFromSignalTrampoline(sp(), r.intValue())); } - ThreadContext context = th.getContext(); - - Address nextRSP = sp != null ? sp : getNextRSP(); - if (nextRSP == null) { + senderSP = getSenderSP(senderSP); + if (senderSP == null) { return null; } - Address nextPC = pc != null ? pc : getNextPC(); - if (nextPC == null) { + senderPC = getSenderPC(senderPC); + if (senderPC == null) { return null; } - DwarfParser nextDwarf = null; + DwarfParser senderDwarf = null; boolean fallback = false; try { - nextDwarf = createDwarfParser(nextPC); + senderDwarf = createDwarfParser(linuxDbg(), senderPC); } catch (DebuggerException _) { - // Try again with RIP-1 in case RIP is just outside function bounds, + // Try again with PC-1 in case PC is just outside function bounds, // due to function ending with a `call` instruction. try { - nextDwarf = createDwarfParser(nextPC.addOffsetTo(-1)); + senderDwarf = createDwarfParser(linuxDbg(), senderPC.addOffsetTo(-1)); fallback = true; } catch (DebuggerException _) { // DWARF processing should succeed when the frame is native @@ -213,56 +114,29 @@ public final class LinuxAMD64CFrame extends BasicCFrame { } } - Address nextRBP = getNextRBP(fp); + senderFP = getSenderFP(senderFP); try { - Address nextCFA = getNextCFA(nextDwarf, fp, nextPC); - return isValidFrame(nextCFA, nextRBP) - ? new LinuxAMD64CFrame(dbg, nextRSP, nextRBP, nextCFA, nextPC, nextDwarf, fallback) + Address senderCFA = getSenderCFA(senderDwarf, senderSP, senderFP); + return isValidFrame(senderCFA, senderFP) + ? new LinuxAMD64CFrame(linuxDbg(), senderSP, senderFP, senderCFA, senderPC, senderDwarf, fallback) : null; } catch (DebuggerException e) { - if (dbg.isSignalTrampoline(nextPC)) { - // We can through the caller frame if it is signal trampoline. - // getNextCFA() might fail because DwarfParser cannot find out CFA register. - return new LinuxAMD64CFrame(dbg, nextRSP, nextRBP, null, nextPC, nextDwarf, fallback); + if (linuxDbg().isSignalTrampoline(senderPC)) { + // We can use the caller frame if it is a signal trampoline. + // getSenderCFA() might fail because DwarfParser cannot find out CFA register. + return new LinuxAMD64CFrame(linuxDbg(), senderSP, senderFP, null, senderPC, senderDwarf, fallback); } - // Rethrow the original exception if getNextCFA() failed + // Rethrow the original exception if getSenderCFA() failed // and the caller is not signal trampoline. throw e; } } - private DwarfParser createDwarfParser(Address pc) throws DebuggerException { - DwarfParser nextDwarf = null; - Address libptr = dbg.findLibPtrByAddress(pc); - if (libptr != null) { - try { - nextDwarf = new DwarfParser(libptr); - } catch (DebuggerException _) { - // Bail out to Java frame - } - } - - if (nextDwarf != null) { - nextDwarf.processDwarf(pc); - } - - return nextDwarf; - } - @Override public Frame toFrame() { - return new AMD64Frame(rsp, localVariableBase(), rip); + return new AMD64Frame(sp(), localVariableBase(), pc()); } - // package/class internals only - private static final int ADDRESS_SIZE = 8; - private Address rsp; - private Address rbp; - private Address rip; - private Address cfa; - private LinuxDebugger dbg; - private DwarfParser dwarf; - private boolean use1ByteBeforeToLookup; } diff --git a/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixedWithXComp.java b/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixedWithXComp.java index 1ebf6c21a70..a3880bc9f0e 100644 --- a/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixedWithXComp.java +++ b/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixedWithXComp.java @@ -38,7 +38,7 @@ import jdk.test.lib.process.OutputAnalyzer; * @requires vm.hasSA * @requires vm.gc != "Z" * @requires os.family == "linux" - * @requires os.arch == "amd64" + * @requires (os.arch == "amd64") | (os.arch == "aarch64") * @library /test/lib * @run driver TestJhsdbJstackMixedWithXComp */ @@ -49,7 +49,7 @@ import jdk.test.lib.process.OutputAnalyzer; * @requires vm.hasSA * @requires vm.gc != "Z" * @requires os.family == "linux" - * @requires os.arch == "amd64" + * @requires (os.arch == "amd64") | (os.arch == "aarch64") * @library /test/lib * @run driver TestJhsdbJstackMixedWithXComp -XX:+PreserveFramePointer */ @@ -60,7 +60,7 @@ import jdk.test.lib.process.OutputAnalyzer; * @requires vm.hasSA * @requires vm.gc != "Z" * @requires os.family == "linux" - * @requires os.arch == "amd64" + * @requires (os.arch == "amd64") | (os.arch == "aarch64") * @library /test/lib * @run driver TestJhsdbJstackMixedWithXComp -XX:-TieredCompilation */ From d89bd4c9806a5893937950a27c8cf3aae352dce0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eirik=20Bj=C3=B8rsn=C3=B8s?= Date: Fri, 10 Apr 2026 05:29:18 +0000 Subject: [PATCH 232/359] 8380542: ZipOutputStream.setComment and ZipEntry.setComment spec updates for rejecting unmappable characters and allowing null or empty comments Reviewed-by: alanb, lancea, jpai --- .../share/classes/java/util/zip/ZipEntry.java | 7 ++- .../java/util/zip/ZipOutputStream.java | 28 ++++++---- .../UnmappableZipFileComment.java | 56 +++++++++++++++++++ 3 files changed, 78 insertions(+), 13 deletions(-) create mode 100644 test/jdk/java/util/zip/ZipOutputStream/UnmappableZipFileComment.java diff --git a/src/java.base/share/classes/java/util/zip/ZipEntry.java b/src/java.base/share/classes/java/util/zip/ZipEntry.java index bf0bf55ff98..0206d2a5154 100644 --- a/src/java.base/share/classes/java/util/zip/ZipEntry.java +++ b/src/java.base/share/classes/java/util/zip/ZipEntry.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -651,8 +651,9 @@ public class ZipEntry implements ZipConstants, Cloneable { } /** - * Sets the optional comment string for the entry. - * @param comment the comment string + * Sets the optional comment string for the entry. If {@code comment} is an + * empty string or {@code null} then the entry will have no comment. + * @param comment the comment string, or an empty string or null for no comment * @throws IllegalArgumentException if the combined length * of the specified entry comment, the {@linkplain #getName() entry name}, * the {@linkplain #getExtra() extra field data}, and the diff --git a/src/java.base/share/classes/java/util/zip/ZipOutputStream.java b/src/java.base/share/classes/java/util/zip/ZipOutputStream.java index 4ea4a103fef..d79b0a1bd9c 100644 --- a/src/java.base/share/classes/java/util/zip/ZipOutputStream.java +++ b/src/java.base/share/classes/java/util/zip/ZipOutputStream.java @@ -43,6 +43,10 @@ import sun.nio.cs.UTF_8; *

Unless otherwise noted, passing a {@code null} argument to a constructor * or method in this class will cause a {@link NullPointerException} to be * thrown. + *

By default, the UTF-8 charset is used to encode entry names and comments. + * {@link #ZipOutputStream(OutputStream, Charset)} may be be used to specify + * an alternative charset. + * * @author David Connelly * @since 1.1 */ @@ -110,10 +114,8 @@ public class ZipOutputStream extends DeflaterOutputStream implements ZipConstant public static final int DEFLATED = ZipEntry.DEFLATED; /** - * Creates a new ZIP output stream. - * - *

The UTF-8 {@link java.nio.charset.Charset charset} is used - * to encode the entry names and comments. + * Creates a new ZIP output stream using the UTF-8 + * {@link Charset charset} to encode entry names and comments. * * @param out the actual output stream */ @@ -122,12 +124,13 @@ public class ZipOutputStream extends DeflaterOutputStream implements ZipConstant } /** - * Creates a new ZIP output stream. + * Creates a new ZIP output stream using the specified + * {@link Charset charset} to encode entry names and comments. * * @param out the actual output stream * * @param charset the {@linkplain java.nio.charset.Charset charset} - * to be used to encode the entry names and comments + * to be used to encode entry names and comments * * @since 1.7 */ @@ -140,10 +143,15 @@ public class ZipOutputStream extends DeflaterOutputStream implements ZipConstant } /** - * Sets the ZIP file comment. - * @param comment the comment string - * @throws IllegalArgumentException if the length of the specified - * ZIP file comment is greater than 0xFFFF bytes + * Sets the ZIP file comment. If {@code comment} is an empty string or + * {@code null} then the output will have no ZIP file comment. + * + * @param comment the comment string, or an empty string or null for no comment + * + * @throws IllegalArgumentException if the length of the specified ZIP file + * comment is greater than 0xFFFF bytes or if the {@code comment} + * contains characters that cannot be mapped by the {@code Charset} + * used to encode entry names and comments */ public void setComment(String comment) { byte[] bytes = null; diff --git a/test/jdk/java/util/zip/ZipOutputStream/UnmappableZipFileComment.java b/test/jdk/java/util/zip/ZipOutputStream/UnmappableZipFileComment.java new file mode 100644 index 00000000000..5879ae1497a --- /dev/null +++ b/test/jdk/java/util/zip/ZipOutputStream/UnmappableZipFileComment.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.zip.ZipOutputStream; + +import static java.io.OutputStream.nullOutputStream; +import static org.junit.jupiter.api.Assertions.assertThrows; + +/* @test + * @bug 8380542 + * @summary ZipOutputStream.setComment should throw IllegalArgumentException for unmappable characters in comment + * @run junit ${test.main.class} + */ +public class UnmappableZipFileComment { + /** + * Verify that calling ZipOutputStream.setComment with an unmappable + * comment is rejected with a IllegalArgumentException. + * + * @throws IOException if an unexpected IO error occurs + */ + @Test + void rejectUnmappableZipFileComment() throws IOException { + // Charset used when creating the ZIP file + Charset charset = StandardCharsets.US_ASCII; + // 'ø' is an unmappable character in US_ASCII + String comment = "\u00f8"; + try (var out = new ZipOutputStream(nullOutputStream(), charset)) { + assertThrows(IllegalArgumentException.class, () -> out.setComment(comment)); + } + } +} From a0af250b429736f1016bff47fc3e9e3a3cf520b4 Mon Sep 17 00:00:00 2001 From: Ivan Walulya Date: Fri, 10 Apr 2026 07:53:29 +0000 Subject: [PATCH 233/359] 8381006: G1: Wrong IHOP old gen allocation rate calculation in presence of periodic gcs Reviewed-by: tschatzl, ayang --- src/hotspot/share/gc/g1/g1Policy.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/gc/g1/g1Policy.cpp b/src/hotspot/share/gc/g1/g1Policy.cpp index 5744bbc2f03..78a533d62c0 100644 --- a/src/hotspot/share/gc/g1/g1Policy.cpp +++ b/src/hotspot/share/gc/g1/g1Policy.cpp @@ -962,12 +962,12 @@ void G1Policy::record_young_collection_end(bool concurrent_operation_is_full_mar _free_regions_at_end_of_collection = _g1h->num_free_regions(); + _old_gen_alloc_tracker.reset_after_gc(_g1h->humongous_regions_count() * G1HeapRegion::GrainBytes); // Do not update dynamic IHOP due to G1 periodic collection as it is highly likely // that in this case we are not running in a "normal" operating mode. if (_g1h->gc_cause() != GCCause::_g1_periodic_collection) { update_young_length_bounds(); - _old_gen_alloc_tracker.reset_after_gc(_g1h->humongous_regions_count() * G1HeapRegion::GrainBytes); if (update_ihop_prediction(app_time_ms / 1000.0, is_young_only_pause)) { _ihop_control->report_statistics(_g1h->gc_tracer_stw(), _g1h->non_young_occupancy_after_allocation(allocation_word_size)); } From 8357de88aa35ee998fefe321ee6dae9eb4993fa6 Mon Sep 17 00:00:00 2001 From: Alexey Ivanov Date: Fri, 10 Apr 2026 13:07:00 +0000 Subject: [PATCH 234/359] 8334868: Ensure CheckUninstallModalHook is called in WPageDialogPeer._show Ensure AwtDialog::CheckInstallModalHook and AwtDialog::ModalActivateNextWindow are always called after ::PageSetupDlg returns. Reverse the condition of the if statement and bail out if ::PageSetupDlg returns an error. Remove the doIt flag and use explicit returns: * JNI_FALSE if an error detected; * JNI_TRUE if the function reached its end without errors. Reviewed-by: dmarkov, prr --- .../native/libawt/windows/awt_PrintJob.cpp | 169 +++++++++--------- .../PrinterJob/PageDialogCancelTest.java | 9 +- .../PrinterJob/PageDialogFormatTest.java | 63 +++++++ 3 files changed, 152 insertions(+), 89 deletions(-) create mode 100644 test/jdk/java/awt/print/PrinterJob/PageDialogFormatTest.java diff --git a/src/java.desktop/windows/native/libawt/windows/awt_PrintJob.cpp b/src/java.desktop/windows/native/libawt/windows/awt_PrintJob.cpp index 8d016d8b39f..b18fa5a7e2c 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_PrintJob.cpp +++ b/src/java.desktop/windows/native/libawt/windows/awt_PrintJob.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -522,7 +522,6 @@ Java_sun_awt_windows_WPageDialogPeer__1show(JNIEnv *env, jobject peer) AwtComponent *awtParent = (parent != NULL) ? (AwtComponent *)JNI_GET_PDATA(parent) : NULL; HWND hwndOwner = awtParent ? awtParent->GetHWnd() : NULL; - jboolean doIt = JNI_FALSE; PAGESETUPDLG setup; memset(&setup, 0, sizeof(setup)); @@ -578,7 +577,7 @@ Java_sun_awt_windows_WPageDialogPeer__1show(JNIEnv *env, jobject peer) */ if ((setup.hDevMode == NULL) && (setup.hDevNames == NULL)) { CLEANUP_SHOW; - return doIt; + return JNI_FALSE; } } else { int measure = PSD_INTHOUSANDTHSOFINCHES; @@ -606,7 +605,7 @@ Java_sun_awt_windows_WPageDialogPeer__1show(JNIEnv *env, jobject peer) pageFormatToSetup(env, self, page, &setup, AwtPrintControl::getPrintDC(env, self)); if (env->ExceptionCheck()) { CLEANUP_SHOW; - return doIt; + return JNI_FALSE; } setup.lpfnPageSetupHook = reinterpret_cast(pageDlgHook); @@ -615,89 +614,91 @@ Java_sun_awt_windows_WPageDialogPeer__1show(JNIEnv *env, jobject peer) AwtDialog::CheckInstallModalHook(); BOOL ret = ::PageSetupDlg(&setup); - if (ret) { - - jobject paper = getPaper(env, page); - if (paper == NULL) { - CLEANUP_SHOW; - return doIt; - } - int units = setup.Flags & PSD_INTHOUSANDTHSOFINCHES ? - MM_HIENGLISH : - MM_HIMETRIC; - POINT paperSize; - RECT margins; - jint orientation; - - /* The printer may have been changed, and we track that change, - * but then need to get a new DC for the current printer so that - * we validate the paper size correctly - */ - if (setup.hDevNames != NULL) { - DEVNAMES* names = (DEVNAMES*)::GlobalLock(setup.hDevNames); - if (names != NULL) { - LPTSTR printer = (LPTSTR)names+names->wDeviceOffset; - SAVE_CONTROLWORD - HDC newDC = ::CreateDC(TEXT("WINSPOOL"), printer, NULL, NULL); - RESTORE_CONTROLWORD - if (newDC != NULL) { - HDC oldDC = AwtPrintControl::getPrintDC(env, self); - if (oldDC != NULL) { - ::DeleteDC(oldDC); - } - } - AwtPrintControl::setPrintDC(env, self, newDC); - } - ::GlobalUnlock(setup.hDevNames); - } - - /* Get the Windows paper and margins description. - */ - retrievePaperInfo(&setup, &paperSize, &margins, &orientation, - AwtPrintControl::getPrintDC(env, self)); - - /* Convert the Windows' paper and margins description - * and place them into a Paper instance. - */ - setPaperValues(env, paper, &paperSize, &margins, units); - if (env->ExceptionCheck()) { - CLEANUP_SHOW; - return doIt; - } - /* - * Put the updated Paper instance and the orientation into - * the PageFormat. - */ - setPaper(env, page, paper); - if (env->ExceptionCheck()) { - CLEANUP_SHOW; - return doIt; - } - setPageFormatOrientation(env, page, orientation); - if (env->ExceptionCheck()) { - CLEANUP_SHOW; - return JNI_FALSE; - } - if (setup.hDevMode != NULL) { - DEVMODE *devmode = (DEVMODE *)::GlobalLock(setup.hDevMode); - if (devmode != NULL) { - if (devmode->dmFields & DM_PAPERSIZE) { - jboolean err = setPrintPaperSize(env, self, devmode->dmPaperSize); - if (err) { - CLEANUP_SHOW; - return doIt; - } - } - } - ::GlobalUnlock(setup.hDevMode); - } - doIt = JNI_TRUE; - } AwtDialog::CheckUninstallModalHook(); - AwtDialog::ModalActivateNextWindow(NULL, target, peer); + if (!ret) { + CLEANUP_SHOW; + return JNI_FALSE; + } + + jobject paper = getPaper(env, page); + if (paper == NULL) { + CLEANUP_SHOW; + return JNI_FALSE; + } + int units = setup.Flags & PSD_INTHOUSANDTHSOFINCHES ? + MM_HIENGLISH : + MM_HIMETRIC; + POINT paperSize; + RECT margins; + jint orientation; + + /* The printer may have been changed, and we track that change, + * but then need to get a new DC for the current printer so that + * we validate the paper size correctly + */ + if (setup.hDevNames != NULL) { + DEVNAMES* names = (DEVNAMES*)::GlobalLock(setup.hDevNames); + if (names != NULL) { + LPTSTR printer = (LPTSTR)names+names->wDeviceOffset; + SAVE_CONTROLWORD + HDC newDC = ::CreateDC(TEXT("WINSPOOL"), printer, NULL, NULL); + RESTORE_CONTROLWORD + if (newDC != NULL) { + HDC oldDC = AwtPrintControl::getPrintDC(env, self); + if (oldDC != NULL) { + ::DeleteDC(oldDC); + } + } + AwtPrintControl::setPrintDC(env, self, newDC); + } + ::GlobalUnlock(setup.hDevNames); + } + + /* Get the Windows paper and margins description. + */ + retrievePaperInfo(&setup, &paperSize, &margins, &orientation, + AwtPrintControl::getPrintDC(env, self)); + + /* Convert the Windows' paper and margins description + * and place them into a Paper instance. + */ + setPaperValues(env, paper, &paperSize, &margins, units); + if (env->ExceptionCheck()) { + CLEANUP_SHOW; + return JNI_FALSE; + } + /* + * Put the updated Paper instance and the orientation into + * the PageFormat. + */ + setPaper(env, page, paper); + if (env->ExceptionCheck()) { + CLEANUP_SHOW; + return JNI_FALSE; + } + setPageFormatOrientation(env, page, orientation); + if (env->ExceptionCheck()) { + CLEANUP_SHOW; + return JNI_FALSE; + } + if (setup.hDevMode != NULL) { + DEVMODE *devmode = (DEVMODE *)::GlobalLock(setup.hDevMode); + if (devmode != NULL) { + if (devmode->dmFields & DM_PAPERSIZE) { + jboolean err = setPrintPaperSize(env, self, devmode->dmPaperSize); + if (err) { + ::GlobalUnlock(setup.hDevMode); + CLEANUP_SHOW; + return JNI_FALSE; + } + } + } + ::GlobalUnlock(setup.hDevMode); + } + HGLOBAL oldG = AwtPrintControl::getPrintHDMode(env, self); if (setup.hDevMode != oldG) { AwtPrintControl::setPrintHDMode(env, self, setup.hDevMode); @@ -710,7 +711,7 @@ Java_sun_awt_windows_WPageDialogPeer__1show(JNIEnv *env, jobject peer) CLEANUP_SHOW; - return doIt; + return JNI_TRUE; CATCH_BAD_ALLOC_RET(0); } diff --git a/test/jdk/java/awt/print/PrinterJob/PageDialogCancelTest.java b/test/jdk/java/awt/print/PrinterJob/PageDialogCancelTest.java index f9ce1b7c196..fc3d251cb6c 100644 --- a/test/jdk/java/awt/print/PrinterJob/PageDialogCancelTest.java +++ b/test/jdk/java/awt/print/PrinterJob/PageDialogCancelTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,10 +23,10 @@ /* * @test - * @bug 8334366 + * @bug 8334366 8334868 * @key headful printer - * @summary Verifies original pageobject is returned unmodified - * on cancelling pagedialog + * @summary Verifies original PageFormat object is returned unmodified + * if PrinterJob.pageDialog is cancelled * @requires (os.family == "windows") * @run main PageDialogCancelTest */ @@ -55,4 +55,3 @@ public class PageDialogCancelTest { } } } - diff --git a/test/jdk/java/awt/print/PrinterJob/PageDialogFormatTest.java b/test/jdk/java/awt/print/PrinterJob/PageDialogFormatTest.java new file mode 100644 index 00000000000..b727ba12928 --- /dev/null +++ b/test/jdk/java/awt/print/PrinterJob/PageDialogFormatTest.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8334366 8334868 + * @key headful printer + * @summary Verifies PageFormat object returned from PrinterJob.pageDialog + * changes to landscape orientation when "Landscape" is selected + * @requires (os.family == "windows") + * @run main PageDialogFormatTest + */ + +import java.awt.Robot; +import java.awt.event.KeyEvent; +import java.awt.print.PageFormat; +import java.awt.print.PrinterJob; + +public class PageDialogFormatTest { + + public static void main(String[] args) throws Exception { + PrinterJob pj = PrinterJob.getPrinterJob(); + PageFormat oldFormat = new PageFormat(); + Robot robot = new Robot(); + Thread t1 = new Thread(() -> { + robot.delay(2000); + // Select Landscape orientation + robot.keyPress(KeyEvent.VK_ALT); + robot.keyPress(KeyEvent.VK_A); + robot.keyRelease(KeyEvent.VK_A); + robot.keyRelease(KeyEvent.VK_ALT); + // Press OK + robot.keyPress(KeyEvent.VK_ENTER); + robot.keyRelease(KeyEvent.VK_ENTER); + robot.waitForIdle(); + }); + t1.start(); + PageFormat newFormat = pj.pageDialog(oldFormat); + if (newFormat.getOrientation() != PageFormat.LANDSCAPE) { + throw new RuntimeException("PageFormat didn't change to landscape"); + } + } +} From d9c5c866340b209189b1e542e9a2b1c477f30157 Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Fri, 10 Apr 2026 15:06:00 +0000 Subject: [PATCH 235/359] 8374943: TestDirectBufferStatisticsEvent failed with too few statistics events Reviewed-by: egahlin --- .../jfr/event/runtime/TestDirectBufferStatisticsEvent.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/jdk/jdk/jfr/event/runtime/TestDirectBufferStatisticsEvent.java b/test/jdk/jdk/jfr/event/runtime/TestDirectBufferStatisticsEvent.java index 581884664a5..13b5d008113 100644 --- a/test/jdk/jdk/jfr/event/runtime/TestDirectBufferStatisticsEvent.java +++ b/test/jdk/jdk/jfr/event/runtime/TestDirectBufferStatisticsEvent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ package jdk.jfr.event.runtime; import java.nio.ByteBuffer; +import java.util.ArrayList; import java.util.List; import jdk.internal.misc.VM; @@ -48,13 +49,14 @@ public class TestDirectBufferStatisticsEvent { private static final String EVENT_PATH = EventNames.DirectBufferStatistics; public static void main(String[] args) throws Throwable { + ArrayList buffers = new ArrayList<>(); try (Recording recording = new Recording()) { recording.enable(EVENT_PATH); recording.start(); int rounds = 16; int size = 1 * 1024 * 1024; // 1M for (int i = 0; i < rounds; i++) { - ByteBuffer.allocateDirect(size); + buffers.add(ByteBuffer.allocateDirect(size)); } recording.stop(); From ccbbef5561134a346adb083a863fe5149fe29b75 Mon Sep 17 00:00:00 2001 From: Dusan Balek Date: Fri, 10 Apr 2026 15:15:15 +0000 Subject: [PATCH 236/359] 8381654: Tokenizer warnings dropped when annotation processing is present Reviewed-by: jlahoda, liach --- .../com/sun/tools/javac/code/Preview.java | 15 +- .../sun/tools/javac/parser/JavaTokenizer.java | 6 +- .../sun/tools/javac/parser/JavacParser.java | 20 +- .../JavacProcessingEnvironment.java | 1 + .../com/sun/tools/javac/util/AbstractLog.java | 12 +- .../warnings/TestParserWarnings.java | 219 ++++++++++++++++++ 6 files changed, 253 insertions(+), 20 deletions(-) create mode 100644 test/langtools/tools/javac/processing/warnings/TestParserWarnings.java diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java index 1c93c37698a..7a8e6c6f4f1 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +34,7 @@ import com.sun.tools.javac.resources.CompilerProperties.LintWarnings; import com.sun.tools.javac.resources.CompilerProperties.Warnings; import com.sun.tools.javac.util.Assert; import com.sun.tools.javac.util.Context; +import com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; import com.sun.tools.javac.util.JCDiagnostic.Error; import com.sun.tools.javac.util.JCDiagnostic.LintWarning; @@ -150,24 +151,26 @@ public class Preview { /** * Report usage of a preview feature. Usages reported through this method will affect the * set of sourcefiles with dependencies on preview features. + * @param flag a flag to set on the diagnostic * @param pos the position at which the preview feature was used. * @param feature the preview feature used. */ - public void warnPreview(int pos, Feature feature) { - warnPreview(new SimpleDiagnosticPosition(pos), feature); + public void warnPreview(DiagnosticFlag flag, int pos, Feature feature) { + warnPreview(flag, new SimpleDiagnosticPosition(pos), feature); } /** * Report usage of a preview feature. Usages reported through this method will affect the * set of sourcefiles with dependencies on preview features. + * @param flag a flag to set on the diagnostic * @param pos the position at which the preview feature was used. * @param feature the preview feature used. */ - public void warnPreview(DiagnosticPosition pos, Feature feature) { + public void warnPreview(DiagnosticFlag flag, DiagnosticPosition pos, Feature feature) { Assert.check(isEnabled()); Assert.check(isPreview(feature)); markUsesPreview(pos); - log.warning(pos, + log.warning(flag, pos, feature.isPlural() ? LintWarnings.PreviewFeatureUsePlural(feature.nameFragment()) : LintWarnings.PreviewFeatureUse(feature.nameFragment())); @@ -263,7 +266,7 @@ public class Preview { log.error(pos, feature.error(source.name)); } if (isEnabled() && isPreview(feature)) { - warnPreview(pos, feature); + warnPreview(null, pos, feature); } } } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java index 55f2f76e358..d8b5b1ddd6b 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java @@ -176,7 +176,7 @@ public class JavaTokenizer extends UnicodeReader { lexError(pos, feature.error(source.name)); } else if (preview.isPreview(feature)) { //use of preview feature, warn - preview.warnPreview(pos, feature); + preview.warnPreview(DiagnosticFlag.SYNTAX, pos, feature); } } @@ -1040,10 +1040,10 @@ public class JavaTokenizer extends UnicodeReader { // Verify that the incidental indentation is consistent. Set checks = TextBlockSupport.checkWhitespace(string); if (checks.contains(TextBlockSupport.WhitespaceChecks.INCONSISTENT)) { - log.warning(pos, LintWarnings.InconsistentWhiteSpaceIndentation); + log.warning(DiagnosticFlag.SYNTAX, pos, LintWarnings.InconsistentWhiteSpaceIndentation); } if (checks.contains(TextBlockSupport.WhitespaceChecks.TRAILING)) { - log.warning(pos, LintWarnings.TrailingWhiteSpaceWillBeRemoved); + log.warning(DiagnosticFlag.SYNTAX, pos, LintWarnings.TrailingWhiteSpaceWillBeRemoved); } // Remove incidental indentation. try { diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java index df5da5cb954..b4dfb04766c 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java @@ -772,7 +772,7 @@ public class JavacParser implements Parser { } } else if (token.kind == UNDERSCORE) { if (Feature.UNDERSCORE_IDENTIFIER.allowedInSource(source)) { - log.warning(token.pos, Warnings.UnderscoreAsIdentifier); + log.warning(DiagnosticFlag.SYNTAX, token.pos, Warnings.UnderscoreAsIdentifier); } else if (asVariable) { checkSourceLevel(Feature.UNNAMED_VARIABLES); if (peekToken(LBRACKET)) { @@ -2339,7 +2339,7 @@ public class JavacParser implements Parser { if (allowYieldStatement) { return true; } else { - log.warning(pos, Warnings.InvalidYield); + log.warning(DiagnosticFlag.SYNTAX, pos, Warnings.InvalidYield); } } return false; @@ -3858,35 +3858,35 @@ public class JavacParser implements Parser { if (Feature.LOCAL_VARIABLE_TYPE_INFERENCE.allowedInSource(source)) { return Source.JDK10; } else if (shouldWarn) { - log.warning(pos, Warnings.RestrictedTypeNotAllowed(name, Source.JDK10)); + log.warning(DiagnosticFlag.SYNTAX, pos, Warnings.RestrictedTypeNotAllowed(name, Source.JDK10)); } } if (name == names.yield) { if (allowYieldStatement) { return Source.JDK14; } else if (shouldWarn) { - log.warning(pos, Warnings.RestrictedTypeNotAllowed(name, Source.JDK14)); + log.warning(DiagnosticFlag.SYNTAX, pos, Warnings.RestrictedTypeNotAllowed(name, Source.JDK14)); } } if (name == names.record) { if (allowRecords) { return Source.JDK14; } else if (shouldWarn) { - log.warning(pos, Warnings.RestrictedTypeNotAllowedPreview(name, Source.JDK14)); + log.warning(DiagnosticFlag.SYNTAX, pos, Warnings.RestrictedTypeNotAllowedPreview(name, Source.JDK14)); } } if (name == names.sealed) { if (allowSealedTypes) { return Source.JDK15; } else if (shouldWarn) { - log.warning(pos, Warnings.RestrictedTypeNotAllowedPreview(name, Source.JDK15)); + log.warning(DiagnosticFlag.SYNTAX, pos, Warnings.RestrictedTypeNotAllowedPreview(name, Source.JDK15)); } } if (name == names.permits) { if (allowSealedTypes) { return Source.JDK15; } else if (shouldWarn) { - log.warning(pos, Warnings.RestrictedTypeNotAllowedPreview(name, Source.JDK15)); + log.warning(DiagnosticFlag.SYNTAX, pos, Warnings.RestrictedTypeNotAllowedPreview(name, Source.JDK15)); } } return null; @@ -4057,7 +4057,7 @@ public class JavacParser implements Parser { if (source.compareTo(Source.JDK21) >= 0) reportSyntaxError(semiList.first().pos, Errors.ExtraneousSemicolon); else - log.warning(semiList.first().pos, Warnings.ExtraneousSemicolon); + log.warning(DiagnosticFlag.SYNTAX, semiList.first().pos, Warnings.ExtraneousSemicolon); } seenImport = true; defs.append(importDeclaration()); @@ -4074,7 +4074,7 @@ public class JavacParser implements Parser { if (source.compareTo(Source.JDK21) >= 0) reportSyntaxError(semiList.first().pos, Errors.ExtraneousSemicolon); else - log.warning(semiList.first().pos, Warnings.ExtraneousSemicolon); + log.warning(DiagnosticFlag.SYNTAX, semiList.first().pos, Warnings.ExtraneousSemicolon); } ModuleKind kind = ModuleKind.STRONG; if (token.name() == names.open) { @@ -5616,7 +5616,7 @@ public class JavacParser implements Parser { log.error(pos, feature.error(source.name)); } else if (preview.isPreview(feature)) { //use of preview feature, warn - preview.warnPreview(pos, feature); + preview.warnPreview(DiagnosticFlag.SYNTAX, pos, feature); } } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java index 809c19d5012..11fa3a5aebf 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java @@ -1204,6 +1204,7 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea //where: private final Predicate ACCEPT_NON_RECOVERABLE_LINTS = d -> !Optional.of(d) + .filter(diag -> !diag.isFlagSet(SYNTAX)) .map(JCDiagnostic::getLintCategory) .map(lc -> lc.annotationSuppression || lc == Lint.LintCategory.INCUBATING) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/AbstractLog.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/AbstractLog.java index ce3e56f2f3f..b8b2a3af254 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/AbstractLog.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/AbstractLog.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -192,6 +192,16 @@ public abstract class AbstractLog { report(diags.warning(null, source, wrap(pos), warningKey)); } + /** Report a warning, unless suppressed by the -nowarn option or the + * maximum number of warnings has been reached. + * @param flag A flag to set on the diagnostic + * @param pos The source position at which to report the warning. + * @param warningKey The key for the localized warning message. + */ + public void warning(DiagnosticFlag flag, int pos, Warning warningKey) { + report(diags.warning(flag, source, wrap(pos), warningKey)); + } + /** Provide a non-fatal notification, unless suppressed by the -nowarn option. * @param noteKey The key for the localized notification message. */ diff --git a/test/langtools/tools/javac/processing/warnings/TestParserWarnings.java b/test/langtools/tools/javac/processing/warnings/TestParserWarnings.java new file mode 100644 index 00000000000..b611e7a8655 --- /dev/null +++ b/test/langtools/tools/javac/processing/warnings/TestParserWarnings.java @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8381654 + * @summary AP interference with tokenizer warnings + * @library /tools/lib + * @modules + * jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * @build toolbox.ToolBox toolbox.JavacTask + * @run junit ${test.main.class} + */ + +import java.io.IOException; +import java.io.Writer; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import java.util.Set; + +import javax.annotation.processing.AbstractProcessor; +import javax.annotation.processing.Filer; +import javax.annotation.processing.Messager; +import javax.annotation.processing.ProcessingEnvironment; +import javax.annotation.processing.RoundEnvironment; +import javax.annotation.processing.SupportedAnnotationTypes; +import javax.lang.model.SourceVersion; +import javax.lang.model.element.TypeElement; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInfo; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import toolbox.JavacTask; +import toolbox.Task; +import toolbox.ToolBox; + +public class TestParserWarnings { + + static boolean[] apOptions() { + return new boolean[] {false, true}; + } + + final ToolBox tb = new ToolBox(); + Path base, src, classes; + + @ParameterizedTest @MethodSource("apOptions") + public void testPreviewWarning(boolean useProcessor) throws Exception { + tb.writeJavaFiles(src, """ + public record MyRec() {} + """); + + JavacTask task = new JavacTask(tb) + .options("--enable-preview", + "-source", Integer.toString(Runtime.version().feature()), + "-XDforcePreview", + "-XDrawDiagnostics") + .files(tb.findJavaFiles(src)) + .outdir(classes); + if (useProcessor) { + task.processors(new ProcessorImpl()); + } + List log = task + .run() + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + + List expected = List.of( + "- compiler.note.preview.filename: MyRec.java, DEFAULT", + "- compiler.note.preview.recompile" + ); + + tb.checkEqual(expected, log); + } + + @ParameterizedTest @MethodSource("apOptions") + public void testTextBlockWarning(boolean useProcessor) throws Exception { + tb.writeJavaFiles(src, """ + class TextBlockWhitespace { + String m() { + return ""\" + \\u0009\\u0009\\u0009\\u0009tab indentation + \\u0020\\u0020\\u0020\\u0020space indentation and trailing space\\u0020 + \\u0020\\u0020\\u0020\\u0020""\"; + } + } + """); + + JavacTask task = new JavacTask(tb) + .options("-Xlint:text-blocks", + "-XDrawDiagnostics") + .files(tb.findJavaFiles(src)) + .outdir(classes); + if (useProcessor) { + task.processors(new ProcessorImpl()); + } + List log = task + .run() + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + + List expected = List.of( + "TextBlockWhitespace.java:3:16: compiler.warn.inconsistent.white.space.indentation", + "TextBlockWhitespace.java:3:16: compiler.warn.trailing.white.space.will.be.removed", + "2 warnings" + ); + + tb.checkEqual(expected, log); + } + + @Test + public void testAPGeneratedSource() throws Exception { + tb.writeJavaFiles(src, """ + import java.lang.annotation.ElementType; + import java.lang.annotation.Target; + + @A + class Test {} + + @Target(ElementType.TYPE) + @interface A {} + """); + + List log = new JavacTask(tb) + .options("-Xlint:text-blocks", + "-XDrawDiagnostics") + .files(tb.findJavaFiles(src)) + .outdir(classes) + .processors(new ProcessorImpl()) + .run() + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + + List expected = List.of( + "Generated.java:3:16: compiler.warn.inconsistent.white.space.indentation", + "Generated.java:3:16: compiler.warn.trailing.white.space.will.be.removed", + "2 warnings" + ); + + tb.checkEqual(expected, log); + } + + @SupportedAnnotationTypes("*") + private static class ProcessorImpl extends AbstractProcessor { + private boolean done = false; + private Filer filer; + private Messager msgr; + + @Override + public void init(ProcessingEnvironment env) { + filer = env.getFiler(); + msgr = env.getMessager(); + } + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + if (!done && !annotations.isEmpty()) { + try (Writer pw = filer.createSourceFile("Generated").openWriter()) { + pw.write(""" + public class Generated { + String m() { + return ""\" + \\u0009\\u0009\\u0009\\u0009tab indentation + \\u0020\\u0020\\u0020\\u0020space indentation and trailing space\\u0020 + \\u0020\\u0020\\u0020\\u0020""\"; + } + } + """); + pw.flush(); + pw.close(); + done = true; + } catch (IOException ioe) { + msgr.printError(ioe.getMessage()); + return false; + } + return true; + } + return false; + } + + @Override + public SourceVersion getSupportedSourceVersion() { + return SourceVersion.latest(); + } + } + + @BeforeEach + public void setUp(TestInfo info) throws Exception { + base = Path.of(".").resolve(info.getTestMethod().get().getName()); + if (Files.exists(base)) { + tb.cleanDirectory(base); + } + src = base.resolve("src"); + classes = base.resolve("classes"); + Files.createDirectories(classes); + } +} From 701d0cb3a2a983ca94dedb7ca4f3554e040dec43 Mon Sep 17 00:00:00 2001 From: Andrew Haley Date: Fri, 10 Apr 2026 17:03:15 +0000 Subject: [PATCH 237/359] 8381969: os::physical_memory is still broken in 32-bit systems when running on 64-bit OSes Reviewed-by: jsikstro, stefank, aartemov --- src/hotspot/share/runtime/arguments.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index 1d79c4d0488..225e7074076 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -1515,7 +1515,7 @@ void Arguments::set_heap_size() { !FLAG_IS_DEFAULT(MinRAMPercentage) || !FLAG_IS_DEFAULT(InitialRAMPercentage); - const size_t avail_mem = os::physical_memory(); + const physical_memory_size_type avail_mem = os::physical_memory(); // If the maximum heap size has not been set with -Xmx, then set it as // fraction of the size of physical memory, respecting the maximum and From a3309eb6655ff0deb05d824ff80c4c1028683056 Mon Sep 17 00:00:00 2001 From: Vladimir Kozlov Date: Fri, 10 Apr 2026 17:11:33 +0000 Subject: [PATCH 238/359] 8381899: Assertions and crashes in aot/cds tests on Linux Alpine Reviewed-by: adinn --- src/hotspot/share/code/aotCodeCache.cpp | 26 ++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/hotspot/share/code/aotCodeCache.cpp b/src/hotspot/share/code/aotCodeCache.cpp index 6594d94fa91..79211e75db4 100644 --- a/src/hotspot/share/code/aotCodeCache.cpp +++ b/src/hotspot/share/code/aotCodeCache.cpp @@ -1093,11 +1093,13 @@ bool AOTCodeCache::store_code_blob(CodeBlob& blob, AOTCodeEntry::Kind entry_kind // now we have added all the other data we can write details of any // extra the AOT relocations - bool write_ok; + bool write_ok = true; if (AOTCodeEntry::is_multi_stub_blob(entry_kind)) { - CodeSection* cs = code_buffer->code_section(CodeBuffer::SECT_INSTS); - RelocIterator iter(cs); - write_ok = cache->write_relocations(blob, iter); + if (reloc_count > 0) { + CodeSection* cs = code_buffer->code_section(CodeBuffer::SECT_INSTS); + RelocIterator iter(cs); + write_ok = cache->write_relocations(blob, iter); + } } else { RelocIterator iter(&blob); write_ok = cache->write_relocations(blob, iter); @@ -1403,13 +1405,15 @@ void AOTCodeReader::restore(CodeBlob* code_blob) { // reinstate the AOT-load time relocs we saved from the code // buffer that generated this blob in a new code buffer and use // the latter to iterate over them - CodeBuffer code_buffer(code_blob); - relocInfo* locs = (relocInfo*)_reloc_data; - code_buffer.insts()->initialize_shared_locs(locs, _reloc_count); - code_buffer.insts()->set_locs_end(locs + _reloc_count); - CodeSection *cs = code_buffer.code_section(CodeBuffer::SECT_INSTS); - RelocIterator reloc_iter(cs); - fix_relocations(code_blob, reloc_iter); + if (_reloc_count > 0) { + CodeBuffer code_buffer(code_blob); + relocInfo* locs = (relocInfo*)_reloc_data; + code_buffer.insts()->initialize_shared_locs(locs, _reloc_count); + code_buffer.insts()->set_locs_end(locs + _reloc_count); + CodeSection *cs = code_buffer.code_section(CodeBuffer::SECT_INSTS); + RelocIterator reloc_iter(cs); + fix_relocations(code_blob, reloc_iter); + } } else { // the AOT-load time relocs will be in the blob's restored relocs RelocIterator reloc_iter(code_blob); From d3d8a0d90410f7dd0ced55fe719af04c93d46431 Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Fri, 10 Apr 2026 17:55:02 +0000 Subject: [PATCH 239/359] 8381636: Add built-in AOT support to GrowableArray Co-authored-by: Stefan Karlsson Reviewed-by: matsaave, kvn, coleenp --- src/hotspot/share/cds/aotGrowableArray.cpp | 34 --------- src/hotspot/share/cds/aotGrowableArray.hpp | 76 ------------------- .../share/cds/aotGrowableArray.inline.hpp | 37 --------- src/hotspot/share/cds/cppVtables.cpp | 6 +- src/hotspot/share/classfile/moduleEntry.cpp | 3 +- src/hotspot/share/classfile/moduleEntry.hpp | 7 +- src/hotspot/share/classfile/packageEntry.cpp | 3 +- src/hotspot/share/classfile/packageEntry.hpp | 3 +- src/hotspot/share/memory/metaspaceClosure.cpp | 4 +- src/hotspot/share/memory/metaspaceClosure.hpp | 55 +++++++++++--- src/hotspot/share/utilities/growableArray.cpp | 7 +- src/hotspot/share/utilities/growableArray.hpp | 13 ++-- .../gtest/utilities/test_metaspaceClosure.cpp | 13 ++-- 13 files changed, 72 insertions(+), 189 deletions(-) delete mode 100644 src/hotspot/share/cds/aotGrowableArray.cpp delete mode 100644 src/hotspot/share/cds/aotGrowableArray.hpp delete mode 100644 src/hotspot/share/cds/aotGrowableArray.inline.hpp diff --git a/src/hotspot/share/cds/aotGrowableArray.cpp b/src/hotspot/share/cds/aotGrowableArray.cpp deleted file mode 100644 index ec63e7aa57f..00000000000 --- a/src/hotspot/share/cds/aotGrowableArray.cpp +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please 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/aotGrowableArray.hpp" -#include "cds/aotMetaspace.hpp" -#include "memory/allocation.inline.hpp" -#include "utilities/growableArray.hpp" - -void AOTGrowableArrayHelper::deallocate(void* mem) { - if (!AOTMetaspace::in_aot_cache(mem)) { - GrowableArrayCHeapAllocator::deallocate(mem); - } -} diff --git a/src/hotspot/share/cds/aotGrowableArray.hpp b/src/hotspot/share/cds/aotGrowableArray.hpp deleted file mode 100644 index 0a0c137ed07..00000000000 --- a/src/hotspot/share/cds/aotGrowableArray.hpp +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please 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_AOT_AOTGROWABLEARRAY_HPP -#define SHARE_AOT_AOTGROWABLEARRAY_HPP - -#include -#include - -class AOTGrowableArrayHelper { -public: - static void deallocate(void* mem); -}; - -// An AOTGrowableArray provides the same functionality as a GrowableArray that -// uses the C heap allocator. In addition, AOTGrowableArray can be iterated with -// MetaspaceClosure. This type should be used for growable arrays that need to be -// stored in the AOT cache. See ModuleEntry::_reads for an example. -template -class AOTGrowableArray : public GrowableArrayWithAllocator> { - friend class VMStructs; - friend class GrowableArrayWithAllocator; - - static E* allocate(int max, MemTag mem_tag) { - return (E*)GrowableArrayCHeapAllocator::allocate(max, sizeof(E), mem_tag); - } - - E* allocate() { - return allocate(this->_capacity, mtClass); - } - - void deallocate(E* mem) { -#if INCLUDE_CDS - AOTGrowableArrayHelper::deallocate(mem); -#else - GrowableArrayCHeapAllocator::deallocate(mem); -#endif - } - -public: - AOTGrowableArray(int initial_capacity, MemTag mem_tag) : - GrowableArrayWithAllocator( - allocate(initial_capacity, mem_tag), - initial_capacity) {} - - AOTGrowableArray() : AOTGrowableArray(0, mtClassShared) {} - - // methods required by MetaspaceClosure - void metaspace_pointers_do(MetaspaceClosure* it); - int size_in_heapwords() const { return (int)heap_word_size(sizeof(*this)); } - MetaspaceClosureType type() const { return MetaspaceClosureType::GrowableArrayType; } - static bool is_read_only_by_default() { return false; } -}; - -#endif // SHARE_AOT_AOTGROWABLEARRAY_HPP diff --git a/src/hotspot/share/cds/aotGrowableArray.inline.hpp b/src/hotspot/share/cds/aotGrowableArray.inline.hpp deleted file mode 100644 index 8c6e8cb6503..00000000000 --- a/src/hotspot/share/cds/aotGrowableArray.inline.hpp +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please 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_AOTGROWABLEARRAY_INLINE_HPP -#define SHARE_CDS_AOTGROWABLEARRAY_INLINE_HPP - -#include "cds/aotGrowableArray.hpp" - -#include "memory/metaspaceClosure.hpp" - -template -void AOTGrowableArray::metaspace_pointers_do(MetaspaceClosure* it) { - it->push_c_array(AOTGrowableArray::data_addr(), AOTGrowableArray::capacity()); -} - -#endif // SHARE_CDS_AOTGROWABLEARRAY_INLINE_HPP diff --git a/src/hotspot/share/cds/cppVtables.cpp b/src/hotspot/share/cds/cppVtables.cpp index dc5a777d7b1..57da12dee48 100644 --- a/src/hotspot/share/cds/cppVtables.cpp +++ b/src/hotspot/share/cds/cppVtables.cpp @@ -22,7 +22,6 @@ * */ -#include "cds/aotGrowableArray.hpp" #include "cds/aotMetaspace.hpp" #include "cds/archiveBuilder.hpp" #include "cds/archiveUtils.hpp" @@ -41,6 +40,7 @@ #include "oops/typeArrayKlass.hpp" #include "runtime/arguments.hpp" #include "utilities/globalDefinitions.hpp" +#include "utilities/growableArray.hpp" // Objects of the Metadata types (such as Klass and ConstantPool) have C++ vtables. // (In GCC this is the field ::_vptr, i.e., first word in the object.) @@ -58,10 +58,10 @@ #ifndef PRODUCT -// AOTGrowableArray has a vtable only when in non-product builds (due to +// GrowableArray has a vtable only when in non-product builds (due to // the virtual printing functions in AnyObj). -using GrowableArray_ModuleEntry_ptr = AOTGrowableArray; +using GrowableArray_ModuleEntry_ptr = GrowableArray; #define DEBUG_CPP_VTABLE_TYPES_DO(f) \ f(GrowableArray_ModuleEntry_ptr) \ diff --git a/src/hotspot/share/classfile/moduleEntry.cpp b/src/hotspot/share/classfile/moduleEntry.cpp index b5b8aa4ef55..c7fadeaea9b 100644 --- a/src/hotspot/share/classfile/moduleEntry.cpp +++ b/src/hotspot/share/classfile/moduleEntry.cpp @@ -23,7 +23,6 @@ */ #include "cds/aotClassLocation.hpp" -#include "cds/aotGrowableArray.inline.hpp" #include "cds/archiveBuilder.hpp" #include "cds/archiveUtils.hpp" #include "cds/cdsConfig.hpp" @@ -168,7 +167,7 @@ void ModuleEntry::add_read(ModuleEntry* m) { } else { if (reads() == nullptr) { // Lazily create a module's reads list - AOTGrowableArray* new_reads = new (mtModule) AOTGrowableArray(MODULE_READS_SIZE, mtModule); + GrowableArray* new_reads = new (mtModule) GrowableArray(MODULE_READS_SIZE, mtModule); set_reads(new_reads); } diff --git a/src/hotspot/share/classfile/moduleEntry.hpp b/src/hotspot/share/classfile/moduleEntry.hpp index 1a0251a2c2a..10dec73e9fa 100644 --- a/src/hotspot/share/classfile/moduleEntry.hpp +++ b/src/hotspot/share/classfile/moduleEntry.hpp @@ -25,7 +25,6 @@ #ifndef SHARE_CLASSFILE_MODULEENTRY_HPP #define SHARE_CLASSFILE_MODULEENTRY_HPP -#include "cds/aotGrowableArray.hpp" #include "jni.h" #include "memory/metaspaceClosureType.hpp" #include "oops/oopHandle.hpp" @@ -70,7 +69,7 @@ private: // for shared classes from this module Symbol* _name; // name of this module ClassLoaderData* _loader_data; - AOTGrowableArray* _reads; // list of modules that are readable by this module + GrowableArray* _reads; // list of modules that are readable by this module Symbol* _version; // module version number Symbol* _location; // module location @@ -118,10 +117,10 @@ public: bool can_read(ModuleEntry* m) const; bool has_reads_list() const; - AOTGrowableArray* reads() const { + GrowableArray* reads() const { return _reads; } - void set_reads(AOTGrowableArray* r) { + void set_reads(GrowableArray* r) { _reads = r; } void pack_reads() { diff --git a/src/hotspot/share/classfile/packageEntry.cpp b/src/hotspot/share/classfile/packageEntry.cpp index 3e61f2e3a3e..3eb50fcb5a7 100644 --- a/src/hotspot/share/classfile/packageEntry.cpp +++ b/src/hotspot/share/classfile/packageEntry.cpp @@ -22,7 +22,6 @@ * */ -#include "cds/aotGrowableArray.inline.hpp" #include "cds/aotMetaspace.hpp" #include "cds/archiveBuilder.hpp" #include "cds/archiveUtils.hpp" @@ -83,7 +82,7 @@ void PackageEntry::add_qexport(ModuleEntry* m) { if (!has_qual_exports_list()) { // Lazily create a package's qualified exports list. // Initial size is small, do not anticipate export lists to be large. - _qualified_exports = new (mtModule) AOTGrowableArray(QUAL_EXP_SIZE, mtModule); + _qualified_exports = new (mtModule) GrowableArray(QUAL_EXP_SIZE, mtModule); } // Determine, based on this newly established export to module m, diff --git a/src/hotspot/share/classfile/packageEntry.hpp b/src/hotspot/share/classfile/packageEntry.hpp index 7b174a92287..e064e53b263 100644 --- a/src/hotspot/share/classfile/packageEntry.hpp +++ b/src/hotspot/share/classfile/packageEntry.hpp @@ -25,7 +25,6 @@ #ifndef SHARE_CLASSFILE_PACKAGEENTRY_HPP #define SHARE_CLASSFILE_PACKAGEENTRY_HPP -#include "cds/aotGrowableArray.hpp" #include "classfile/moduleEntry.hpp" #include "memory/metaspaceClosureType.hpp" #include "oops/symbol.hpp" @@ -116,7 +115,7 @@ private: bool _must_walk_exports; // Contains list of modules this package is qualifiedly exported to. Access // to this list is protected by the Module_lock. - AOTGrowableArray* _qualified_exports; + GrowableArray* _qualified_exports; JFR_ONLY(DEFINE_TRACE_ID_FIELD;) // Initial size of a package entry's list of qualified exports. diff --git a/src/hotspot/share/memory/metaspaceClosure.cpp b/src/hotspot/share/memory/metaspaceClosure.cpp index 0239eadf692..0926b55b9a3 100644 --- a/src/hotspot/share/memory/metaspaceClosure.cpp +++ b/src/hotspot/share/memory/metaspaceClosure.cpp @@ -22,11 +22,11 @@ * */ -#include "cds/aotGrowableArray.hpp" #include "classfile/packageEntry.hpp" #include "memory/metaspaceClosure.hpp" #include "oops/array.hpp" #include "oops/instanceKlass.hpp" +#include "utilities/growableArray.hpp" // Sanity checks static_assert(!HAS_METASPACE_POINTERS_DO(int)); @@ -35,8 +35,6 @@ static_assert(HAS_METASPACE_POINTERS_DO(Array)); static_assert(HAS_METASPACE_POINTERS_DO(Array)); static_assert(HAS_METASPACE_POINTERS_DO(InstanceKlass)); static_assert(HAS_METASPACE_POINTERS_DO(PackageEntry)); -static_assert(HAS_METASPACE_POINTERS_DO(AOTGrowableArray)); -static_assert(HAS_METASPACE_POINTERS_DO(AOTGrowableArray)); void MetaspaceClosure::push_impl(MetaspaceClosure::Ref* ref) { if (_enclosing_ref != nullptr) { diff --git a/src/hotspot/share/memory/metaspaceClosure.hpp b/src/hotspot/share/memory/metaspaceClosure.hpp index b6ba69d6f63..ac42dd13c6c 100644 --- a/src/hotspot/share/memory/metaspaceClosure.hpp +++ b/src/hotspot/share/memory/metaspaceClosure.hpp @@ -25,7 +25,6 @@ #ifndef SHARE_MEMORY_METASPACECLOSURE_HPP #define SHARE_MEMORY_METASPACECLOSURE_HPP -#include "cds/aotGrowableArray.hpp" #include "cppstdlib/type_traits.hpp" #include "logging/log.hpp" #include "memory/allocation.hpp" @@ -90,7 +89,9 @@ public: // int size_in_heapwords() const; // // Currently, the iterable types include all subtypes of MetsapceObj, as well - // as GrowableArray, ModuleEntry and PackageEntry. + // as GrowableArray (C-heap allocated only), ModuleEntry, and PackageEntry. + // + // (Note that GrowableArray is supported specially and does not require the above functions.) // // Calling these functions would be trivial if these were virtual functions. // However, to save space, MetaspaceObj has NO vtable. The vtable is introduced @@ -303,11 +304,38 @@ private: }; //-------------------------------- - // Support for AOTGrowableArray + // Support for GrowableArray //-------------------------------- + // GrowableArrayRef -- iterate an instance of GrowableArray. + template class GrowableArrayRef : public Ref { + GrowableArray** _mpp; + GrowableArray* dereference() const { + return *_mpp; + } + + public: + GrowableArrayRef(GrowableArray** mpp, Writability w) : Ref(w), _mpp(mpp) {} + + virtual void** mpp() const { + return (void**)_mpp; + } + + virtual void metaspace_pointers_do(MetaspaceClosure *it) const { + GrowableArray* array = dereference(); + log_trace(aot)("Iter(GrowableArray): %p [%d]", array, array->length()); + array->assert_on_C_heap(); + it->push_c_array(array->data_addr(), array->capacity()); + } + + virtual bool is_read_only_by_default() const { return false; } + virtual bool not_null() const { return dereference() != nullptr; } + virtual int size() const { return (int)heap_word_size(sizeof(*dereference())); } + virtual MetaspaceClosureType type() const { return MetaspaceClosureType::GrowableArrayType; } + }; + // Abstract base class for MSOCArrayRef, MSOPointerCArrayRef and OtherCArrayRef. - // These are used for iterating the buffer held by AOTGrowableArray. + // These are used for iterating the buffer held by GrowableArray. template class CArrayRef : public Ref { T** _mpp; int _num_elems; // Number of elements @@ -354,7 +382,7 @@ private: // MSOCArrayRef -- iterate a C array of type T, where T has metaspace_pointer_do(). // We recursively call T::metaspace_pointers_do() for each element in this array. - // This is for supporting AOTGrowableArray. + // This is for supporting GrowableArray. // // E.g., PackageEntry* _pkg_entry_pointers[2]; // a buffer that has 2 PackageEntry objects // ... @@ -377,7 +405,7 @@ private: // MSOPointerCArrayRef -- iterate a C array of type T*, where T has metaspace_pointer_do(). // We recursively call MetaspaceClosure::push() for each pointer in this array. - // This is for supporting AOTGrowableArray. + // This is for supporting GrowableArray. // // E.g., PackageEntry** _pkg_entry_pointers[2]; // a buffer that has 2 PackageEntry pointers // ... @@ -440,11 +468,11 @@ public: // Array*>* a4 = ...; it->push(&a4); => MSOPointerArrayRef // Array* a5 = ...; it->push(&a5); => MSOPointerArrayRef // - // AOTGrowableArrays have a separate "C array" buffer, so they are scanned in two steps: + // GrowableArrays have a separate "C array" buffer, so they are scanned in two steps: // - // AOTGrowableArray* ga1 = ...; it->push(&ga1); => MSORef => OtherCArrayRef - // AOTGrowableArray* ga2 = ...; it->push(&ga2); => MSORef => MSOCArrayRef - // AOTGrowableArray* ga3 = ...; it->push(&ga3); => MSORef => MSOPointerCArrayRef + // GrowableArray* ga1 = ...; it->push(&ga1); => GrowableArrayRef => OtherCArrayRef + // GrowableArray* ga2 = ...; it->push(&ga2); => GrowableArrayRef => MSOCArrayRef + // GrowableArray* ga3 = ...; it->push(&ga3); => GrowableArrayRef => MSOPointerCArrayRef // // Note that the following will fail to compile: // @@ -476,7 +504,12 @@ public: push_with_ref>(mpp, w); } - // --- The buffer of AOTGrowableArray + template + void push(GrowableArray** mpp, Writability w = _default) { + push_with_ref>(mpp, w); + } + + // --- The buffer of GrowableArray template void push_c_array(T** mpp, int num_elems, Writability w = _default) { push_impl(new OtherCArrayRef(mpp, num_elems, w)); diff --git a/src/hotspot/share/utilities/growableArray.cpp b/src/hotspot/share/utilities/growableArray.cpp index 6a1cb0b0414..9cc0813a1f6 100644 --- a/src/hotspot/share/utilities/growableArray.cpp +++ b/src/hotspot/share/utilities/growableArray.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,6 +22,7 @@ * */ +#include "cds/aotMetaspace.hpp" #include "memory/allocation.inline.hpp" #include "memory/resourceArea.hpp" #include "runtime/javaThread.hpp" @@ -56,7 +57,9 @@ void* GrowableArrayCHeapAllocator::allocate(int max, int element_size, MemTag me } void GrowableArrayCHeapAllocator::deallocate(void* elements) { - FreeHeap(elements); + if (!AOTMetaspace::in_aot_cache(elements)) { + FreeHeap(elements); + } } #ifdef ASSERT diff --git a/src/hotspot/share/utilities/growableArray.hpp b/src/hotspot/share/utilities/growableArray.hpp index e300bea6993..14b54cfc4ea 100644 --- a/src/hotspot/share/utilities/growableArray.hpp +++ b/src/hotspot/share/utilities/growableArray.hpp @@ -116,12 +116,6 @@ protected: ~GrowableArrayView() {} -protected: - // Used by AOTGrowableArray for MetaspaceClosure support. - E** data_addr() { - return &_data; - } - public: bool operator==(const GrowableArrayView& rhs) const { if (_len != rhs._len) @@ -303,6 +297,11 @@ public: } tty->print("}\n"); } + + // MetaspaceClosure support + E** data_addr() { + return &_data; + } }; template @@ -821,6 +820,8 @@ public: this->clear_and_deallocate(); } } + + void assert_on_C_heap() { assert(on_C_heap(), "must be on C heap"); } }; // Leaner GrowableArray for CHeap backed data arrays, with compile-time decided MemTag. diff --git a/test/hotspot/gtest/utilities/test_metaspaceClosure.cpp b/test/hotspot/gtest/utilities/test_metaspaceClosure.cpp index c98b38b8c3c..091767cc273 100644 --- a/test/hotspot/gtest/utilities/test_metaspaceClosure.cpp +++ b/test/hotspot/gtest/utilities/test_metaspaceClosure.cpp @@ -21,7 +21,6 @@ * questions. */ -#include "cds/aotGrowableArray.inline.hpp" #include "memory/allocation.hpp" #include "memory/metadataFactory.hpp" #include "memory/metaspaceClosure.hpp" @@ -168,9 +167,9 @@ TEST_VM(MetaspaceClosure, OtherArrayRef) { EXPECT_TRUE(closure.has_visited(array)) << "must be"; } -// iterate an AOTGrowableArray +// iterate an GrowableArray TEST_VM(MetaspaceClosure, GrowableArray_MSOPointer) { - AOTGrowableArray* array = new(mtClass) AOTGrowableArray(2, mtClass); + GrowableArray* array = new(mtClass) GrowableArray(2, mtClass); MyMetaData x; MyMetaData y; @@ -190,9 +189,9 @@ TEST_VM(MetaspaceClosure, GrowableArray_MSOPointer) { EXPECT_TRUE(closure.has_visited(&z)) << "must be"; } -// iterate an AOTGrowableArray +// iterate an GrowableArray TEST_VM(MetaspaceClosure, GrowableArray_MSO) { - AOTGrowableArray* array = new(mtClass) AOTGrowableArray(4, mtClass); + GrowableArray* array = new(mtClass) GrowableArray(4, mtClass); for (int i = 0; i < array->length(); i++) { EXPECT_TRUE(array->at(i)._a == nullptr) << "should be initialized to null"; @@ -218,9 +217,9 @@ TEST_VM(MetaspaceClosure, GrowableArray_MSO) { EXPECT_TRUE(closure.has_visited(&z)) << "must be"; } -// iterate an AOTGrowableArray +// iterate an GrowableArray TEST_VM(MetaspaceClosure, GrowableArray_jlong) { - AOTGrowableArray* array = new(mtClass) AOTGrowableArray(4, mtClass); + GrowableArray* array = new(mtClass) GrowableArray(4, mtClass); MyUniqueMetaspaceClosure closure; closure.push(&array); From f7c06959a1af73e4bb481b9c24bb252ad8ca7b4c Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Fri, 10 Apr 2026 18:01:16 +0000 Subject: [PATCH 240/359] 8381998: Move UseCompressedClassPointers to obsolete flags section Reviewed-by: stefank, phubner, dholmes --- src/hotspot/share/runtime/arguments.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index 225e7074076..2d40ee1822a 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -533,9 +533,6 @@ static SpecialFlag const special_jvm_flags[] = { { "DynamicDumpSharedSpaces", JDK_Version::jdk(18), JDK_Version::jdk(19), JDK_Version::undefined() }, { "RequireSharedSpaces", JDK_Version::jdk(18), JDK_Version::jdk(19), JDK_Version::undefined() }, { "UseSharedSpaces", JDK_Version::jdk(18), JDK_Version::jdk(19), JDK_Version::undefined() }, -#ifdef _LP64 - { "UseCompressedClassPointers", JDK_Version::jdk(25), JDK_Version::jdk(27), JDK_Version::undefined() }, -#endif { "AggressiveHeap", JDK_Version::jdk(26), JDK_Version::jdk(27), JDK_Version::jdk(28) }, // --- Deprecated alias flags (see also aliased_jvm_flags) - sorted by obsolete_in then expired_in: { "CreateMinidumpOnCrash", JDK_Version::jdk(9), JDK_Version::undefined(), JDK_Version::undefined() }, @@ -546,6 +543,9 @@ static SpecialFlag const special_jvm_flags[] = { #if defined(AARCH64) { "NearCpool", JDK_Version::undefined(), JDK_Version::jdk(25), JDK_Version::undefined() }, #endif +#ifdef _LP64 + { "UseCompressedClassPointers", JDK_Version::jdk(25), JDK_Version::jdk(27), JDK_Version::undefined() }, +#endif { "PSChunkLargeArrays", JDK_Version::jdk(26), JDK_Version::jdk(27), JDK_Version::jdk(28) }, { "ParallelRefProcEnabled", JDK_Version::jdk(26), JDK_Version::jdk(27), JDK_Version::jdk(28) }, From 2b716d7b32d745fa135f479c5a236517e87014e2 Mon Sep 17 00:00:00 2001 From: Leonid Mesnik Date: Fri, 10 Apr 2026 18:21:44 +0000 Subject: [PATCH 241/359] 8381658: Update nsk/jvmti/scenarios/sampling to better test virtual threads Reviewed-by: cjplummer, sspitsyn --- .../scenarios/allocation/AP04/ap04t001.java | 7 +- .../scenarios/allocation/AP04/ap04t002.java | 7 +- .../scenarios/allocation/AP04/ap04t003.java | 7 +- .../scenarios/bcinstr/BI04/bi04t002.java | 5 +- .../scenarios/contention/TC04/tc04t001.java | 5 +- .../jvmti/scenarios/events/EM02/em02t001.java | 7 +- .../jvmti/scenarios/events/EM02/em02t003.java | 8 +- .../EM02/em02t003/loadclass/em02t003a.java | 5 +- .../EM02/em02t005/loadclass/em02t005a.java | 5 +- .../jvmti/scenarios/events/EM02/em02t008.java | 9 +- .../jvmti/scenarios/events/EM05/em05t001.java | 5 +- .../jvmti/scenarios/events/EM05/em05t002.java | 5 +- .../jvmti/scenarios/events/EM07/em07t002.java | 10 +- .../EM07/em07t002/loadclass/em07t002a.java | 5 +- .../scenarios/hotswap/HS101/hs101t001.java | 5 +- .../scenarios/hotswap/HS101/hs101t002.java | 5 +- .../scenarios/hotswap/HS101/hs101t003.java | 5 +- .../scenarios/hotswap/HS101/hs101t004.java | 5 +- .../scenarios/hotswap/HS101/hs101t005.java | 5 +- .../scenarios/hotswap/HS101/hs101t006.java | 5 +- .../scenarios/hotswap/HS101/hs101t007.java | 5 +- .../scenarios/hotswap/HS101/hs101t008.java | 5 +- .../scenarios/hotswap/HS102/hs102t001.java | 5 +- .../scenarios/hotswap/HS102/hs102t002.java | 5 +- .../hotswap/HS103/hs103t002/MyThread.java | 6 +- .../HS103/hs103t002/newclass00/MyThread.java | 6 +- .../hotswap/HS104/hs104t002/MyThread.java | 5 +- .../HS104/hs104t002/newclass00/MyThread.java | 5 +- .../scenarios/hotswap/HS201/hs201t001.java | 7 +- .../scenarios/hotswap/HS201/hs201t002.java | 12 +- .../scenarios/hotswap/HS201/hs201t003.java | 6 +- .../hotswap/HS202/hs202t001/MyThread.java | 7 +- .../hotswap/HS202/hs202t001/hs202t001.java | 6 +- .../HS202/hs202t001/newclass00/MyThread.java | 7 +- .../hotswap/HS202/hs202t002/MyThread.java | 7 +- .../hotswap/HS202/hs202t002/hs202t002.java | 8 +- .../HS202/hs202t002/newclass00/MyThread.java | 7 +- .../hotswap/HS203/hs203t001/MyThread.java | 6 +- .../hotswap/HS203/hs203t001/hs203t001.java | 6 +- .../HS203/hs203t001/newclass00/MyThread.java | 6 +- .../hotswap/HS203/hs203t002/MyThread.java | 6 +- .../hotswap/HS203/hs203t002/hs203t002.java | 12 +- .../HS203/hs203t002/newclass00/MyThread.java | 6 +- .../hotswap/HS203/hs203t003/MyThread.java | 6 +- .../hotswap/HS203/hs203t003/hs203t003.java | 8 +- .../HS203/hs203t003/newclass00/MyThread.java | 6 +- .../hotswap/HS203/hs203t004/MyThread.java | 6 +- .../hotswap/HS203/hs203t004/hs203t004.java | 8 +- .../HS203/hs203t004/newclass00/MyThread.java | 6 +- .../hotswap/HS204/hs204t002/MyThread.java | 7 +- .../HS204/hs204t002/newclass00/MyThread.java | 7 +- .../hotswap/HS204/hs204t003/MyThread.java | 6 +- .../hotswap/HS204/hs204t003/hs204t003.java | 7 +- .../HS204/hs204t003/newclass00/MyThread.java | 7 +- .../hotswap/HS204/hs204t004/hs204t004.java | 8 +- .../scenarios/multienv/MA03/ma03t001.java | 5 +- .../scenarios/sampling/SP01/sp01t001.java | 19 +- .../sampling/SP01/sp01t001/sp01t001.cpp | 4 +- .../nsk/share/ExtraClassesBuilder.java | 4 +- test/lib/jdk/test/lib/Utils.java | 7 +- .../jdk/test/lib/thread/ThreadWrapper.java | 246 ++++++++++++++++++ 61 files changed, 489 insertions(+), 149 deletions(-) create mode 100644 test/lib/jdk/test/lib/thread/ThreadWrapper.java diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/allocation/AP04/ap04t001.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/allocation/AP04/ap04t001.java index df80009d315..1a539f4d37b 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/allocation/AP04/ap04t001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/allocation/AP04/ap04t001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ package nsk.jvmti.scenarios.allocation.AP04; import java.io.*; import java.lang.reflect.*; +import jdk.test.lib.thread.ThreadWrapper; import nsk.share.*; import nsk.share.jvmti.*; @@ -114,7 +115,7 @@ public class ap04t001 extends DebugeeClass { log.display("All objects collected"); log.display("Wait for thread to finish"); - joinThread(thread); + joinThread(thread.getThread()); log.display("CASE #" + caseName + " finished.\n"); } @@ -172,7 +173,7 @@ class ap04t001SomeReachachableObjectsIterator implements ap04t001Iterator { } /**************************************************************************/ -class ap04t001Thread extends Thread { +class ap04t001Thread extends ThreadWrapper { String name; ap04t001Iterator iterator; Wicket startLock; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/allocation/AP04/ap04t002.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/allocation/AP04/ap04t002.java index 9ecadf22f08..962474e0d01 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/allocation/AP04/ap04t002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/allocation/AP04/ap04t002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ package nsk.jvmti.scenarios.allocation.AP04; import java.io.*; import java.lang.reflect.*; +import jdk.test.lib.thread.ThreadWrapper; import nsk.share.*; import nsk.share.jvmti.*; @@ -100,7 +101,7 @@ public class ap04t002 extends DebugeeClass { modified++; log.display("Wait for completion thread to finish"); - joinThread(thread); + joinThread(thread.getThread()); log.display("Cleaning tags and references to objects..."); for (int i = 0; i < OBJ_MAX_COUNT; i++) { if (root[i] != null) { @@ -166,7 +167,7 @@ class ap04t002SomeReachachableObjectsIterator implements ap04t002Iterator { } /**************************************************************************/ -class ap04t002Thread extends Thread { +class ap04t002Thread extends ThreadWrapper { String name; ap04t002Iterator iterator; Wicket startLock; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/allocation/AP04/ap04t003.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/allocation/AP04/ap04t003.java index 15e7aa1c63a..60ca7cea837 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/allocation/AP04/ap04t003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/allocation/AP04/ap04t003.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ package nsk.jvmti.scenarios.allocation.AP04; import java.io.*; import java.lang.reflect.*; +import jdk.test.lib.thread.ThreadWrapper; import nsk.share.*; import nsk.share.jvmti.*; @@ -98,7 +99,7 @@ public class ap04t003 extends DebugeeClass { ap04t003Thread thread = startThread( threadName, iterator); log.display("Wait for thread to finish"); - joinThread(thread); + joinThread(thread.getThread()); log.display("Cleaning tags and references to objects..."); for (int i = 0; i < OBJ_MAX_COUNT; i++) { if (root[i] != null) { @@ -164,7 +165,7 @@ class ap04t003SomeReachachableObjectsIterator implements ap04t003Iterator { } /**************************************************************************/ -class ap04t003Thread extends Thread { +class ap04t003Thread extends ThreadWrapper { String name; ap04t003Iterator iterator; Wicket startLock; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/bcinstr/BI04/bi04t002.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/bcinstr/BI04/bi04t002.java index 87a0de5d31d..db5ddf45a7c 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/bcinstr/BI04/bi04t002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/bcinstr/BI04/bi04t002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,7 @@ import nsk.share.Consts; import nsk.share.jvmti.ArgumentHandler; import nsk.share.jvmti.DebugeeClass; +import jdk.test.lib.thread.ThreadWrapper; public class bi04t002 extends DebugeeClass { @@ -118,7 +119,7 @@ public class bi04t002 extends DebugeeClass { } } -class bi04t002b extends Thread { +class bi04t002b extends ThreadWrapper { Object obj = new Object(); static Object started = new Object(); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/contention/TC04/tc04t001.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/contention/TC04/tc04t001.java index 0707f38b4dd..2aa37d5d4ce 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/contention/TC04/tc04t001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/contention/TC04/tc04t001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,7 @@ import java.util.concurrent.*; import nsk.share.*; import nsk.share.jvmti.*; +import jdk.test.lib.thread.ThreadWrapper; public class tc04t001 extends DebugeeClass { @@ -92,7 +93,7 @@ public class tc04t001 extends DebugeeClass { /* =================================================================== */ -class tc04t001Thread extends Thread { +class tc04t001Thread extends ThreadWrapper { final static int INCREMENT_LIMIT = 100; final static int DELAY = 1000; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM02/em02t001.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM02/em02t001.java index 9f92bf5423e..c37f0649067 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM02/em02t001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM02/em02t001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,7 @@ import java.io.PrintStream; import nsk.share.*; import nsk.share.jvmti.*; +import jdk.test.lib.thread.ThreadWrapper; public class em02t001 extends DebugeeClass { @@ -65,7 +66,7 @@ public class em02t001 extends DebugeeClass { logger.display("Timeout = " + timeout + " msc."); for (int i = 0; i < 3; i++) { - debuggeeThread = new em02t001Thread("Debuggee Thread"); + debuggeeThread = new em02t001Thread("Debuggee Thread").getThread(); generateEvents(); @@ -113,7 +114,7 @@ public class em02t001 extends DebugeeClass { } // tested threads - class em02t001Thread extends Thread { + class em02t001Thread extends ThreadWrapper { public em02t001Thread(String name) { super(name); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM02/em02t003.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM02/em02t003.java index a23732dc554..0914b0129f2 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM02/em02t003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM02/em02t003.java @@ -33,6 +33,8 @@ import nsk.share.jvmti.*; import java.util.*; import java.math.*; +import jdk.test.lib.thread.ThreadWrapper; + public class em02t003 extends DebugeeClass { // run test from command line @@ -74,7 +76,7 @@ public class em02t003 extends DebugeeClass { } Class loadedClass; - Thread thrd; + ThreadWrapper thrd; ClassUnloader unloader = new ClassUnloader(); for (int i = 0; i < 3; i++) { @@ -90,7 +92,7 @@ public class em02t003 extends DebugeeClass { loadedClass = unloader.getLoadedClass(); try { - thrd = (Thread )loadedClass.newInstance(); + thrd = ((ThreadWrapper)loadedClass.newInstance()); } catch (Exception e) { logger.complain("Unexpected exception " + e); e.printStackTrace(); @@ -139,7 +141,7 @@ public class em02t003 extends DebugeeClass { return status; } - boolean invokeMethod(Class cls, Thread thrd, String methodName) { + boolean invokeMethod(Class cls, ThreadWrapper thrd, String methodName) { Method method; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM02/em02t003/loadclass/em02t003a.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM02/em02t003/loadclass/em02t003a.java index 32150e99ed6..8b11a8cd961 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM02/em02t003/loadclass/em02t003a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM02/em02t003/loadclass/em02t003a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,8 +22,9 @@ */ package nsk.jvmti.scenarios.events.EM02; +import jdk.test.lib.thread.ThreadWrapper; -public class em02t003a extends Thread { +public class em02t003a extends ThreadWrapper { public void run() { // invoke methods in a loop to provoke compilation diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM02/em02t005/loadclass/em02t005a.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM02/em02t005/loadclass/em02t005a.java index ee340084946..89bd00f5f83 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM02/em02t005/loadclass/em02t005a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM02/em02t005/loadclass/em02t005a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,8 +22,9 @@ */ package nsk.jvmti.scenarios.events.EM02; +import jdk.test.lib.thread.ThreadWrapper; -public class em02t005a extends Thread { +public class em02t005a extends ThreadWrapper { public void em02t005a() { } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM02/em02t008.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM02/em02t008.java index 7e30300c41b..a5a7e4298fe 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM02/em02t008.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM02/em02t008.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,7 @@ import java.io.PrintStream; import nsk.share.*; import nsk.share.jvmti.*; +import jdk.test.lib.thread.ThreadWrapper; public class em02t008 extends DebugeeClass { @@ -55,7 +56,7 @@ public class em02t008 extends DebugeeClass { int status = Consts.TEST_PASSED; long timeout = argHandler.getWaitTime() * 60000; // milliseconds - Thread thrd1, thrd2; + ThreadWrapper thrd1, thrd2; for (int i = 0; i < STEP_NUMBER; i++) { thrd1 = new em02t008a(); @@ -79,7 +80,7 @@ public class em02t008 extends DebugeeClass { return status; } - class em02t008a extends Thread{ + class em02t008a extends ThreadWrapper { em02t008a() { setName("em02t008a"); @@ -90,7 +91,7 @@ public class em02t008 extends DebugeeClass { } } - class em02t008b extends Thread{ + class em02t008b extends ThreadWrapper { em02t008b() { setName("em02t008b"); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM05/em05t001.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM05/em05t001.java index 3fa8e076729..11a7efd6bd8 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM05/em05t001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM05/em05t001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,7 @@ import java.io.PrintStream; import nsk.share.*; import nsk.share.jvmti.*; +import jdk.test.lib.thread.ThreadWrapper; public class em05t001 extends DebugeeClass { @@ -95,7 +96,7 @@ public class em05t001 extends DebugeeClass { /* =================================================================== */ // tested threads -class em05t001Thread extends Thread { +class em05t001Thread extends ThreadWrapper { public void run() { // invoke methods in a loop to provoke compilation for (int i = 0; i < 100; i++) { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM05/em05t002.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM05/em05t002.java index 011f03e8cc0..378d770dd06 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM05/em05t002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM05/em05t002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,7 @@ import java.io.PrintStream; import nsk.share.*; import nsk.share.jvmti.*; +import jdk.test.lib.thread.ThreadWrapper; public class em05t002 extends DebugeeClass { @@ -98,7 +99,7 @@ public class em05t002 extends DebugeeClass { /* =================================================================== */ // tested threads -class em05t002Thread extends Thread { +class em05t002Thread extends ThreadWrapper { public void run() { // invoke methods in a loop to provoke compilation for (int i = 0; i < 100; i++) { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM07/em07t002.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM07/em07t002.java index dcaca552073..852549276ec 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM07/em07t002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM07/em07t002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,8 @@ import java.io.File; import nsk.share.*; import nsk.share.jvmti.*; +import jdk.test.lib.thread.ThreadWrapper; + /** * Test executes the following scenario to check events COMPILED_METHOD_LOAD, * COMPILED_METHOD_UNLOAD: @@ -118,7 +120,7 @@ public class em07t002 extends DebugeeClass { String path = args[0]; Class loadedClass; - Thread thrd; + ThreadWrapper thrd; ClassUnloader unloader = new ClassUnloader(); for (int i = 0; i < attempts; i++) { logger.display("======================================"); @@ -136,7 +138,7 @@ public class em07t002 extends DebugeeClass { loadedClass = unloader.getLoadedClass(); try { - thrd = (Thread )loadedClass.newInstance(); + thrd = (ThreadWrapper)loadedClass.newInstance(); } catch (Exception e) { logger.complain("Unexpected exception " + e); e.printStackTrace(); @@ -170,7 +172,7 @@ public class em07t002 extends DebugeeClass { return status; } - boolean invokeMethod(Class cls, Thread thrd, String methodName) { + boolean invokeMethod(Class cls, ThreadWrapper thrd, String methodName) { Method method; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM07/em07t002/loadclass/em07t002a.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM07/em07t002/loadclass/em07t002a.java index 3f03fd95568..dc3abe49296 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM07/em07t002/loadclass/em07t002a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM07/em07t002/loadclass/em07t002a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,8 +22,9 @@ */ package nsk.jvmti.scenarios.events.EM07; +import jdk.test.lib.thread.ThreadWrapper; -public class em07t002a extends Thread { +public class em07t002a extends ThreadWrapper { public void run() { // invoke methods in a loop to provoke compilation diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS101/hs101t001.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS101/hs101t001.java index 21fc0a0e158..b3c1c25833c 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS101/hs101t001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS101/hs101t001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2026, Oracle and/or its affiliates. All rights reserved. * 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 nsk.jvmti.scenarios.hotswap.HS101; import java.io.PrintStream; +import jdk.test.lib.thread.ThreadWrapper; import nsk.share.*; import nsk.share.jvmti.*; @@ -115,7 +116,7 @@ public class hs101t001 extends DebugeeClass { /* =================================================================== */ -class hs101t001Thread extends Thread { +class hs101t001Thread extends ThreadWrapper { public Wicket startingBarrier = new Wicket(); private volatile boolean flag = true; public int i; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS101/hs101t002.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS101/hs101t002.java index 368ed04a01e..e654dde6db0 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS101/hs101t002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS101/hs101t002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2026, Oracle and/or its affiliates. All rights reserved. * 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 nsk.jvmti.scenarios.hotswap.HS101; import java.io.PrintStream; +import jdk.test.lib.thread.ThreadWrapper; import nsk.share.*; import nsk.share.jvmti.*; @@ -115,7 +116,7 @@ public class hs101t002 extends DebugeeClass { /* =================================================================== */ -class hs101t002Thread extends Thread { +class hs101t002Thread extends ThreadWrapper { public Wicket startingBarrier = new Wicket(); private volatile boolean flag = true; public int i; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS101/hs101t003.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS101/hs101t003.java index 2d554fd73ec..f08d07f2c17 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS101/hs101t003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS101/hs101t003.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2026, Oracle and/or its affiliates. All rights reserved. * 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 nsk.jvmti.scenarios.hotswap.HS101; import java.io.PrintStream; +import jdk.test.lib.thread.ThreadWrapper; import nsk.share.*; import nsk.share.jvmti.*; @@ -115,7 +116,7 @@ public class hs101t003 extends DebugeeClass { /* =================================================================== */ -class hs101t003Thread extends Thread { +class hs101t003Thread extends ThreadWrapper { public Wicket startingBarrier = new Wicket(); private volatile boolean flag = true; public int i; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS101/hs101t004.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS101/hs101t004.java index f43609ab042..121cb4a0aac 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS101/hs101t004.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS101/hs101t004.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2026, Oracle and/or its affiliates. All rights reserved. * 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 nsk.jvmti.scenarios.hotswap.HS101; import java.io.PrintStream; +import jdk.test.lib.thread.ThreadWrapper; import nsk.share.*; import nsk.share.jvmti.*; @@ -98,7 +99,7 @@ public class hs101t004 extends DebugeeClass { /* =================================================================== */ -class hs101t004Thread extends Thread { +class hs101t004Thread extends ThreadWrapper { public Wicket startingBarrier = new Wicket(); private volatile boolean flag = true; public int i; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS101/hs101t005.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS101/hs101t005.java index afee53a2331..31bba4a409a 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS101/hs101t005.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS101/hs101t005.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2026, Oracle and/or its affiliates. All rights reserved. * 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 nsk.jvmti.scenarios.hotswap.HS101; import java.io.PrintStream; +import jdk.test.lib.thread.ThreadWrapper; import nsk.share.*; import nsk.share.jvmti.*; @@ -98,7 +99,7 @@ public class hs101t005 extends DebugeeClass { /* =================================================================== */ -class hs101t005Thread extends Thread { +class hs101t005Thread extends ThreadWrapper { public Wicket startingBarrier = new Wicket(); private volatile boolean flag = true; public int i; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS101/hs101t006.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS101/hs101t006.java index 98568577032..a27521dcbd9 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS101/hs101t006.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS101/hs101t006.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2026, Oracle and/or its affiliates. All rights reserved. * 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 nsk.jvmti.scenarios.hotswap.HS101; import java.io.PrintStream; +import jdk.test.lib.thread.ThreadWrapper; import nsk.share.*; import nsk.share.jvmti.*; @@ -98,7 +99,7 @@ public class hs101t006 extends DebugeeClass { /* =================================================================== */ -class hs101t006Thread extends Thread { +class hs101t006Thread extends ThreadWrapper { public Wicket startingBarrier = new Wicket(); private volatile boolean flag = true; public int i; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS101/hs101t007.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS101/hs101t007.java index f19805e9d1a..270fd7751a4 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS101/hs101t007.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS101/hs101t007.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2026, Oracle and/or its affiliates. All rights reserved. * 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 nsk.jvmti.scenarios.hotswap.HS101; import java.io.PrintStream; +import jdk.test.lib.thread.ThreadWrapper; import nsk.share.*; import nsk.share.jvmti.*; @@ -95,7 +96,7 @@ public class hs101t007 extends DebugeeClass { /* =================================================================== */ -class hs101t007Thread extends Thread { +class hs101t007Thread extends ThreadWrapper { public Wicket startingBarrier = new Wicket(); private volatile boolean flag = true; public int i; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS101/hs101t008.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS101/hs101t008.java index b421cf3c185..9fca9678d0a 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS101/hs101t008.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS101/hs101t008.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2026, Oracle and/or its affiliates. All rights reserved. * 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 nsk.jvmti.scenarios.hotswap.HS101; import java.io.PrintStream; +import jdk.test.lib.thread.ThreadWrapper; import nsk.share.*; import nsk.share.jvmti.*; @@ -95,7 +96,7 @@ public class hs101t008 extends DebugeeClass { /* =================================================================== */ -class hs101t008Thread extends Thread { +class hs101t008Thread extends ThreadWrapper { public Wicket startingBarrier = new Wicket(); private volatile boolean flag = true; public int i; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS102/hs102t001.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS102/hs102t001.java index 29d7aca6935..09ba44a5c32 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS102/hs102t001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS102/hs102t001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2026, Oracle and/or its affiliates. All rights reserved. * 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 nsk.jvmti.scenarios.hotswap.HS102; import java.io.PrintStream; +import jdk.test.lib.thread.ThreadWrapper; import nsk.share.*; import nsk.share.jvmti.*; @@ -150,7 +151,7 @@ public class hs102t001 extends DebugeeClass { /* =================================================================== */ -class hs102t001Thread extends Thread { +class hs102t001Thread extends ThreadWrapper { public Wicket startingBarrier = new Wicket(); private volatile boolean flag = true; public int i; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS102/hs102t002.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS102/hs102t002.java index a34f3f6c109..c38fb07fb69 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS102/hs102t002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS102/hs102t002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2026, Oracle and/or its affiliates. All rights reserved. * 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 nsk.jvmti.scenarios.hotswap.HS102; import java.io.PrintStream; +import jdk.test.lib.thread.ThreadWrapper; import nsk.share.*; import nsk.share.jvmti.*; @@ -150,7 +151,7 @@ public class hs102t002 extends DebugeeClass { /* =================================================================== */ -class hs102t002Thread extends Thread { +class hs102t002Thread extends ThreadWrapper { public Wicket startingBarrier = new Wicket(); private volatile boolean flag = true; public int i; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS103/hs103t002/MyThread.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS103/hs103t002/MyThread.java index 9f7d6e2f5c8..09fef278ca5 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS103/hs103t002/MyThread.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS103/hs103t002/MyThread.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,9 +22,11 @@ */ package nsk.jvmti.scenarios.hotswap.HS103.hs103t002; +import jdk.test.lib.thread.ThreadWrapper; + import java.util.concurrent.atomic.AtomicInteger; -public class MyThread extends Thread { +public class MyThread extends ThreadWrapper { public static AtomicInteger ai = new AtomicInteger(0); public static final int size = 10; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS103/hs103t002/newclass00/MyThread.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS103/hs103t002/newclass00/MyThread.java index 404ab78ff55..5874a1e11fc 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS103/hs103t002/newclass00/MyThread.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS103/hs103t002/newclass00/MyThread.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,9 +22,11 @@ */ package nsk.jvmti.scenarios.hotswap.HS103.hs103t002; +import jdk.test.lib.thread.ThreadWrapper; + import java.util.concurrent.atomic.AtomicInteger; -public class MyThread extends Thread { +public class MyThread extends ThreadWrapper { public static AtomicInteger ai = new AtomicInteger(0); public static final int size = 10; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS104/hs104t002/MyThread.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS104/hs104t002/MyThread.java index 771dfeeb054..2c5dfcf070c 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS104/hs104t002/MyThread.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS104/hs104t002/MyThread.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,9 +22,10 @@ */ package nsk.jvmti.scenarios.hotswap.HS104.hs104t002; +import jdk.test.lib.thread.ThreadWrapper; import nsk.share.Wicket; -public class MyThread extends Thread { +public class MyThread extends ThreadWrapper { int threadState; private Wicket wicket; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS104/hs104t002/newclass00/MyThread.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS104/hs104t002/newclass00/MyThread.java index 6ebbc04b5c1..409a3f6ffcc 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS104/hs104t002/newclass00/MyThread.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS104/hs104t002/newclass00/MyThread.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,9 +22,10 @@ */ package nsk.jvmti.scenarios.hotswap.HS104.hs104t002; +import jdk.test.lib.thread.ThreadWrapper; import nsk.share.Wicket; -public class MyThread extends Thread { +public class MyThread extends ThreadWrapper { int threadState; private Wicket wicket; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS201/hs201t001.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS201/hs201t001.java index 2f6e2b15db7..2cb0f1bc683 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS201/hs201t001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS201/hs201t001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,7 @@ import java.io.PrintStream; import nsk.share.*; import nsk.share.jvmti.*; +import jdk.test.lib.thread.ThreadWrapper; public class hs201t001 extends DebugeeClass { @@ -74,7 +75,7 @@ public class hs201t001 extends DebugeeClass { timeout = argHandler.getWaitTime() * 60 * 1000; // milliseconds log.display(">>> starting tested thread"); - Thread thread = new hs201t001Thread(); + Thread thread = new hs201t001Thread().getThread(); // testing sync status = checkStatus(status); @@ -130,7 +131,7 @@ public class hs201t001 extends DebugeeClass { return status; } -class hs201t001Thread extends Thread { +class hs201t001Thread extends ThreadWrapper { hs201t001Thread() { setName("hs201t001Thread"); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS201/hs201t002.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS201/hs201t002.java index c76a9b005d1..69d243d49b1 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS201/hs201t002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS201/hs201t002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,7 @@ import java.util.concurrent.CountDownLatch; import nsk.share.*; import nsk.share.jvmti.*; +import jdk.test.lib.thread.ThreadWrapper; public class hs201t002 extends DebugeeClass { @@ -74,7 +75,8 @@ public class hs201t002 extends DebugeeClass { timeout = argHandler.getWaitTime() * 60 * 1000; // milliseconds log.display(">>> starting tested thread"); - hs201t002Thread thread = new hs201t002Thread(); + hs201t002Thread wrappedThread = new hs201t002Thread(); + Thread thread = wrappedThread.getThread(); // testing sync status = checkStatus(status); @@ -84,12 +86,12 @@ public class hs201t002 extends DebugeeClass { // setThread(thread) enables JVMTI events, and that can only be done on a live thread, // so wait until the thread has started. try { - thread.ready.await(); + wrappedThread.ready.await(); } catch (InterruptedException e) { } setThread(thread); - thread.go.countDown(); + wrappedThread.go.countDown(); while (currentStep != 4) { try { @@ -148,7 +150,7 @@ public class hs201t002 extends DebugeeClass { return status; } -class hs201t002Thread extends Thread { +class hs201t002Thread extends ThreadWrapper { CountDownLatch ready = new CountDownLatch(1); CountDownLatch go = new CountDownLatch(1); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS201/hs201t003.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS201/hs201t003.java index f33afd148e8..fc0680f88eb 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS201/hs201t003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS201/hs201t003.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,8 @@ package nsk.jvmti.scenarios.hotswap.HS201; import java.io.*; import java.util.*; + +import jdk.test.lib.thread.ThreadWrapper; import nsk.share.*; import nsk.share.jvmti.*; @@ -187,7 +189,7 @@ public class hs201t003 extends DebugeeClass { /** * Class executing a class to be redefined. */ - class RedefClassWrapper extends Thread { + class RedefClassWrapper extends ThreadWrapper { boolean stopMe = false; RedefClassWrapper() { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS202/hs202t001/MyThread.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS202/hs202t001/MyThread.java index ecb702f1873..b94ed1f8faa 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS202/hs202t001/MyThread.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS202/hs202t001/MyThread.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * 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,10 @@ * questions. */ package nsk.jvmti.scenarios.hotswap.HS202.hs202t001; -public class MyThread extends Thread { + +import jdk.test.lib.thread.ThreadWrapper; + +public class MyThread extends ThreadWrapper { MyObject myObject; public MyThread(MyObject obj) { this.myObject = obj; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS202/hs202t001/hs202t001.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS202/hs202t001/hs202t001.java index c386a88dc12..788d4114498 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS202/hs202t001/hs202t001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS202/hs202t001/hs202t001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * 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,8 +80,8 @@ public class hs202t001 extends RedefineAgent { add(myObject, 1); } myObject.stop(true); - if( popThreadFrame(mt)) {; - resumeThread(mt); + if( popThreadFrame(mt.getThread())) {; + resumeThread(mt.getThread()); } // Popoing will not be possible on .. mt.join(); state = myObject.getAge(); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS202/hs202t001/newclass00/MyThread.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS202/hs202t001/newclass00/MyThread.java index 9fbccbbcfab..7fc9dcf161a 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS202/hs202t001/newclass00/MyThread.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS202/hs202t001/newclass00/MyThread.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * 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,10 @@ * questions. */ package nsk.jvmti.scenarios.hotswap.HS202.hs202t001; -public class MyThread extends Thread { + +import jdk.test.lib.thread.ThreadWrapper; + +public class MyThread extends ThreadWrapper { MyObject myObject; public MyThread(MyObject obj) { this.myObject = obj; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS202/hs202t002/MyThread.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS202/hs202t002/MyThread.java index 45ec4af6249..c5e8fd6eb46 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS202/hs202t002/MyThread.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS202/hs202t002/MyThread.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * 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,10 @@ * questions. */ package nsk.jvmti.scenarios.hotswap.HS202.hs202t002; -public class MyThread extends Thread { + +import jdk.test.lib.thread.ThreadWrapper; + +public class MyThread extends ThreadWrapper { private int val = 100; public void run() { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS202/hs202t002/hs202t002.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS202/hs202t002/hs202t002.java index e78702cc587..dd295195543 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS202/hs202t002/hs202t002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS202/hs202t002/hs202t002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * 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,15 +70,15 @@ public class hs202t002 extends RedefineAgent { try { mt.start(); - while (!isThreadSuspended(mt)) { + while (!isThreadSuspended(mt.getThread())) { Thread.yield(); } - if (!popThreadFrame(mt)) { + if (!popThreadFrame(mt.getThread())) { throw new RuntimeException("error in popframe operation!"); } - if (!resumeThread(mt)) { + if (!resumeThread(mt.getThread())) { throw new RuntimeException("error in resuming thread!"); } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS202/hs202t002/newclass00/MyThread.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS202/hs202t002/newclass00/MyThread.java index 32a7a085a13..1af54872316 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS202/hs202t002/newclass00/MyThread.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS202/hs202t002/newclass00/MyThread.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * 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,10 @@ * questions. */ package nsk.jvmti.scenarios.hotswap.HS202.hs202t002; -public class MyThread extends Thread { + +import jdk.test.lib.thread.ThreadWrapper; + +public class MyThread extends ThreadWrapper { private int val = 100; public void run() { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS203/hs203t001/MyThread.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS203/hs203t001/MyThread.java index c5646af4024..109ea8ec918 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS203/hs203t001/MyThread.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS203/hs203t001/MyThread.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,8 +21,10 @@ * questions. */ package nsk.jvmti.scenarios.hotswap.HS203.hs203t001; +import jdk.test.lib.thread.ThreadWrapper; + import java.util.concurrent.atomic.AtomicBoolean; -public class MyThread extends Thread { +public class MyThread extends ThreadWrapper { public static AtomicBoolean resume = new AtomicBoolean(false); public int threadState=100; public MyThread() { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS203/hs203t001/hs203t001.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS203/hs203t001/hs203t001.java index abbe8221444..e42bede4e01 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS203/hs203t001/hs203t001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS203/hs203t001/hs203t001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -76,8 +76,8 @@ public class hs203t001 extends RedefineAgent { mt.start(); while(!MyThread.resume.get()); Thread.sleep(10000); - popThreadFrame(mt); - resumeThread(mt); + popThreadFrame(mt.getThread()); + resumeThread(mt.getThread()); mt.join(); log.println(" ..."+mt.threadState); } catch(Exception ie) { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS203/hs203t001/newclass00/MyThread.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS203/hs203t001/newclass00/MyThread.java index 4ddbfc43c79..c5792c9789d 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS203/hs203t001/newclass00/MyThread.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS203/hs203t001/newclass00/MyThread.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,8 +21,10 @@ * questions. */ package nsk.jvmti.scenarios.hotswap.HS203.hs203t001; +import jdk.test.lib.thread.ThreadWrapper; + import java.util.concurrent.atomic.AtomicBoolean; -public class MyThread extends Thread { +public class MyThread extends ThreadWrapper { public static AtomicBoolean resume = new AtomicBoolean(false); public int threadState=10; public MyThread() { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS203/hs203t002/MyThread.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS203/hs203t002/MyThread.java index 94eee8ebe07..787da2529d6 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS203/hs203t002/MyThread.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS203/hs203t002/MyThread.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,8 +21,10 @@ * questions. */ package nsk.jvmti.scenarios.hotswap.HS203.hs203t002; +import jdk.test.lib.thread.ThreadWrapper; + import java.util.concurrent.atomic.AtomicBoolean; -public class MyThread extends Thread { +public class MyThread extends ThreadWrapper { public static AtomicBoolean resume = new AtomicBoolean(false); public static AtomicBoolean resume2 = new AtomicBoolean(false); public int threadState=100; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS203/hs203t002/hs203t002.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS203/hs203t002/hs203t002.java index d9dd4a88c80..f62bd49f674 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS203/hs203t002/hs203t002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS203/hs203t002/hs203t002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * 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,14 +77,14 @@ public class hs203t002 extends RedefineAgent { while(!MyThread.resume.get()); MyThread.resume.set(false); Thread.sleep(10000); - popThreadFrame(mt); - resumeThread(mt); + popThreadFrame(mt.getThread()); + resumeThread(mt.getThread()); while(!MyThread.resume2.get()); Thread.sleep(10000); - suspendThread(mt); + suspendThread(mt.getThread()); //mt.suspend(); - popThreadFrame(mt); - resumeThread(mt); + popThreadFrame(mt.getThread()); + resumeThread(mt.getThread()); MyThread.resume.set(true); mt.join(); log.println(" ..."+mt.threadState); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS203/hs203t002/newclass00/MyThread.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS203/hs203t002/newclass00/MyThread.java index cce4bd7326e..185bb0bd5e1 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS203/hs203t002/newclass00/MyThread.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS203/hs203t002/newclass00/MyThread.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,8 +21,10 @@ * questions. */ package nsk.jvmti.scenarios.hotswap.HS203.hs203t002; +import jdk.test.lib.thread.ThreadWrapper; + import java.util.concurrent.atomic.AtomicBoolean; -public class MyThread extends Thread { +public class MyThread extends ThreadWrapper { public static AtomicBoolean resume = new AtomicBoolean(false); public static AtomicBoolean resume2 = new AtomicBoolean(false); public int threadState=100; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS203/hs203t003/MyThread.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS203/hs203t003/MyThread.java index dd07c191f38..7942e765299 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS203/hs203t003/MyThread.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS203/hs203t003/MyThread.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,9 +22,11 @@ */ package nsk.jvmti.scenarios.hotswap.HS203.hs203t003; +import jdk.test.lib.thread.ThreadWrapper; + import java.util.concurrent.atomic.AtomicBoolean; -public class MyThread extends Thread { +public class MyThread extends ThreadWrapper { public static AtomicBoolean resume = new AtomicBoolean(false); public int threadState=0; // field watch is added on. diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS203/hs203t003/hs203t003.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS203/hs203t003/hs203t003.java index 348dc8b5ee4..6c4a018e0b7 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS203/hs203t003/hs203t003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS203/hs203t003/hs203t003.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ public class hs203t003 extends RedefineAgent { Thread.sleep(100); } // Wait for the thread to be suspended. - while (!isSuspended(mt)) { + while (!isSuspended(mt.getThread())) { if (!agentStatus()) { System.out.println("Failed to suspend thread"); return passed; @@ -101,12 +101,12 @@ public class hs203t003 extends RedefineAgent { Thread.sleep(100); } // Pop the frame. - if (!popThreadFrame(mt)) { + if (!popThreadFrame(mt.getThread())) { System.out.println("Failed to pop a frame = " + mt.threadState); } // Resume the thread. - if(!resumeThread(mt)) { + if(!resumeThread(mt.getThread())) { System.out.println("Failed to resume the thread = " + mt.threadState); } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS203/hs203t003/newclass00/MyThread.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS203/hs203t003/newclass00/MyThread.java index e60b3da5c4b..105f90e360c 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS203/hs203t003/newclass00/MyThread.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS203/hs203t003/newclass00/MyThread.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,8 +22,10 @@ */ package nsk.jvmti.scenarios.hotswap.HS203.hs203t003; +import jdk.test.lib.thread.ThreadWrapper; + import java.util.concurrent.atomic.AtomicBoolean; -public class MyThread extends Thread { +public class MyThread extends ThreadWrapper { public static AtomicBoolean resume = new AtomicBoolean(false); public int threadState=100; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS203/hs203t004/MyThread.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS203/hs203t004/MyThread.java index 8cf6750917a..84eea67fe4a 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS203/hs203t004/MyThread.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS203/hs203t004/MyThread.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * 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,9 @@ */ package nsk.jvmti.scenarios.hotswap.HS203.hs203t004; -public class MyThread extends Thread { +import jdk.test.lib.thread.ThreadWrapper; + +public class MyThread extends ThreadWrapper { public static volatile boolean stop = true; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS203/hs203t004/hs203t004.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS203/hs203t004/hs203t004.java index f9f1aa8a270..c8b1f09bf1e 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS203/hs203t004/hs203t004.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS203/hs203t004/hs203t004.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -82,11 +82,11 @@ public class hs203t004 extends RedefineAgent { Thread.yield(); } - suspendThread(myThread); + suspendThread(myThread.getThread()); - popThreadFrame(myThread); + popThreadFrame(myThread.getThread()); - resumeThread(myThread); + resumeThread(myThread.getThread()); MyThread.stop = false; myThread.join(); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS203/hs203t004/newclass00/MyThread.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS203/hs203t004/newclass00/MyThread.java index 7276b8cc5fd..f63dcc4577e 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS203/hs203t004/newclass00/MyThread.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS203/hs203t004/newclass00/MyThread.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * 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,9 @@ package nsk.jvmti.scenarios.hotswap.HS203.hs203t004; -public class MyThread extends Thread { +import jdk.test.lib.thread.ThreadWrapper; + +public class MyThread extends ThreadWrapper { public static volatile boolean stop = true; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS204/hs204t002/MyThread.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS204/hs204t002/MyThread.java index c502e124814..5a220345c2d 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS204/hs204t002/MyThread.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS204/hs204t002/MyThread.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * 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,10 @@ * questions. */ package nsk.jvmti.scenarios.hotswap.HS204.hs204t002; -public class MyThread extends Thread{ + +import jdk.test.lib.thread.ThreadWrapper; + +public class MyThread extends ThreadWrapper { public static int value=100; static { System.out.println(" ... Break Point here.."); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS204/hs204t002/newclass00/MyThread.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS204/hs204t002/newclass00/MyThread.java index 0556e5dd45e..2fb796f1f56 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS204/hs204t002/newclass00/MyThread.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS204/hs204t002/newclass00/MyThread.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * 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,10 @@ * questions. */ package nsk.jvmti.scenarios.hotswap.HS204.hs204t002; -public class MyThread extends Thread{ + +import jdk.test.lib.thread.ThreadWrapper; + +public class MyThread extends ThreadWrapper { public static int value=200; static { System.out.println(" ... Break Point here.."); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS204/hs204t003/MyThread.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS204/hs204t003/MyThread.java index 7e9ba68c85d..51f8af20995 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS204/hs204t003/MyThread.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS204/hs204t003/MyThread.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * 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,9 @@ */ package nsk.jvmti.scenarios.hotswap.HS204.hs204t003; -public class MyThread extends Thread { +import jdk.test.lib.thread.ThreadWrapper; + +public class MyThread extends ThreadWrapper { private static volatile int intState=100; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS204/hs204t003/hs204t003.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS204/hs204t003/hs204t003.java index b0f716794dc..6607f76899c 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS204/hs204t003/hs204t003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS204/hs204t003/hs204t003.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -61,6 +61,7 @@ package nsk.jvmti.scenarios.hotswap.HS204.hs204t003; import nsk.share.jvmti.RedefineAgent; +import jdk.test.lib.thread.ThreadWrapper; public class hs204t003 extends RedefineAgent { public native boolean popFrame(Thread thread) ; @@ -82,7 +83,7 @@ public class hs204t003 extends RedefineAgent { TempThread temp = new TempThread(); temp.start(); Thread.sleep(10000); - popFrame(temp); + popFrame(temp.getThread()); temp.join(); mthread = temp.mthread; mthread.start(); @@ -104,7 +105,7 @@ public class hs204t003 extends RedefineAgent { return passed; } } -class TempThread extends Thread { +class TempThread extends ThreadWrapper { public MyThread mthread; public TempThread() { super("TempThread."); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS204/hs204t003/newclass00/MyThread.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS204/hs204t003/newclass00/MyThread.java index be2bc229538..b685015a2e3 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS204/hs204t003/newclass00/MyThread.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS204/hs204t003/newclass00/MyThread.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * 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,10 @@ * questions. */ package nsk.jvmti.scenarios.hotswap.HS204.hs204t003; -public class MyThread extends Thread { + +import jdk.test.lib.thread.ThreadWrapper; + +public class MyThread extends ThreadWrapper { private static volatile int intState=0; public static int count=100; static { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS204/hs204t004/hs204t004.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS204/hs204t004/hs204t004.java index e06eceeb425..08cd7d22d56 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS204/hs204t004/hs204t004.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/hotswap/HS204/hs204t004/hs204t004.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +51,8 @@ package nsk.jvmti.scenarios.hotswap.HS204.hs204t004; import java.util.concurrent.atomic.AtomicBoolean; + +import jdk.test.lib.thread.ThreadWrapper; import nsk.share.jvmti.RedefineAgent; public class hs204t004 extends RedefineAgent { @@ -71,7 +73,7 @@ public class hs204t004 extends RedefineAgent { mt.start(); while(!MyThread.resume.get()) ; Thread.sleep(10000); - popFrame(mt); + popFrame(mt.getThread()); mt.join(); } catch(Exception exp) { exp.printStackTrace(); @@ -88,7 +90,7 @@ public class hs204t004 extends RedefineAgent { public static native boolean popFrame(Thread thread); } -class MyThread extends Thread { +class MyThread extends ThreadWrapper { public static AtomicBoolean resume = new AtomicBoolean(false); public String name="MyThread"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/multienv/MA03/ma03t001.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/multienv/MA03/ma03t001.java index 87751c5960f..7aab6551203 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/multienv/MA03/ma03t001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/multienv/MA03/ma03t001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,7 @@ import java.io.PrintStream; import nsk.share.*; import nsk.share.jvmti.*; +import jdk.test.lib.thread.ThreadWrapper; public class ma03t001 extends DebugeeClass { @@ -79,7 +80,7 @@ public class ma03t001 extends DebugeeClass { /* =================================================================== */ -class ma03t001Thread extends Thread { +class ma03t001Thread extends ThreadWrapper { public Wicket startingBarrier = new Wicket(); public Wicket endingBarrier = new Wicket(); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/sampling/SP01/sp01t001.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/sampling/SP01/sp01t001.java index 7686e68952e..4c9d9bc65a4 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/sampling/SP01/sp01t001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/sampling/SP01/sp01t001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ import java.io.PrintStream; import nsk.share.*; import nsk.share.jvmti.*; +import jdk.test.lib.thread.ThreadWrapper; + public class sp01t001 extends DebugeeClass { // run test from command line @@ -51,7 +53,8 @@ public class sp01t001 extends DebugeeClass { int status = Consts.TEST_PASSED; // tested threads list - static sp01t001Thread threads[] = null; + static sp01t001Thread threadWrappers[] = null; + static Thread threads[] = null; static int indexStartedThread = 0; // run debuggee class @@ -60,21 +63,25 @@ public class sp01t001 extends DebugeeClass { log = new Log(out, argHandler); // create threads list - threads = new sp01t001Thread[] { + threadWrappers = new sp01t001Thread[] { // not started thread new sp01t001ThreadNotStarted(), // started threads new sp01t001ThreadFinished() }; + threads = new Thread[] { + threadWrappers[0].getThread(), + threadWrappers[1].getThread() + }; indexStartedThread = 1; // run threads try { // start threads for (int i = indexStartedThread; i < threads.length; i++) { - synchronized (threads[i].startingMonitor) { + synchronized (threadWrappers[i].startingMonitor) { threads[i].start(); - threads[i].startingMonitor.wait(); + threadWrappers[i].startingMonitor.wait(); } } @@ -98,7 +105,7 @@ public class sp01t001 extends DebugeeClass { /* =================================================================== */ // basic class for tested threads -abstract class sp01t001Thread extends Thread { +abstract class sp01t001Thread extends ThreadWrapper { public Object startingMonitor = new Object(); } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/sampling/SP01/sp01t001/sp01t001.cpp b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/sampling/SP01/sp01t001/sp01t001.cpp index 40db16504b6..93a4e05b135 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/sampling/SP01/sp01t001/sp01t001.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/sampling/SP01/sp01t001/sp01t001.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,7 @@ extern "C" { /* constant names */ #define DEBUGEE_CLASS_NAME "nsk/jvmti/scenarios/sampling/SP01/sp01t001" -#define THREAD_CLASS_NAME "nsk/jvmti/scenarios/sampling/SP01/sp01t001Thread" +#define THREAD_CLASS_NAME "java/lang/Thread" #define THREADS_FIELD_NAME "threads" #define THREADS_FIELD_SIG "[L" THREAD_CLASS_NAME ";" diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/ExtraClassesBuilder.java b/test/hotspot/jtreg/vmTestbase/nsk/share/ExtraClassesBuilder.java index 162f8fa84c6..d92b1ef6b15 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/ExtraClassesBuilder.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/ExtraClassesBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -63,6 +63,8 @@ public class ExtraClassesBuilder { JDKToolLauncher javac = JDKToolLauncher.create("javac") .addToolArg("-d") .addToolArg(dst.toString()) + .addToolArg("-sourcepath") + .addToolArg(Utils.TEST_SRC_PATH) .addToolArg("-cp") .addToolArg(Utils.TEST_CLASS_PATH); diff --git a/test/lib/jdk/test/lib/Utils.java b/test/lib/jdk/test/lib/Utils.java index 2f46ed87340..95b7a117b2c 100644 --- a/test/lib/jdk/test/lib/Utils.java +++ b/test/lib/jdk/test/lib/Utils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +105,11 @@ public final class Utils { */ public static final String TEST_SRC = System.getProperty("test.src", "").trim(); + /** + * Returns the value of 'test.src.path' system property. + */ + public static final String TEST_SRC_PATH = System.getProperty("test.src.path", "").trim(); + /** * Returns the value of 'test.root' system property. */ diff --git a/test/lib/jdk/test/lib/thread/ThreadWrapper.java b/test/lib/jdk/test/lib/thread/ThreadWrapper.java new file mode 100644 index 00000000000..ab850bf5a4a --- /dev/null +++ b/test/lib/jdk/test/lib/thread/ThreadWrapper.java @@ -0,0 +1,246 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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.test.lib.thread; + +import java.time.Duration; +import java.util.Map; + +/* + The ThreadWrapper is a helper class that allows to extend + coverage of virtual threads testing for existing tests with threads. + + Specifically, it is useful for the pattern where Thread is extended + by some class. Example: + + class resumethrd02Thread extends Thread {...} + ... + resumethrd02Thread thr = new resumethrd02Thread(); + + The test can be updated to use this wrapper: + class resumethrd02Thread extends ThreadWrapper {...} + ... + resumethrd02Thread thr = new resumethrd02Thread(); + + So resumethrd02Thread can be run with platform or virtual threads. + + Method getThread() is used to get instance of Thread. + + It is not expected to use this wrapper for new tests or classes that + are not extending Thread. The TestThreadFactory should be used to + create threads in such cases. + */ + +public class ThreadWrapper implements Runnable { + private final Thread thread; + + @SuppressWarnings("this-escape") + public ThreadWrapper() { + // thread is a platform or virtual thread + thread = TestThreadFactory.newThread(this); + } + + @SuppressWarnings("this-escape") + public ThreadWrapper(String name) { + // thread is a platform or virtual thread + thread = TestThreadFactory.newThread(this, name); + } + + public Thread getThread() { + return thread; + } + + public static Thread currentThread() { + return Thread.currentThread(); + } + + public static void yield() { + Thread.yield(); + } + + public static void sleep(long millis) throws InterruptedException { + Thread.sleep(millis); + } + + public static void sleep(long millis, int nanos) throws InterruptedException { + Thread.sleep(millis, nanos); + } + + public static void sleep(Duration duration) throws InterruptedException { + Thread.sleep(duration); + } + + public static void onSpinWait() { + Thread.onSpinWait(); + } + + public static Thread.Builder.OfPlatform ofPlatform() { + return Thread.ofPlatform(); + } + + public static Thread.Builder.OfVirtual ofVirtual() { + return Thread.ofVirtual(); + } + + public static Thread startVirtualThread(Runnable task) { + return Thread.startVirtualThread(task); + } + + public boolean isVirtual() { + return thread.isVirtual(); + } + + public void start() { + thread.start(); + } + + public void run() { + } + + public void interrupt() { + thread.interrupt(); + } + + public static boolean interrupted() { + return Thread.interrupted(); + } + + public boolean isInterrupted() { + return thread.isInterrupted(); + } + + public boolean isAlive() { + return thread.isAlive(); + } + + public void setPriority(int newPriority) { + thread.setPriority(newPriority); + } + + public int getPriority() { + return thread.getPriority(); + } + + public void setName(String name) { + thread.setName(name); + } + + public String getName() { + return thread.getName(); + } + + public ThreadGroup getThreadGroup() { + return thread.getThreadGroup(); + } + + public static int activeCount() { + return Thread.activeCount(); + } + + public static int enumerate(Thread[] tarray) { + return Thread.enumerate(tarray); + } + + public void join(long millis) throws InterruptedException { + thread.join(millis); + } + + public void join(long millis, int nanos) throws InterruptedException { + thread.join(millis, nanos); + } + + public void join() throws InterruptedException { + thread.join(); + } + + public boolean join(Duration duration) throws InterruptedException { + return thread.join(duration); + } + + public static void dumpStack() { + Thread.dumpStack(); + } + + public void setDaemon(boolean on) { + thread.setDaemon(on); + } + + public boolean isDaemon() { + return thread.isDaemon(); + } + + @Override + public String toString() { + return thread.toString(); + } + + public ClassLoader getContextClassLoader() { + return thread.getContextClassLoader(); + } + + public void setContextClassLoader(ClassLoader cl) { + thread.setContextClassLoader(cl); + } + + public static boolean holdsLock(Object obj) { + return Thread.holdsLock(obj); + } + + public StackTraceElement[] getStackTrace() { + return thread.getStackTrace(); + } + + public static Map getAllStackTraces() { + return Thread.getAllStackTraces(); + } + + @Deprecated(since = "19") + public long getId() { + return thread.getId(); + } + + public long threadId() { + return thread.threadId(); + } + + public Thread.State getState() { + return thread.getState(); + } + + public static void setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler ueh) { + Thread.setDefaultUncaughtExceptionHandler(ueh); + } + + public static Thread.UncaughtExceptionHandler getDefaultUncaughtExceptionHandler() { + return Thread.getDefaultUncaughtExceptionHandler(); + } + + public Thread.UncaughtExceptionHandler getUncaughtExceptionHandler() { + return thread.getUncaughtExceptionHandler(); + } + + public void setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler ueh) { + thread.setUncaughtExceptionHandler(ueh); + } +} From aa5677afcbb4c42248168c364889cbd910327c0c Mon Sep 17 00:00:00 2001 From: Vladimir Ivanov Date: Fri, 10 Apr 2026 18:36:58 +0000 Subject: [PATCH 242/359] 8374496: C2: assert(val->find_edge(con) > 0) failed Reviewed-by: chagedorn, dfenacci --- src/hotspot/share/opto/parse2.cpp | 2 +- .../types/TestSubTypeCheckMismatch.java | 50 +++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 test/hotspot/jtreg/compiler/types/TestSubTypeCheckMismatch.java diff --git a/src/hotspot/share/opto/parse2.cpp b/src/hotspot/share/opto/parse2.cpp index a7c5398171b..ae20418942d 100644 --- a/src/hotspot/share/opto/parse2.cpp +++ b/src/hotspot/share/opto/parse2.cpp @@ -1803,8 +1803,8 @@ static bool match_type_check(PhaseGVN& gvn, assert(idx == 1 || idx == 2, ""); Node* vcon = val->in(idx); - assert(val->find_edge(con) > 0, ""); if ((btest == BoolTest::eq && vcon == con) || (btest == BoolTest::ne && vcon != con)) { + assert(val->find_edge(con) > 0, "mismatch"); SubTypeCheckNode* sub = b1->in(1)->as_SubTypeCheck(); Node* obj_or_subklass = sub->in(SubTypeCheckNode::ObjOrSubKlass); Node* superklass = sub->in(SubTypeCheckNode::SuperKlass); diff --git a/test/hotspot/jtreg/compiler/types/TestSubTypeCheckMismatch.java b/test/hotspot/jtreg/compiler/types/TestSubTypeCheckMismatch.java new file mode 100644 index 00000000000..5fcf93625a1 --- /dev/null +++ b/test/hotspot/jtreg/compiler/types/TestSubTypeCheckMismatch.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8374496 + * @summary "C2: assert(val->find_edge(con) > 0) failed" + * + * @run main/othervm -Xbatch ${test.main.class} + */ +package compiler.types; + +public class TestSubTypeCheckMismatch { + static class A {} + + static Integer test(Object o, int a, int b) { + int i = -1; + if (o instanceof A) { // results in SubTypeCheck node and diamond-shape if + i = Math.min(a, b); + } + return Integer.valueOf(i); // late inlined + } + + public static void main(String[] args) { + for (int i = 0; i < 20_000; i++) { + test(new A(), 0, 0); + test(new Object(), 0, 0); + } + } +} From 322f3a3447419ae661eb83be6b1ae07dc41562ce Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Fri, 10 Apr 2026 19:16:46 +0000 Subject: [PATCH 243/359] 8381932: Publish stubgen entries when -XX:-AOTStubCaching configured Reviewed-by: asmehra, kvn --- src/hotspot/share/code/aotCodeCache.cpp | 10 +++--- src/hotspot/share/code/aotCodeCache.hpp | 8 +++-- src/hotspot/share/runtime/stubRoutines.cpp | 41 +++++++++++++--------- 3 files changed, 33 insertions(+), 26 deletions(-) diff --git a/src/hotspot/share/code/aotCodeCache.cpp b/src/hotspot/share/code/aotCodeCache.cpp index 79211e75db4..a3dd3d2bfd0 100644 --- a/src/hotspot/share/code/aotCodeCache.cpp +++ b/src/hotspot/share/code/aotCodeCache.cpp @@ -1862,11 +1862,8 @@ void AOTCodeReader::read_dbg_strings(DbgStrings& dbg_strings) { // addresses, respectively, keyed by the relevant address void AOTCodeAddressTable::hash_address(address addr, int idx) { - // only do this if we are caching stubs and we have a non-null - // address to record - if (!AOTStubCaching) { - return; - } + // only do this if we have a non-null address to record and the + // cache is open for dumping if (addr == nullptr) { return; } @@ -2515,10 +2512,11 @@ AOTStubData::AOTStubData(BlobId blob_id) : // cannot be accessed before initialising the universe if (blob_id == BlobId::stubgen_preuniverse_id) { // invalidate any attempt to use this - _flags |= INVALID; + _flags = INVALID; return; } if (AOTCodeCache::is_on()) { + _flags = OPEN; // allow update of stub entry addresses if (AOTCodeCache::is_using_stub()) { // allow stub loading diff --git a/src/hotspot/share/code/aotCodeCache.hpp b/src/hotspot/share/code/aotCodeCache.hpp index c4ebe271767..5b773a986f1 100644 --- a/src/hotspot/share/code/aotCodeCache.hpp +++ b/src/hotspot/share/code/aotCodeCache.hpp @@ -236,9 +236,10 @@ private: // whether we are loading or storing stubs or have encountered any // invalid stubs. enum Flags { - USING = 1 << 0, // open and loading stubs - DUMPING = 1 << 1, // open and storing stubs - INVALID = 1 << 2, // found invalid stub when loading + OPEN = 1 << 0, // cache is open + USING = 1 << 1, // open and loading stubs + DUMPING = 1 << 2, // open and storing stubs + INVALID = 1 << 3, // found invalid stub when loading }; uint32_t _flags; @@ -253,6 +254,7 @@ public: ~AOTStubData() CDS_ONLY({FREE_C_HEAP_ARRAY(StubAddrRange, _ranges);}) NOT_CDS({}) + bool is_open() CDS_ONLY({ return (_flags & OPEN) != 0; }) NOT_CDS_RETURN_(false); bool is_using() CDS_ONLY({ return (_flags & USING) != 0; }) NOT_CDS_RETURN_(false); bool is_dumping() CDS_ONLY({ return (_flags & DUMPING) != 0; }) NOT_CDS_RETURN_(false); bool is_invalid() CDS_ONLY({ return (_flags & INVALID) != 0; }) NOT_CDS_RETURN_(false); diff --git a/src/hotspot/share/runtime/stubRoutines.cpp b/src/hotspot/share/runtime/stubRoutines.cpp index 0bc71c65471..f5509b9d996 100644 --- a/src/hotspot/share/runtime/stubRoutines.cpp +++ b/src/hotspot/share/runtime/stubRoutines.cpp @@ -178,18 +178,23 @@ static BufferBlob* initialize_stubs(BlobId blob_id, AOTStubData* stub_data_p = nullptr; LogTarget(Info, stubs) lt; + // we need to track and publish details of stubs in a stubgen blob + // when we are 1) using stubs from the cache 2) dumping stubs to the + // cache 3) generating stubs that may be needed by other cache + // elements. + + if (stub_data.is_open()) { + stub_data_p = &stub_data; + } if (code_size > 0 && stub_data.is_using()) { - // AOTCodeEntry tracks and logs status of any cached blob - bool loaded = stub_data.load_code_blob(); - if (loaded) { + // try to load the blob and details of its stubs from cache. if + // that fails we will still generate all necessary stubs + if (stub_data.load_code_blob()) { if (lt.is_enabled()) { LogStream ls(lt); ls.print_cr("Found blob %s in AOT cache", StubInfo::name(blob_id)); } - stub_data_p = &stub_data; } - } else if (stub_data.is_dumping()) { - stub_data_p = &stub_data; } // Even if we managed to load a blob from the AOT cache we still @@ -236,17 +241,8 @@ static BufferBlob* initialize_stubs(BlobId blob_id, "increase %s, code_size: %d, used: %d, free: %d", assert_msg, code_size, buffer.total_content_size(), buffer.insts_remaining()); - if (stub_data.is_using()) { - // we generated some new entries so republish all entries TODO - - // ensure we publish collect and publish the preuniverse stubs but - // don't try to save them - AOTCodeCache::publish_stub_addresses(*stubs_code, blob_id, &stub_data); - if (lt.is_enabled()) { - LogStream ls(lt); - ls.print_cr("Republished entries for blob '%s'", buffer_name); - } - } else if (stub_data.is_dumping()) { - // save the blob and publihs the entry addresses + if (stub_data.is_dumping()) { + // save the blob and publish the entry addresses if (stub_data.store_code_blob(*stubs_code, &buffer)) { if (lt.is_enabled()) { LogStream ls(lt); @@ -258,6 +254,17 @@ static BufferBlob* initialize_stubs(BlobId blob_id, ls.print_cr("Failed to store blob '%s' to Startup Code Cache", buffer_name); } } + } else if (stub_data.is_open()) { + // we either loaded some entries or generated new entries so + // publish all entries + // + // TODO - ensure we publish collect and publish the preuniverse + // stubs but don't try to save them + AOTCodeCache::publish_stub_addresses(*stubs_code, blob_id, &stub_data); + if (lt.is_enabled()) { + LogStream ls(lt); + ls.print_cr("Republished entries for blob '%s'", buffer_name); + } } // close off recording of any further stubgen generation From 88bd42d0350c126581b740bc9044aebcdb0138da Mon Sep 17 00:00:00 2001 From: William Kemper Date: Fri, 10 Apr 2026 19:39:39 +0000 Subject: [PATCH 244/359] 8314599: [GenShen] Couple adaptive tenuring and generation size budgeting Reviewed-by: kdnilsen, xpeng, ruili --- .../shenandoahGenerationalHeuristics.cpp | 124 ++++++++---------- .../shenandoahGenerationalHeuristics.hpp | 13 +- .../gc/shenandoah/shenandoahAgeCensus.cpp | 9 ++ .../gc/shenandoah/shenandoahAgeCensus.hpp | 6 + .../shenandoah/test_shenandoahAgeCensus.cpp | 9 +- 5 files changed, 93 insertions(+), 68 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp index 45ba2740ea5..a12f48c0877 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp @@ -38,11 +38,6 @@ using idx_t = ShenandoahSimpleBitMap::idx_t; -typedef struct { - ShenandoahHeapRegion* _region; - size_t _live_data; -} AgedRegionData; - static int compare_by_aged_live(AgedRegionData a, AgedRegionData b) { if (a._live_data < b._live_data) return -1; @@ -321,12 +316,48 @@ void ShenandoahGenerationalHeuristics::filter_regions(ShenandoahCollectionSet* c immediate_garbage); } -// Select for inclusion into the collection set all regions whose age is at or above tenure age and for which the -// garbage percentage exceeds a dynamically adjusted threshold (known as the old-garbage threshold percentage). We -// identify these regions by setting the appropriate entry of the collection set's preselected regions array to true. -// All entries are initialized to false before calling this function. +void ShenandoahGenerationalHeuristics::add_tenured_regions_to_collection_set(const size_t old_promotion_reserve, + ShenandoahGenerationalHeap *const heap, + size_t candidates, AgedRegionData* sorted_regions) { + size_t old_consumed = 0; + if (candidates > 0) { + // Sort in increasing order according to live data bytes. Note that + // candidates represents the number of regions that qualify to be promoted + // by evacuation. + QuickSort::sort(sorted_regions, candidates, + compare_by_aged_live); + + size_t selected_regions = 0; + size_t selected_live = 0; + for (size_t i = 0; i < candidates; i++) { + ShenandoahHeapRegion *const region = sorted_regions[i]._region; + const size_t region_live_data = sorted_regions[i]._live_data; + const size_t promotion_need = (size_t)(region_live_data * ShenandoahPromoEvacWaste); + if (old_consumed + promotion_need > old_promotion_reserve) { + // We rejected the remaining promotable regions from the collection set + // because we have no room to hold their evacuees. We do not need to + // iterate the remaining regions to estimate the amount we expect to + // promote because we know it directly form the census we computed + // during the preceding mark phase. + break; + } + + old_consumed += promotion_need; + heap->collection_set()->add_region(region); + selected_regions++; + selected_live += region_live_data; + } + log_debug(gc, ergo)( "Preselected %zu regions containing " PROPERFMT " live data," + " consuming: " PROPERFMT " of budgeted: " PROPERFMT, + selected_regions, PROPERFMTARGS(selected_live), + PROPERFMTARGS(old_consumed), PROPERFMTARGS(old_promotion_reserve)); + } +} + +// Select for inclusion into the collection set all regions whose age is at or +// above tenure age and for which the +// garbage percentage exceeds a dynamically adjusted threshold (known as the old-garbage threshold percentage). // -// During the subsequent selection of the collection set, we give priority to these promotion set candidates. // Without this prioritization, we found that the aged regions tend to be ignored because they typically have // much less garbage and much more live data than the recently allocated "eden" regions. When aged regions are // repeatedly excluded from the collection set, the amount of live memory within the young generation tends to @@ -334,8 +365,8 @@ void ShenandoahGenerationalHeuristics::filter_regions(ShenandoahCollectionSet* c // CPU and wall-clock time. // // A second benefit of treating aged regions differently than other regions during collection set selection is -// that this allows us to more accurately budget memory to hold the results of evacuation. Memory for evacuation -// of aged regions must be reserved in the old generation. Memory for evacuation of all other regions must be +// that this allows us to more accurately budget memory to hold the results of evacuation. Memory for evacuation +// of aged regions must be reserved in the old generation. Memory for evacuation of all other regions must be // reserved in the young generation. size_t ShenandoahGenerationalHeuristics::select_aged_regions(ShenandoahInPlacePromotionPlanner& in_place_promotions, const size_t old_promotion_reserve) { @@ -345,7 +376,6 @@ size_t ShenandoahGenerationalHeuristics::select_aged_regions(ShenandoahInPlacePr auto const heap = ShenandoahGenerationalHeap::heap(); - size_t promo_potential = 0; size_t candidates = 0; // Sort the promotion-eligible regions in order of increasing live-data-bytes so that we can first reclaim regions that require @@ -386,66 +416,28 @@ size_t ShenandoahGenerationalHeuristics::select_aged_regions(ShenandoahInPlacePr sorted_regions[candidates]._live_data = r->get_live_data_bytes(); candidates++; } - } else { - // We only evacuate & promote objects from regular regions whose garbage() is above old-garbage-threshold. - // Objects in tenure-worthy regions with less garbage are promoted in place. These take a different path to - // old-gen. Regions excluded from promotion because their garbage content is too low (causing us to anticipate that - // the region would be promoted in place) may be eligible for evacuation promotion by the time promotion takes - // place during a subsequent GC pass because more garbage is found within the region between now and then. This - // should not happen if we are properly adapting the tenure age. The theory behind adaptive tenuring threshold - // is to choose the youngest age that demonstrates no "significant" further loss of population since the previous - // age. If not this, we expect the tenure age to demonstrate linear population decay for at least two population - // samples, whereas we expect to observe exponential population decay for ages younger than the tenure age. - // - // In the case that certain regions which were anticipated to be promoted in place need to be promoted by - // evacuation, it may be the case that there is not sufficient reserve within old-gen to hold evacuation of - // these regions. The likely outcome is that these regions will not be selected for evacuation or promotion - // in the current cycle and we will anticipate that they will be promoted in the next cycle. This will cause - // us to reserve more old-gen memory so that these objects can be promoted in the subsequent cycle. - if (heap->is_aging_cycle() && heap->age_census()->is_tenurable(r->age() + 1)) { - if (r->garbage() >= in_place_promotions.old_garbage_threshold()) { - promo_potential += r->get_live_data_bytes(); - } - } } - // Note that we keep going even if one region is excluded from selection. - // Subsequent regions may be selected if they have smaller live data. } in_place_promotions.complete_planning(); - // Sort in increasing order according to live data bytes. Note that candidates represents the number of regions - // that qualify to be promoted by evacuation. - size_t old_consumed = 0; - if (candidates > 0) { - size_t selected_regions = 0; - size_t selected_live = 0; - QuickSort::sort(sorted_regions, candidates, compare_by_aged_live); - for (size_t i = 0; i < candidates; i++) { - ShenandoahHeapRegion* const region = sorted_regions[i]._region; - const size_t region_live_data = sorted_regions[i]._live_data; - const size_t promotion_need = (size_t) (region_live_data * ShenandoahPromoEvacWaste); - if (old_consumed + promotion_need <= old_promotion_reserve) { - old_consumed += promotion_need; - heap->collection_set()->add_region(region); - selected_regions++; - selected_live += region_live_data; - } else { - // We rejected this promotable region from the collection set because we had no room to hold its copy. - // Add this region to promo potential for next GC. - promo_potential += region_live_data; - assert(!heap->collection_set()->is_in(region), "Region %zu shouldn't be in the collection set", region->index()); - } - // We keep going even if one region is excluded from selection because we need to accumulate all eligible - // regions that are not preselected into promo_potential - } - log_debug(gc, ergo)("Preselected %zu regions containing " PROPERFMT " live data," - " consuming: " PROPERFMT " of budgeted: " PROPERFMT, - selected_regions, PROPERFMTARGS(selected_live), PROPERFMTARGS(old_consumed), PROPERFMTARGS(old_promotion_reserve)); - } + add_tenured_regions_to_collection_set(old_promotion_reserve, heap, candidates, sorted_regions); - log_info(gc, ergo)("Promotion potential of aged regions with sufficient garbage: " PROPERFMT, PROPERFMTARGS(promo_potential)); + const uint tenuring_threshold = heap->age_census()->tenuring_threshold(); + const size_t tenurable_this_cycle = heap->age_census()->get_tenurable_bytes(tenuring_threshold); + const size_t tenurable_next_cycle = heap->age_census()->get_tenurable_bytes(tenuring_threshold - 1); + assert(tenurable_next_cycle >= tenurable_this_cycle, + "Tenurable next cycle (" PROPERFMT ") should include tenurable this cycle (" PROPERFMT ")", + PROPERFMTARGS(tenurable_next_cycle), PROPERFMTARGS(tenurable_this_cycle)); + + const size_t max_promotions = tenurable_this_cycle * ShenandoahPromoEvacWaste; + const size_t old_consumed = MIN2(max_promotions, old_promotion_reserve); + + // Don't include the bytes we expect to promote in this cycle in the next cycle + const size_t promo_potential = (tenurable_next_cycle - tenurable_this_cycle) * ShenandoahPromoEvacWaste; heap->old_generation()->set_promotion_potential(promo_potential); + log_info(gc, ergo)("Promotion potential of aged regions with sufficient garbage: " PROPERFMT, PROPERFMTARGS(promo_potential)); + return old_consumed; } diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.hpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.hpp index d6551cffb73..1a47cb756f4 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.hpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.hpp @@ -34,6 +34,11 @@ class ShenandoahHeap; class ShenandoahCollectionSet; class RegionData; +typedef struct { + ShenandoahHeapRegion* _region; + size_t _live_data; +} AgedRegionData; + /* * This class serves as the base class for heuristics used to trigger and * choose the collection sets for young and global collections. It leans @@ -50,7 +55,7 @@ public: void choose_collection_set(ShenandoahCollectionSet* collection_set) override; - virtual void post_initialize() override; + void post_initialize() override; private: // Compute evacuation budgets prior to choosing collection set. @@ -73,6 +78,12 @@ private: // to false. size_t select_aged_regions(ShenandoahInPlacePromotionPlanner& in_place_promotions, const size_t old_promotion_reserve); + // Select regions for inclusion in the collection set that are tenured, but do + // not hold enough live data to warrant promotion in place. + void add_tenured_regions_to_collection_set(size_t old_promotion_reserve, + ShenandoahGenerationalHeap *const heap, + size_t candidates, AgedRegionData* sorted_regions); + // Filter and sort remaining regions before adding to collection set. void filter_regions(ShenandoahCollectionSet* collection_set); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.cpp b/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.cpp index 71fd6e37614..a81efa99d70 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.cpp @@ -171,6 +171,15 @@ void ShenandoahAgeCensus::update_census(size_t age0_pop) { NOT_PRODUCT(update_total();) } +size_t ShenandoahAgeCensus::get_tenurable_bytes(const uint tenuring_threshold) const { + assert(_epoch < MAX_SNAPSHOTS, "Out of bounds"); + size_t total = 0; + const AgeTable* pv = _global_age_tables[_epoch]; + for (uint i = tenuring_threshold; i < MAX_COHORTS; i++) { + total += pv->sizes[i]; + } + return total * HeapWordSize; +} // Reset the epoch for the global age tables, // clearing all history. diff --git a/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.hpp b/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.hpp index 9c5baaedcd6..c140f445e21 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.hpp @@ -216,6 +216,12 @@ class ShenandoahAgeCensus: public CHeapObj { // allocated when the concurrent marking was in progress. void update_census(size_t age0_pop); + // Return the total size of the population at or above the given threshold for the current epoch + size_t get_tenurable_bytes(uint tenuring_threshold) const; + + // As above, but use the current tenuring threshold + size_t get_tenurable_bytes() const { return get_tenurable_bytes(tenuring_threshold()); } + // Reset the epoch, clearing accumulated census history // Note: this isn't currently used, but reserved for planned // future usage. diff --git a/test/hotspot/gtest/gc/shenandoah/test_shenandoahAgeCensus.cpp b/test/hotspot/gtest/gc/shenandoah/test_shenandoahAgeCensus.cpp index c53d0a15554..0b89c59634a 100644 --- a/test/hotspot/gtest/gc/shenandoah/test_shenandoahAgeCensus.cpp +++ b/test/hotspot/gtest/gc/shenandoah/test_shenandoahAgeCensus.cpp @@ -63,7 +63,7 @@ protected: total += _cohort_populations[i]; } } - return total; + return total * HeapWordSize; } void promote_all_tenurable(const size_t tenuring_threshold) { @@ -87,6 +87,13 @@ TEST_F(ShenandoahAgeCensusTest, initialize) { EXPECT_EQ(census.tenuring_threshold(), ShenandoahAgeCensus::MAX_COHORTS); } +TEST_F(ShenandoahAgeCensusTest, get_tenurable_bytes) { + ShenandoahAgeCensus census(1); + update(census); + EXPECT_EQ(get_total_population_older_than(1), census.get_tenurable_bytes(1)); + EXPECT_LT(census.get_tenurable_bytes(2), census.get_tenurable_bytes(1)); +} + TEST_F(ShenandoahAgeCensusTest, ignore_small_populations) { // Small populations are ignored so we do not return early before reaching the youngest cohort. ShenandoahAgeCensus census(1); From aa6db8d06e59bb91630be6d7f75da195d39d3190 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Fri, 10 Apr 2026 23:44:17 +0000 Subject: [PATCH 245/359] 8382022: jpackage: enhance CompositeProxy Reviewed-by: almatvee --- .../internal/util/CompositeProxy.java | 737 +++++++----- .../internal/util/CompositeProxyTest.java | 1062 +++++++++++++++-- .../tools/jdk/jpackage/test/JUnitUtils.java | 14 + 3 files changed, 1464 insertions(+), 349 deletions(-) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CompositeProxy.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CompositeProxy.java index 39a9d319468..e4257c87306 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CompositeProxy.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CompositeProxy.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,17 +31,17 @@ import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.lang.reflect.Proxy; +import java.util.ArrayList; import java.util.Arrays; +import java.util.BitSet; import java.util.Collection; import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.Set; -import java.util.function.BinaryOperator; +import java.util.Optional; import java.util.function.Predicate; +import java.util.stream.Collectors; import java.util.stream.Stream; /** @@ -95,11 +95,9 @@ import java.util.stream.Stream; * } * }; * - * Sloop sloop = CompositeProxy.create(Sloop.class, new Sailboat() { - * }, withMain, withJib); + * Sloop sloop = CompositeProxy.create(Sloop.class, withMain, withJib); * - * Catboat catboat = CompositeProxy.create(Catboat.class, new Sailboat() { - * }, withMain); + * Catboat catboat = CompositeProxy.create(Catboat.class, withMain); * * sloop.trimSails(); * catboat.trimSails(); @@ -137,20 +135,60 @@ public final class CompositeProxy { * dispatching the interface method invocations to the given handlers */ public T create(Class interfaceType, Object... slices) { - return CompositeProxy.createCompositeProxy(interfaceType, conflictResolver, invokeTunnel, slices); + return CompositeProxy.createCompositeProxy( + interfaceType, + Optional.ofNullable(methodConflictResolver).orElse(JPACKAGE_METHOD_CONFLICT_RESOLVER), + Optional.ofNullable(objectConflictResolver).orElse(JPACKAGE_OBJECT_CONFLICT_RESOLVER), + invokeTunnel, + allowUnreferencedSlices, + slices); } /** * Sets the method dispatch conflict resolver for this builder. The conflict * resolver is used by composite proxy to select a method call handler from - * multiple candidates. + * several candidates. * - * @param v the conflict resolver for this builder or null if the - * default conflict resolver should be used + * @param v the method conflict resolver for this builder or null + * if the default conflict resolver should be used * @return this */ - public Builder conflictResolver(BinaryOperator v) { - conflictResolver = v; + public Builder methodConflictResolver(MethodConflictResolver v) { + methodConflictResolver = v; + return this; + } + + /** + * Sets the object dispatch conflict resolver for this builder. The conflict + * resolver is used by the composite proxy to select an object from several + * candidates. + * + * @param v the object conflict resolver for this builder or null + * if the default conflict resolver should be used + * @return this + */ + public Builder objectConflictResolver(ObjectConflictResolver v) { + objectConflictResolver = v; + return this; + } + + /** + * Configures if this builder allows unreferenced slices in the + * {@link #create(Class, Object...)}. + *

+ * By default, if the builder happens to create such a composite proxy that one + * or more slices passed in the {@link #create(Class, Object...)} method happen + * to be unreferenced, it will throw {@code IllegalArgumentException}. Passing + * true disables this throw cause. + * + * @param v true to disable throwing of + * {@code IllegalArgumentException} from + * {@link #create(Class, Object...)} if some of the passed in slices + * happen to be unreferenced and false otherwise + * @return this + */ + public Builder allowUnreferencedSlices(boolean v) { + allowUnreferencedSlices = v; return this; } @@ -168,8 +206,65 @@ public final class CompositeProxy { private Builder() {} - private BinaryOperator conflictResolver = STANDARD_CONFLICT_RESOLVER; + private MethodConflictResolver methodConflictResolver; + private ObjectConflictResolver objectConflictResolver; private InvokeTunnel invokeTunnel; + private boolean allowUnreferencedSlices; + } + + /** + * Method conflict resolver. Used when the composite proxy needs to decide if + * the default method of the interface it implements should be overridden by an + * implementing object. + */ + @FunctionalInterface + public interface MethodConflictResolver { + + /** + * Returns {@code true} if the composite proxy should override the default + * method {@code method} in {@code interfaceType} type with the corresponding + * method form the {@code obj}. + * + * @param interfaceType the interface type composite proxy instance should + * implement + * @param slices all objects passed to the calling composite proxy. The + * value is a copy of the last parameter passed in the + * {@link Builder#create(Class, Object...)} + * @param method default method in {@code interfaceType} type + * @param obj object providing a usable method with the same signature + * (the name and parameter types) as the signature of the + * {@code method} method + */ + boolean isOverrideDefault(Class interfaceType, Object[] slices, Method method, Object obj); + } + + /** + * Object conflict resolver. Used when several objects have methods that are + * candidates to implement some method in an interface and the composite proxy + * needs to choose one of these objects. + */ + @FunctionalInterface + public interface ObjectConflictResolver { + + /** + * Returns the object that should be used in a composite proxy to implement + * abstract method {@code method}. + * + * @param interfaceType the interface type composite proxy instance should + * implement + * @param slices all objects passed to the calling composite proxy. The + * value is a copy of the last parameter passed in the + * {@link Builder#create(Class, Object...)} + * @param method abstract method + * @param candidates objects with a method with the same signature (the name + * and parameter types) as the signature of the + * {@code method} method. The array is unordered, doesn't + * contain duplicates, and is a subset of the + * {@code slices} array + * @return either one of items from the {@code candidates} or {@code null} if + * can't choose one + */ + Object choose(Class interfaceType, Object[] slices, Method method, Object[] candidates); } /** @@ -263,233 +358,231 @@ public final class CompositeProxy { private CompositeProxy() { } - private static T createCompositeProxy(Class interfaceType, BinaryOperator conflictResolver, - InvokeTunnel invokeTunnel, Object... slices) { + private static T createCompositeProxy( + Class interfaceType, + MethodConflictResolver methodConflictResolver, + ObjectConflictResolver objectConflictResolver, + InvokeTunnel invokeTunnel, + boolean allowUnreferencedSlices, + Object... slices) { - validateTypeIsInterface(interfaceType); + Objects.requireNonNull(interfaceType); + Objects.requireNonNull(methodConflictResolver); + Objects.requireNonNull(objectConflictResolver); + Stream.of(slices).forEach(Objects::requireNonNull); - final var interfaces = interfaceType.getInterfaces(); - List.of(interfaces).forEach(CompositeProxy::validateTypeIsInterface); - - if (interfaces.length != slices.length) { - throw new IllegalArgumentException( - String.format("type %s must extend %d interfaces", interfaceType.getName(), slices.length)); + if (!interfaceType.isInterface()) { + throw new IllegalArgumentException(String.format("Type %s must be an interface", interfaceType.getName())); } - final Map, Object> interfaceDispatch = createInterfaceDispatch(interfaces, slices); + final var uniqueSlices = Stream.of(slices).map(IdentityWrapper::new).collect(toSet()); + + final var unreferencedSlicesBuilder = SetBuilder.>build().emptyAllowed(true); + + if (!allowUnreferencedSlices) { + unreferencedSlicesBuilder.add(uniqueSlices); + } final Map methodDispatch = getProxyableMethods(interfaceType).map(method -> { - var handler = createHandler(interfaceType, method, interfaceDispatch, conflictResolver, invokeTunnel); - if (handler != null) { - return Map.entry(method, handler); - } else { - return null; + return Map.entry(method, uniqueSlices.stream().flatMap(slice -> { + var sliceMethods = getImplementerMethods(slice.value()).filter(sliceMethod -> { + return signatureEquals(sliceMethod, method); + }).toList(); + + if (sliceMethods.size() > 1) { + throw new AssertionError(); + } + + return sliceMethods.stream().findFirst().map(sliceMethod -> { + return Map.entry(slice, sliceMethod); + }).stream(); + }).toList()); + }).flatMap(e -> { + final Method method = e.getKey(); + final List, Method>> slicesWithMethods = e.getValue(); + + final Map.Entry, Method> sliceWithMethods; + switch (slicesWithMethods.size()) { + case 0 -> { + if (!method.isDefault()) { + throw new IllegalArgumentException(String.format("None of the slices can handle %s", method)); + } else { + return Optional.ofNullable(createHandlerForDefaultMethod(method, invokeTunnel)).map(handler -> { + return Map.entry(method, handler); + }).stream(); + } + } + case 1 -> { + sliceWithMethods = slicesWithMethods.getFirst(); + } + default -> { + var candidates = slicesWithMethods.stream().map(sliceEntry -> { + return sliceEntry.getKey().value(); + }).toList(); + + var candidate = objectConflictResolver.choose( + interfaceType, Arrays.copyOf(slices, slices.length), method, candidates.toArray()); + if (candidate == null) { + throw new IllegalArgumentException(String.format( + "Ambiguous choice between %s for %s", candidates, method)); + } + + var candidateIdentity = IdentityWrapper.wrapIdentity(candidate); + + if (candidates.stream().map(IdentityWrapper::new).noneMatch(Predicate.isEqual(candidateIdentity))) { + throw new UnsupportedOperationException(); + } + + sliceWithMethods = slicesWithMethods.stream().filter(v -> { + return candidateIdentity.equals(v.getKey()); + }).findFirst().orElseThrow(); + } } - }).filter(Objects::nonNull).collect(toMap(Map.Entry::getKey, Map.Entry::getValue)); + + final var slice = sliceWithMethods.getKey().value(); + final var sliceMethod = sliceWithMethods.getValue(); + final Handler handler; + if (!method.isDefault() + || (method.equals(sliceMethod) + && getUnfilteredImplementerMethods(slice) + .map(FullMethodSignature::new) + .anyMatch(Predicate.isEqual(new FullMethodSignature(sliceMethod)))) + || ( method.getReturnType().equals(sliceMethod.getReturnType()) + && !sliceMethod.isDefault() + && methodConflictResolver.isOverrideDefault(interfaceType, Arrays.copyOf(slices, slices.length), method, slice))) { + // Use implementation from the slice if one of the statements is "true": + // - The target method is abstract (not default) + // - The target method is default and it is the same method in the slice which overrides it. + // This is a special case when default method must not be invoked via InvocationHandler.invokeDefault(). + // - The target method is default and the matching slice method has the same return type, + // is not default, and the method conflict resolver approves the use of the slice method + if (!allowUnreferencedSlices) { + unreferencedSlicesBuilder.remove(sliceWithMethods.getKey()); + } + handler = createHandlerForMethod(slice, sliceMethod, invokeTunnel); + } else { + handler = createHandlerForDefaultMethod(method, invokeTunnel); + } + + return Optional.ofNullable(handler).map(h -> { + return Map.entry(method, h); + }).stream(); + + }).collect(toMap(Map.Entry::getKey, Map.Entry::getValue)); + + if (!allowUnreferencedSlices) { + var unreferencedSlices = unreferencedSlicesBuilder.create().stream().map(IdentityWrapper::value).toList(); + if (!unreferencedSlices.isEmpty()) { + throw new IllegalArgumentException(String.format("Unreferenced slices: %s", unreferencedSlices)); + } + } @SuppressWarnings("unchecked") T proxy = (T) Proxy.newProxyInstance(interfaceType.getClassLoader(), new Class[] { interfaceType }, - new CompositeProxyInvocationHandler(methodDispatch)); + new CompositeProxyInvocationHandler(Collections.unmodifiableMap(methodDispatch))); return proxy; } - private record InterfaceDispatchBuilder(Set> interfaces, Collection slices) { - - InterfaceDispatchBuilder { - Objects.requireNonNull(interfaces); - Objects.requireNonNull(slices); - - if (interfaces.isEmpty()) { - throw new IllegalArgumentException("No interfaces to dispatch"); - } - - if (slices.isEmpty()) { - throw createInterfaceNotImplementedException(interfaces); - } - } - - InterfaceDispatchBuilder(Result result) { - this(result.unservedInterfaces(), result.unusedSlices()); - } - - Map, List> createDispatchGroups() { - return interfaces.stream().collect(toMap(x -> x, iface -> { - return slices.stream().filter(obj -> { - return Stream.of(obj.getClass().getInterfaces()).flatMap(sliceIface -> { - return unfoldInterface(sliceIface); - }).anyMatch(Predicate.isEqual(iface)); - }).toList(); - })); - } - - Result createDispatch() { - var groups = createDispatchGroups(); - - var dispatch = groups.entrySet().stream().filter(e -> { - return e.getValue().size() == 1; - }).collect(toMap(Map.Entry::getKey, e -> { - return e.getValue().getFirst(); - })); - - var unservedInterfaces = groups.entrySet().stream().filter(e -> { - return e.getValue().size() != 1; - }).map(Map.Entry::getKey).collect(toSet()); - - var usedSliceIdentities = dispatch.values().stream() - .map(IdentityWrapper::new) - .collect(toSet()); - - var unusedSliceIdentities = new HashSet<>(toIdentitySet(slices)); - unusedSliceIdentities.removeAll(usedSliceIdentities); - - return new Result(dispatch, unservedInterfaces, unusedSliceIdentities.stream().map(IdentityWrapper::value).toList()); - } - - private record Result(Map, Object> dispatch, Set> unservedInterfaces, Collection unusedSlices) { - - Result { - Objects.requireNonNull(dispatch); - Objects.requireNonNull(unservedInterfaces); - Objects.requireNonNull(unusedSlices); - - if (!Collections.disjoint(dispatch.keySet(), unservedInterfaces)) { - throw new IllegalArgumentException(); - } - - if (!Collections.disjoint(toIdentitySet(dispatch.values()), toIdentitySet(unusedSlices))) { - throw new IllegalArgumentException(); - } - } - } - - private static Collection> toIdentitySet(Collection v) { - return v.stream().map(IdentityWrapper::new).collect(toSet()); - } - } - - private static Map, Object> createInterfaceDispatch(Class[] interfaces, Object[] slices) { - - if (interfaces.length == 0) { - return Collections.emptyMap(); - } - - Map, Object> dispatch = new HashMap<>(); - - var builder = new InterfaceDispatchBuilder(Set.of(interfaces), List.of(slices)); - for (;;) { - var result = builder.createDispatch(); - if (result.dispatch().isEmpty()) { - var unserved = builder.createDispatchGroups(); - for (var e : unserved.entrySet()) { - var iface = e.getKey(); - var ifaceSlices = e.getValue(); - if (ifaceSlices.size() > 1) { - throw new IllegalArgumentException( - String.format("multiple slices %s implement %s", ifaceSlices, iface)); - } - } - - var unservedInterfaces = unserved.entrySet().stream().filter(e -> { - return e.getValue().isEmpty(); - }).map(Map.Entry::getKey).toList(); - throw createInterfaceNotImplementedException(unservedInterfaces); - } else { - dispatch.putAll(result.dispatch()); - if (result.unservedInterfaces().isEmpty()) { - break; - } - } - - builder = new InterfaceDispatchBuilder(result); - } - - return dispatch.keySet().stream().flatMap(iface -> { - return unfoldInterface(iface).map(unfoldedIface -> { - return Map.entry(unfoldedIface, dispatch.get(iface)); - }); - }).collect(toMap(Map.Entry::getKey, Map.Entry::getValue)); - } - private static Stream> unfoldInterface(Class interfaceType) { - return Stream.concat(Stream.of(interfaceType), - Stream.of(interfaceType.getInterfaces()).flatMap(CompositeProxy::unfoldInterface)); + return Stream.concat( + Stream.of(interfaceType), + Stream.of(interfaceType.getInterfaces() + ).flatMap(CompositeProxy::unfoldInterface)); } - private static IllegalArgumentException createInterfaceNotImplementedException( - Collection> missingInterfaces) { - return new IllegalArgumentException(String.format("none of the slices implement %s", missingInterfaces)); - } + private static List> getSuperclasses(Class type) { + List> superclasses = new ArrayList<>(); - private static void validateTypeIsInterface(Class type) { - if (!type.isInterface()) { - throw new IllegalArgumentException(String.format("type %s must be an interface", type.getName())); + var current = type.getSuperclass(); + + while (current != null) { + superclasses.add(current); + current = current.getSuperclass(); } + + return superclasses; } - private static Handler createHandler(Class interfaceType, Method method, Map, Object> interfaceDispatch, - BinaryOperator conflictResolver, InvokeTunnel invokeTunnel) { - - final var methodDeclaringClass = method.getDeclaringClass(); - - if (!methodDeclaringClass.equals(interfaceType)) { - // The method is declared in one of the superinterfaces. - final var slice = interfaceDispatch.get(methodDeclaringClass); - - if (isInvokeDefault(method, slice)) { - return createHandlerForDefaultMethod(method, invokeTunnel); - } else { - return createHandlerForMethod(slice, method, invokeTunnel); - } - } else if (method.isDefault()) { - return createHandlerForDefaultMethod(method, invokeTunnel); - } else { - // Find a slice handling the method. - var handler = interfaceDispatch.entrySet().stream().map(e -> { - try { - Class iface = e.getKey(); - Object slice = e.getValue(); - return createHandlerForMethod(slice, iface.getMethod(method.getName(), method.getParameterTypes()), - invokeTunnel); - } catch (NoSuchMethodException ex) { - return null; - } - }).filter(Objects::nonNull).reduce(new ConflictResolverAdapter(conflictResolver)).orElseThrow(() -> { - return new IllegalArgumentException(String.format("none of the slices can handle %s", method)); - }); - - return handler; - } + private static Stream getUnfilteredProxyableMethods(Class interfaceType) { + return unfoldInterface(interfaceType).flatMap(type -> { + return Stream.of(type.getMethods()); + }).filter(method -> { + return !Modifier.isStatic(method.getModifiers()) + && !method.isBridge(); + }); } private static Stream getProxyableMethods(Class interfaceType) { - return Stream.of(interfaceType.getMethods()).filter(method -> !Modifier.isStatic(method.getModifiers())); + return removeRedundancy(getUnfilteredProxyableMethods(interfaceType)); } - private static boolean isInvokeDefault(Method method, Object slice) { - if (!method.isDefault()) { - return false; - } + private static Stream getUnfilteredImplementerMethods(Object slice) { + var sliceType = slice.getClass(); - // The "method" is default. - // See if is overridden by any non-abstract method in the "slice". - // If it is, InvocationHandler.invokeDefault() should not be used to call it. + return Stream.of( + Stream.of(sliceType), + getSuperclasses(sliceType).stream() + ).flatMap(x -> x).flatMap(type -> { + return Stream.of(type.getMethods()); + }).filter(method -> { + return !Modifier.isStatic(method.getModifiers()) + && !method.isBridge() + && !method.isDefault() + && !Modifier.isPrivate(method.getModifiers()); + }); + } - final var sliceClass = slice.getClass(); + private static Stream getImplementerMethods(Object slice) { + var sliceType = slice.getClass(); - final var methodOverriden = Stream.of(sliceClass.getMethods()).filter(Predicate.not(Predicate.isEqual(method))) - .filter(sliceMethod -> !Modifier.isAbstract(sliceMethod.getModifiers())) - .anyMatch(sliceMethod -> signatureEquals(sliceMethod, method)); + var proxyableMethods = Stream.of( + Stream.of(sliceType), + getSuperclasses(sliceType).stream() + ).flatMap(x -> x) + .map(Class::getInterfaces) + .flatMap(Stream::of) + .flatMap(CompositeProxy::unfoldInterface) + .flatMap(CompositeProxy::getUnfilteredProxyableMethods) + .toList(); - return !methodOverriden; + var proxyableMethodSignatures = proxyableMethods.stream() + .map(FullMethodSignature::new) + .collect(toSet()); + + var methods = getUnfilteredImplementerMethods(slice).filter(method -> { + return !proxyableMethodSignatures.contains(new FullMethodSignature(method)); + }); + + return removeRedundancy(Stream.concat(methods, proxyableMethods.stream())); + } + + private static Stream removeRedundancy(Stream methods) { + var groups = methods.distinct().collect(Collectors.groupingBy(MethodSignature::new)).values(); + return groups.stream().map(group -> { + // All but a single method should be filtered out from the group. + return group.stream().reduce((a, b) -> { + var ac = a.getDeclaringClass(); + var bc = b.getDeclaringClass(); + if (ac.equals(bc)) { + // Both methods don't fit: they are declared in the same class and have the same signatures. + // That is possible only with code generation bypassing compiler checks. + throw new AssertionError(); + } else if (ac.isAssignableFrom(bc)) { + return b; + } else if (bc.isAssignableFrom(ac)) { + return a; + } else if (a.isDefault()) { + return b; + } else { + return a; + } + }).orElseThrow(); + }); } private static boolean signatureEquals(Method a, Method b) { - if (!Objects.equals(a.getName(), b.getName()) || !Arrays.equals(a.getParameterTypes(), b.getParameterTypes())) { - return false; - } - - return Objects.equals(a.getReturnType(), b.getReturnType()); + return Objects.equals(new MethodSignature(a), new MethodSignature(b)); } private record CompositeProxyInvocationHandler(Map dispatch) implements InvocationHandler { @@ -515,22 +608,14 @@ public final class CompositeProxy { return obj.getClass().getName() + '@' + Integer.toHexString(System.identityHashCode(obj)); } - private static boolean objectEquals(Object obj, Object other) { + private static boolean objectIsSame(Object obj, Object other) { return obj == other; } - private static Method getMethod(Class type, String methodName, Class...paramaterTypes) { - try { - return type.getDeclaredMethod(methodName, paramaterTypes); - } catch (NoSuchMethodException|SecurityException ex) { - throw new InternalError(ex); - } - } + private record ObjectMethodHandler(Method method) implements Handler { - static class ObjectMethodHandler extends HandlerOfMethod { - - ObjectMethodHandler(Method method) { - super(method); + ObjectMethodHandler { + Objects.requireNonNull(method); } @Override @@ -546,43 +631,47 @@ public final class CompositeProxy { } } - private static final Map OBJECT_METHOD_DISPATCH = Map.of( - getMethod(Object.class, "toString"), - new ObjectMethodHandler(getMethod(CompositeProxyInvocationHandler.class, "objectToString", Object.class)), - getMethod(Object.class, "equals", Object.class), - new ObjectMethodHandler(getMethod(CompositeProxyInvocationHandler.class, "objectEquals", Object.class, Object.class)), - getMethod(Object.class, "hashCode"), - new ObjectMethodHandler(getMethod(System.class, "identityHashCode", Object.class)) - ); + private static final Map OBJECT_METHOD_DISPATCH; + + static { + try { + OBJECT_METHOD_DISPATCH = Map.of( + Object.class.getMethod("toString"), + new ObjectMethodHandler(CompositeProxyInvocationHandler.class.getDeclaredMethod("objectToString", Object.class)), + + Object.class.getMethod("equals", Object.class), + new ObjectMethodHandler(CompositeProxyInvocationHandler.class.getDeclaredMethod("objectIsSame", Object.class, Object.class)), + + Object.class.getMethod("hashCode"), + new ObjectMethodHandler(System.class.getMethod("identityHashCode", Object.class)) + ); + } catch (NoSuchMethodException | SecurityException ex) { + throw new InternalError(ex); + } + } } - private static HandlerOfMethod createHandlerForDefaultMethod(Method method, InvokeTunnel invokeTunnel) { + private static Handler createHandlerForDefaultMethod(Method method, InvokeTunnel invokeTunnel) { + Objects.requireNonNull(method); if (invokeTunnel != null) { - return new HandlerOfMethod(method) { - @Override - public Object invoke(Object proxy, Object[] args) throws Throwable { - return invokeTunnel.invokeDefault(proxy, this.method, args); - } + return (proxy, args) -> { + return invokeTunnel.invokeDefault(proxy, method, args); }; } else { return null; } } - private static HandlerOfMethod createHandlerForMethod(Object obj, Method method, InvokeTunnel invokeTunnel) { + private static Handler createHandlerForMethod(Object obj, Method method, InvokeTunnel invokeTunnel) { + Objects.requireNonNull(obj); + Objects.requireNonNull(method); if (invokeTunnel != null) { - return new HandlerOfMethod(method) { - @Override - public Object invoke(Object proxy, Object[] args) throws Throwable { - return invokeTunnel.invoke(obj, this.method, args); - } + return (proxy, args) -> { + return invokeTunnel.invoke(obj, method, args); }; } else { - return new HandlerOfMethod(method) { - @Override - public Object invoke(Object proxy, Object[] args) throws Throwable { - return this.method.invoke(obj, args); - } + return (proxy, args) -> { + return method.invoke(obj, args); }; } } @@ -593,37 +682,141 @@ public final class CompositeProxy { Object invoke(Object proxy, Object[] args) throws Throwable; } - private abstract static class HandlerOfMethod implements Handler { - HandlerOfMethod(Method method) { - this.method = method; + private record MethodSignature(String name, List> parameterTypes) { + MethodSignature { + Objects.requireNonNull(name); + parameterTypes.forEach(Objects::requireNonNull); } - protected final Method method; + MethodSignature(Method m) { + this(m.getName(), List.of(m.getParameterTypes())); + } } - private record ConflictResolverAdapter(BinaryOperator conflictResolver) - implements BinaryOperator { + private record FullMethodSignature(MethodSignature signature, Class returnType) { + FullMethodSignature { + Objects.requireNonNull(signature); + Objects.requireNonNull(returnType); + } - @Override - public HandlerOfMethod apply(HandlerOfMethod a, HandlerOfMethod b) { - var m = conflictResolver.apply(a.method, b.method); - if (m == a.method) { - return a; - } else if (m == b.method) { - return b; - } else { - throw new UnsupportedOperationException(); + FullMethodSignature(Method m) { + this(new MethodSignature(m), m.getReturnType()); + } + } + + /** + * Returns the standard jpackage configuration if the values of + * {@code interfaceType} and {@code slices} parameters comprise such or an empty + * {@code Optional} otherwise. + *

+ * Standard jpackage configuration is: + *

    + *
  • The proxy implements an interface comprised of two direct + * superinterfaces. + *
  • The superinterfaces are distinct, i.e. they are not superinterfaces of + * each other. + *
  • Each supplied slice implements one of the superinterfaces. + *
+ * + * @param interfaceType the interface type composite proxy instance should + * implement + * @param slices all objects passed to the calling composite proxy. The + * value is a copy of the last parameter passed in the + * {@link Builder#create(Class, Object...)} + */ + static Optional, Class>> detectJPackageConfiguration(Class interfaceType, Object... slices) { + var interfaces = interfaceType.getInterfaces(); + + if (interfaces.length != 2) { + return Optional.empty(); + } + + if (interfaces[0].isAssignableFrom(interfaces[1]) || interfaces[1].isAssignableFrom(interfaces[0])) { + return Optional.empty(); + } + + var uniqueSlices = Stream.of(slices).map(IdentityWrapper::new).distinct().toList(); + if (uniqueSlices.size() != interfaces.length) { + return Optional.empty(); + } + + Map, List>> dispatch = Stream.of(interfaces).collect(toMap(x -> x, iface -> { + return uniqueSlices.stream().filter(slice -> { + return iface.isInstance(slice.value()); + }).toList(); + })); + + return dispatch.values().stream().filter(v -> { + return v.size() == 1; + }).findFirst().map(anambiguous -> { + return dispatch.entrySet().stream().collect(toMap(e -> { + var ifaceSlices = e.getValue(); + if (ifaceSlices.size() == 1) { + return ifaceSlices.getFirst(); + } else { + if (anambiguous.size() != 1) { + throw new AssertionError(); + } + return ifaceSlices.stream().filter(Predicate.isEqual(anambiguous.getFirst()).negate()).findFirst().orElseThrow(); + } + }, Map.Entry::getKey)); + }); + } + + // jpackage-specific object conflict resolver + private static final ObjectConflictResolver JPACKAGE_OBJECT_CONFLICT_RESOLVER = (interfaceType, slices, method, candidates) -> { + return detectJPackageConfiguration(interfaceType, slices).map(dispatch -> { + // In this configuration, if one slice contains matching default method and + // another contains matching implemented method, + // the latter slice is selected as a supplier of this method for the composite proxy. + + var nonDefaultImplementations = new BitSet(candidates.length); + var defaultImplementations = new BitSet(candidates.length); + for (int i = 0; i != candidates.length; i++) { + var slice = candidates[i]; + + var limitSignatures = new Predicate() { + + @Override + public boolean test(Method m) { + return limitSignatures.contains(new MethodSignature(m)); + } + + private final Collection limitSignatures = + getProxyableMethods(dispatch.get(IdentityWrapper.wrapIdentity(slice))) + .map(MethodSignature::new) + .toList(); + }; + + int cur = i; + + getImplementerMethods(slice).filter(limitSignatures).filter(sliceMethod -> { + return signatureEquals(sliceMethod, method); + }).findFirst().ifPresent(sliceMethod -> { + if (!sliceMethod.isDefault() || + getUnfilteredImplementerMethods(slice) + .filter(limitSignatures) + .map(FullMethodSignature::new) + .anyMatch(Predicate.isEqual(new FullMethodSignature(sliceMethod)))) { + nonDefaultImplementations.set(cur); + } else { + defaultImplementations.set(cur); + } + }); } - } - } - private static final BinaryOperator STANDARD_CONFLICT_RESOLVER = (a, b) -> { - if (a.isDefault() == b.isDefault()) { - throw new IllegalArgumentException(String.format("ambiguous choice between %s and %s", a, b)); - } else if (!a.isDefault()) { - return a; - } else { - return b; - } + if (nonDefaultImplementations.cardinality() == 1) { + return candidates[nonDefaultImplementations.nextSetBit(0)]; + } else if (nonDefaultImplementations.cardinality() == 0 && defaultImplementations.cardinality() == 1) { + return candidates[defaultImplementations.nextSetBit(0)]; + } else { + throw new AssertionError(); + } + }).orElse(null); + }; + + // jpackage-specific method conflict resolver + private static final MethodConflictResolver JPACKAGE_METHOD_CONFLICT_RESOLVER = (interfaceType, slices, method, obj) -> { + return false; }; } diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/CompositeProxyTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/CompositeProxyTest.java index 1ece83be0a6..b8b1325529d 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/CompositeProxyTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/CompositeProxyTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * 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,17 +22,35 @@ */ package jdk.jpackage.internal.util; +import static jdk.jpackage.internal.util.PathUtils.mapNullablePath; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertThrowsExactly; +import static org.junit.jupiter.api.Assertions.assertTrue; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.nio.file.Path; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.function.Function; +import java.util.function.UnaryOperator; +import java.util.stream.Stream; +import jdk.jpackage.internal.util.CompositeProxy.InvokeTunnel; +import jdk.jpackage.test.JUnitUtils.StringArrayConverter; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.converter.ConvertWith; +import org.junit.jupiter.params.provider.CsvSource; import org.junit.jupiter.params.provider.ValueSource; -public class CompositeProxyTest { +class CompositeProxyTest { static interface Smalltalk { @@ -86,24 +104,24 @@ public class CompositeProxyTest { } @Test - public void testSmalltalk() { + void testSmalltalk() { var convo = CompositeProxy.create(Smalltalk.class); assertEquals("Hello", convo.sayHello()); assertEquals("Bye", convo.sayBye()); } @Test - public void testConvo() { + void testConvo() { final var otherThings = "How is your day?"; var convo = CompositeProxy.create(Convo.class, - new Smalltalk() {}, new ConvoMixin.Stub(otherThings)); + new ConvoMixin.Stub(otherThings)); assertEquals("Hello", convo.sayHello()); assertEquals("Bye", convo.sayBye()); assertEquals(otherThings, convo.sayThings()); } @Test - public void testConvoWithDuke() { + void testConvoWithDuke() { final var otherThings = "How is your day?"; var convo = CompositeProxy.create(Convo.class, new Smalltalk() { @Override @@ -116,34 +134,47 @@ public class CompositeProxyTest { assertEquals(otherThings, convo.sayThings()); } - @Test - public void testConvoWithCustomSayBye() { + @ParameterizedTest + @ValueSource(booleans = {true, false}) + void testConvoWithCustomSayBye(boolean allowUnreferencedSlices) { var mixin = new ConvoMixinWithOverrideSayBye.Stub("How is your day?", "See you"); - var convo = CompositeProxy.create(ConvoWithOverrideSayBye.class, new Smalltalk() {}, mixin); + var smalltalk = new Smalltalk() {}; - var expectedConvo = new ConvoWithOverrideSayBye() { - @Override - public String sayBye() { - return mixin.sayBye; - } + var proxyBuilder = CompositeProxy.build().allowUnreferencedSlices(allowUnreferencedSlices); - @Override - public String sayThings() { - return mixin.sayThings; - } - }; + if (!allowUnreferencedSlices) { + var ex = assertThrowsExactly(IllegalArgumentException.class, () -> { + proxyBuilder.create(ConvoWithOverrideSayBye.class, smalltalk, mixin); + }); - assertEquals(expectedConvo.sayHello(), convo.sayHello()); - assertEquals(expectedConvo.sayBye(), convo.sayBye()); - assertEquals(expectedConvo.sayThings(), convo.sayThings()); + assertEquals(String.format("Unreferenced slices: %s", List.of(smalltalk)), ex.getMessage()); + } else { + var convo = proxyBuilder.create(ConvoWithOverrideSayBye.class, smalltalk, mixin); + + var expectedConvo = new ConvoWithOverrideSayBye() { + @Override + public String sayBye() { + return mixin.sayBye; + } + + @Override + public String sayThings() { + return mixin.sayThings; + } + }; + + assertEquals(expectedConvo.sayHello(), convo.sayHello()); + assertEquals(expectedConvo.sayBye(), convo.sayBye()); + assertEquals(expectedConvo.sayThings(), convo.sayThings()); + } } @Test - public void testConvoWithCustomSayHelloAndSayBye() { + void testConvoWithCustomSayHelloAndSayBye() { var mixin = new ConvoMixinWithOverrideSayBye.Stub("How is your day?", "See you"); - var convo = CompositeProxy.create(ConvoWithDefaultSayHelloWithOverrideSayBye.class, new Smalltalk() {}, mixin); + var convo = CompositeProxy.create(ConvoWithDefaultSayHelloWithOverrideSayBye.class, mixin); var expectedConvo = new ConvoWithDefaultSayHelloWithOverrideSayBye() { @Override @@ -164,7 +195,7 @@ public class CompositeProxyTest { } @Test - public void testInherited() { + void testInherited() { interface Base { String doSome(); } @@ -193,7 +224,7 @@ public class CompositeProxyTest { } @Test - public void testNestedProxy() { + void testNestedProxy() { interface AddM { String m(); } @@ -231,7 +262,7 @@ public class CompositeProxyTest { } @Test - public void testComposite() { + void testComposite() { interface A { String sayHello(); String sayBye(); @@ -262,54 +293,13 @@ public class CompositeProxyTest { assertEquals("ciao,bye", proxy.talk()); } - @ParameterizedTest - @ValueSource(booleans = {true, false}) - public void testBasicObjectMethods(boolean withOverrides) { - interface A { - default void foo() {} + @Test + void testBasicObjectMethods() { + interface Foo { } - interface B { - default void bar() {} - } - - interface C extends A, B { - } - - final A aImpl; - final B bImpl; - - if (withOverrides) { - aImpl = new A() { - @Override - public String toString() { - return "theA"; - } - - @Override - public boolean equals(Object other) { - return true; - } - - @Override - public int hashCode() { - return 7; - } - }; - - bImpl = new B() { - @Override - public String toString() { - return "theB"; - } - }; - } else { - aImpl = new A() {}; - bImpl = new B() {}; - } - - var proxy = CompositeProxy.create(C.class, aImpl, bImpl); - var proxy2 = CompositeProxy.create(C.class, aImpl, bImpl); + var proxy = CompositeProxy.create(Foo.class); + var proxy2 = CompositeProxy.create(Foo.class); assertNotEquals(proxy.toString(), proxy2.toString()); assertNotEquals(proxy.hashCode(), proxy2.hashCode()); @@ -320,7 +310,925 @@ public class CompositeProxyTest { } @Test - public void testJavadocExample() { + void testAutoMethodConflictResolver() { + + interface A { + String getString(); + } + + interface B { + String getString(); + } + + interface AB extends A, B { + } + + var foo = new Object() { + public String getString() { + return "foo"; + } + }; + + var proxy = CompositeProxy.create(AB.class, foo); + assertEquals("foo", proxy.getString()); + } + + @Test + void testAutoMethodConflictResolver2() { + + interface A { + String getString(); + } + + interface B { + String getString(); + } + + interface AB extends A, B { + String getString(); + } + + var foo = new Object() { + public String getString() { + return "foo"; + } + }; + + var proxy = CompositeProxy.create(AB.class, foo); + assertEquals("foo", proxy.getString()); + } + + @Test + void testUnreferencedSlices() { + + interface A { + String getString(); + } + + interface B { + String getString(); + } + + interface AB extends A, B { + default String getString() { + throw new AssertionError(); + } + } + + var foo = new Object() { + public String getString() { + throw new AssertionError(); + } + }; + + var ex = assertThrowsExactly(IllegalArgumentException.class, () -> { + CompositeProxy.create(AB.class, foo); + }); + + assertEquals(String.format("Unreferenced slices: %s", List.of(foo)), ex.getMessage()); + } + + @Test + void testAutoMethodConflictResolver4() { + + interface A { + String getString(); + } + + interface B { + String getString(); + } + + interface AB extends A, B { + default String getString() { + return "AB"; + } + } + + var proxy = CompositeProxy.create(AB.class); + assertEquals("AB", proxy.getString()); + } + + @Test + void testAutoMethodConflictResolver4_1() { + + interface A { + String foo(); + String bar(); + } + + interface B { + String foo(); + String bar(); + } + + interface AB extends A, B { + default String foo() { + return "AB.foo"; + } + } + + var proxy = CompositeProxy.create(AB.class, new AB() { + @Override + public String bar() { + return "Obj.bar"; + } + }); + assertEquals("AB.foo", proxy.foo()); + assertEquals("Obj.bar", proxy.bar()); + } + + @Test + void testAutoMethodConflictResolver5() { + + interface A { + default String getString() { + throw new AssertionError(); + } + } + + interface B { + String getString(); + } + + interface AB extends A, B { + String getString(); + } + + var foo = new Object() { + public String getString() { + return "foo"; + } + }; + + var proxy = CompositeProxy.create(AB.class, foo); + assertEquals("foo", proxy.getString()); + } + + @Test + void testAutoMethodConflictResolver6() { + + interface A { + default String getString() { + return "A"; + } + } + + interface B { + String getString(); + } + + interface AB extends A, B { + default String getString() { + return A.super.getString() + "!"; + } + } + + var proxy = CompositeProxy.create(AB.class); + assertEquals("A!", proxy.getString()); + } + + @Test + void testAutoMethodConflictResolver7() { + + interface A { + String getString(); + } + + interface B extends A { + default String getString() { + return "B"; + } + } + + interface AB extends A, B { + default String getString() { + return B.super.getString() + "!"; + } + } + + var proxy = CompositeProxy.create(AB.class); + assertEquals("B!", proxy.getString()); + } + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + void testAutoMethodConflictResolver8(boolean override) { + + interface A { + String getString(); + } + + interface B extends A { + default String getString() { + return "B"; + } + } + + interface AB extends A, B { + } + + if (override) { + var foo = new Object() { + public String getString() { + return "foo"; + } + }; + + var proxy = CompositeProxy.build().methodConflictResolver((_, _, _, _) -> { + return true; + }).create(AB.class, foo); + assertEquals("foo", proxy.getString()); + } else { + var proxy = CompositeProxy.create(AB.class); + assertEquals("B", proxy.getString()); + } + } + + @Test + void testAutoMethodConflictResolver9() { + + interface A { + String getString(); + } + + interface B extends A { + default String getString() { + throw new AssertionError(); + } + } + + var foo = new Object() { + public String getString() { + return "foo"; + } + }; + + interface AB extends A, B { + String getString(); + } + + var ab = CompositeProxy.create(AB.class, foo); + assertEquals("foo", ab.getString()); + } + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + void testAutoMethodConflictResolver10(boolean override) { + + interface A { + String getString(); + } + + interface B extends A { + default String getString() { + return "B"; + } + } + + interface AB extends A, B { + String getString(); + } + + if (override) { + var foo = new B() { + @Override + public String getString() { + return B.super.getString() + "!"; + } + }; + + var proxy = CompositeProxy.create(AB.class, foo); + assertEquals("B!", proxy.getString()); + } else { + var proxy = CompositeProxy.create(AB.class, new B() {}); + assertEquals("B", proxy.getString()); + } + } + + @Test + void testAutoMethodConflictResolver11() { + + interface A { + String getString(); + } + + class Foo implements A { + @Override + public String getString() { + throw new AssertionError(); + } + } + + class Bar extends Foo { + @Override + public String getString() { + throw new AssertionError(); + } + } + + class Buz extends Bar { + @Override + public String getString() { + return "buz"; + } + } + + var proxy = CompositeProxy.create(A.class, new Buz()); + assertEquals("buz", proxy.getString()); + } + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + void testAutoMethodConflictResolver12(boolean override) { + + interface A { + String getString(); + } + + interface B { + default String getString() { + return "foo"; + } + } + + if (override) { + class BImpl implements B { + @Override + public String getString() { + return "bar"; + } + } + + var proxy = CompositeProxy.create(A.class, new BImpl() {}); + assertEquals("bar", proxy.getString()); + } else { + class BImpl implements B { + } + + var proxy = CompositeProxy.create(A.class, new BImpl() {}); + assertEquals("foo", proxy.getString()); + } + } + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + void testAutoMethodConflictResolver13(boolean override) { + + interface A { + String getString(); + } + + interface Foo { + default String getString() { + return "foo"; + } + } + + if (override) { + class B { + public String getString() { + return "B"; + } + } + + class C extends B implements Foo { + } + + for (var slice : List.of(new C(), new C() {})) { + var proxy = CompositeProxy.create(A.class, slice); + assertEquals("B", proxy.getString()); + } + + var proxy = CompositeProxy.create(A.class, new C() { + @Override + public String getString() { + return "C"; + } + }); + assertEquals("C", proxy.getString()); + } else { + class B { + } + + class C extends B implements Foo { + } + + for (var slice : List.of(new C(), new C() {})) { + var proxy = CompositeProxy.create(A.class, slice); + assertEquals("foo", proxy.getString()); + } + } + } + + @Test + void testAutoMethodConflictResolver14() { + + interface Launcher { + + String name(); + + Map extraAppImageFileData(); + + record Stub(String name, Map extraAppImageFileData) implements Launcher {} + } + + interface WinLauncherMixin { + + boolean shortcut(); + + record Stub(boolean shortcut) implements WinLauncherMixin {} + } + + interface WinLauncher extends Launcher, WinLauncherMixin { + + default Map extraAppImageFileData() { + return Map.of("shortcut", Boolean.toString(shortcut())); + } + } + + var proxy = CompositeProxy.create(WinLauncher.class, new Launcher.Stub("foo", Map.of()), new WinLauncherMixin.Stub(true)); + + assertEquals("foo", proxy.name()); + assertEquals(Map.of("shortcut", "true"), proxy.extraAppImageFileData()); + } + + @ParameterizedTest + @CsvSource({ + "a,b", + "b,a", + }) + void testObjectConflictResolver(String fooResolve, String barResolve) { + + interface I { + String foo(); + String bar(); + } + + var a = new I() { + @Override + public String foo() { + return "a-foo"; + } + + @Override + public String bar() { + return "a-bar"; + } + }; + + var b = new Object() { + public String foo() { + return "b-foo"; + } + + public String bar() { + return "b-bar"; + } + }; + + Function resolver = tag -> { + return switch (tag) { + case "a" -> a; + case "b" -> b; + default -> { + throw new AssertionError(); + } + }; + }; + + var proxy = CompositeProxy.build().objectConflictResolver((_, _, method, _) -> { + return switch (method.getName()) { + case "foo" -> resolver.apply(fooResolve); + case "bar" -> resolver.apply(barResolve); + default -> { + throw new AssertionError(); + } + }; + }).create(I.class, a, b); + + assertEquals(fooResolve + "-foo", proxy.foo()); + assertEquals(barResolve + "-bar", proxy.bar()); + } + + @Test + void testObjectConflictResolverInvalid() { + + interface I { + String foo(); + } + + var a = new I() { + @Override + public String foo() { + throw new AssertionError(); + } + }; + + var b = new Object() { + public String foo() { + throw new AssertionError(); + } + }; + + assertThrowsExactly(UnsupportedOperationException.class, () -> { + CompositeProxy.build().objectConflictResolver((_, _, _, _) -> { + return new Object(); + }).create(I.class, a, b); + }); + } + + @ParameterizedTest + @ValueSource( strings = { + "no-foo", + "private-foo", + "protected-foo", + "package-foo", + "static-foo", + "static-foo,private-foo,no-foo", + }) + void testMissingImplementer(@ConvertWith(StringArrayConverter.class) String[] slicesSpec) throws NoSuchMethodException, SecurityException { + + interface A { + void foo(); + } + + var slices = Stream.of(slicesSpec).map(slice -> { + return switch (slice) { + case "no-foo" -> new Object(); + case "private-foo" -> new Object() { + private void foo() { + throw new AssertionError(); + } + }; + case "protected-foo" -> new Object() { + protected void foo() { + throw new AssertionError(); + } + }; + case "package-foo" -> new Object() { + void foo() { + throw new AssertionError(); + } + }; + case "static-foo" -> new Object() { + public static void foo() { + throw new AssertionError(); + } + }; + default -> { throw new AssertionError(); } + }; + }).toList(); + + var ex = assertThrowsExactly(IllegalArgumentException.class, () -> { + CompositeProxy.create(A.class, slices.toArray()); + }); + + assertEquals(String.format("None of the slices can handle %s", A.class.getMethod("foo")), ex.getMessage()); + } + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + void testUnusedSlice(boolean all) { + + interface A { + default void foo() { + throw new AssertionError(); + } + } + + A a = new A() {}; + var obj = new Object(); + + if (all) { + var messages = Set.of( + String.format("Unreferenced slices: %s", List.of(a, obj)), + String.format("Unreferenced slices: %s", List.of(obj, a)) + ); + + var ex = assertThrowsExactly(IllegalArgumentException.class, () -> { + CompositeProxy.create(A.class, a, obj); + }); + + assertTrue(messages.contains(ex.getMessage())); + } else { + interface B extends A { + void foo(); + } + + var ex = assertThrowsExactly(IllegalArgumentException.class, () -> { + CompositeProxy.create(B.class, a, obj); + }); + + assertEquals(String.format("Unreferenced slices: %s", List.of(obj)), ex.getMessage()); + } + } + + @ParameterizedTest + @CsvSource({ + "'a,b,a',false", + "'a,b,a',true", + "'a,b',true", + "'b,a',true", + "'a,b',false", + "'b,a',false", + }) + void testAmbiguousImplementers( + @ConvertWith(StringArrayConverter.class) String[] slicesSpec, + boolean withObjectConflictResolver) throws NoSuchMethodException, SecurityException { + + interface A { + String foo(); + String bar(); + } + + var a = new Object() { + public String foo() { + return "a-foo"; + } + public String bar() { + throw new AssertionError(); + } + }; + + var b = new Object() { + public String bar() { + return "b-bar"; + } + }; + + var ambiguousMethod = A.class.getMethod("bar"); + + var slices = Stream.of(slicesSpec).map(slice -> { + return switch (slice) { + case "a" -> a; + case "b" -> b; + default -> { throw new AssertionError(); } + }; + }).toArray(); + + if (withObjectConflictResolver) { + var proxy = CompositeProxy.build().objectConflictResolver((_, _, _, _) -> { + return b; + }).create(A.class, slices); + + assertEquals("a-foo", proxy.foo()); + assertEquals("b-bar", proxy.bar()); + } else { + var ex = assertThrowsExactly(IllegalArgumentException.class, () -> { + CompositeProxy.create(A.class, slices); + }); + + var messages = Set.of( + String.format("Ambiguous choice between %s for %s", List.of(a, b), ambiguousMethod), + String.format("Ambiguous choice between %s for %s", List.of(b, a), ambiguousMethod) + ); + + assertTrue(messages.contains(ex.getMessage())); + } + } + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + void testDifferentReturnTypes(boolean compatible) { + + interface A { + Number foo(); + } + + Object obj; + if (compatible) { + obj = new Object() { + public Integer foo() { + return 123; + } + }; + } else { + obj = new Object() { + public String foo() { + return "123"; + } + }; + } + + var proxy = CompositeProxy.create(A.class, obj); + + if (compatible) { + assertEquals(123, proxy.foo()); + } else { + assertThrows(ClassCastException.class, proxy::foo); + } + } + + @Test + void testCovariantReturnType() { + + interface A { + Number foo(); + } + + interface Mixin { + String bar(); + } + + interface AWithMixin extends A, Mixin { + Integer foo(); + } + + var proxy = CompositeProxy.create(AWithMixin.class, new A() { + @Override + public Number foo() { + return 123; + } + }, new Mixin() { + @Override + public String bar() { + return "bar"; + } + }); + + assertEquals(123, proxy.foo()); + assertEquals("bar", proxy.bar()); + } + + @Test + void testNotInterface() { + var ex = assertThrowsExactly(IllegalArgumentException.class, () -> { + CompositeProxy.create(Integer.class); + }); + + assertEquals(String.format("Type %s must be an interface", Integer.class.getName()), ex.getMessage()); + } + + @Test + void testExcessiveInterfaces() { + + interface Launcher { + String name(); + + default String executableResource() { + return "jpackageapplauncher"; + } + + record Stub(String name) implements Launcher { + } + } + + interface WinLauncherMixin { + String version(); + + record Stub(String version) implements WinLauncherMixin { + } + } + + interface WinLauncher extends Launcher, WinLauncherMixin { + + default String executableResource() { + return "jpackageapplauncher.exe"; + } + } + + var winLauncher = CompositeProxy.create(WinLauncher.class, new Launcher.Stub("foo"), new WinLauncherMixin.Stub("1.0")); + + var winLauncher2 = CompositeProxy.create(WinLauncher.class, new Launcher.Stub("bar"), winLauncher); + + assertEquals("foo", winLauncher.name()); + assertEquals("1.0", winLauncher.version()); + assertEquals("jpackageapplauncher.exe", winLauncher.executableResource()); + + assertEquals("bar", winLauncher2.name()); + assertEquals("1.0", winLauncher2.version()); + assertEquals("jpackageapplauncher.exe", winLauncher2.executableResource()); + } + + @Test + void testInvokeTunnel() { + + interface A { + default String foo() { + return "foo"; + } + String bar(); + } + + var obj = new Object() { + public String bar() { + return "bar"; + } + }; + + Slot invokeCalled = Slot.createEmpty(); + invokeCalled.set(false); + + Slot invokeDefaultCalled = Slot.createEmpty(); + invokeDefaultCalled.set(false); + + var proxy = CompositeProxy.build().invokeTunnel(new InvokeTunnel() { + + @Override + public Object invoke(Object obj, Method method, Object[] args) throws Throwable { + invokeCalled.set(true); + return method.invoke(obj, args); + } + + @Override + public Object invokeDefault(Object proxy, Method method, Object[] args) throws Throwable { + invokeDefaultCalled.set(true); + return InvocationHandler.invokeDefault(proxy, method, args); + } + + }).create(A.class, obj); + + assertFalse(invokeCalled.get()); + assertFalse(invokeDefaultCalled.get()); + assertEquals("foo", proxy.foo()); + assertFalse(invokeCalled.get()); + assertTrue(invokeDefaultCalled.get()); + + invokeDefaultCalled.set(false); + assertEquals("bar", proxy.bar()); + assertTrue(invokeCalled.get()); + assertFalse(invokeDefaultCalled.get()); + } + + @Test + void testDefaultOverride() { + + interface AppImageLayout { + + Path runtimeDirectory(); + + Path rootDirectory(); + + default boolean isResolved() { + return !rootDirectory().equals(Path.of("")); + } + + default AppImageLayout unresolve() { + if (isResolved()) { + final var root = rootDirectory(); + return map(root::relativize); + } else { + return this; + } + } + + AppImageLayout map(UnaryOperator mapper); + + record Stub(Path rootDirectory, Path runtimeDirectory) implements AppImageLayout { + + public Stub { + Objects.requireNonNull(rootDirectory); + } + + public Stub(Path runtimeDirectory) { + this(Path.of(""), runtimeDirectory); + } + + @Override + public AppImageLayout map(UnaryOperator mapper) { + return new Stub(mapNullablePath(mapper, rootDirectory), mapNullablePath(mapper, runtimeDirectory)); + } + } + } + + interface ApplicationLayoutMixin { + + Path appDirectory(); + + record Stub(Path appDirectory) implements ApplicationLayoutMixin { + } + } + + interface ApplicationLayout extends AppImageLayout, ApplicationLayoutMixin { + + @Override + default ApplicationLayout unresolve() { + return (ApplicationLayout)AppImageLayout.super.unresolve(); + } + + @Override + default ApplicationLayout map(UnaryOperator mapper) { + return CompositeProxy.create(ApplicationLayout.class, + new AppImageLayout.Stub(rootDirectory(), runtimeDirectory()).map(mapper), + new ApplicationLayoutMixin.Stub(mapper.apply(appDirectory()))); + } + } + + var proxy = CompositeProxy.create(ApplicationLayout.class, + new AppImageLayout.Stub(Path.of(""), Path.of("runtime")), + new ApplicationLayoutMixin.Stub(Path.of("app"))); + + assertSame(proxy, proxy.unresolve()); + + var mapped = proxy.map(Path.of("a")::resolve); + assertEquals(Path.of("a"), mapped.rootDirectory()); + assertEquals(Path.of("a/runtime"), mapped.runtimeDirectory()); + assertEquals(Path.of("a/app"), mapped.appDirectory()); + } + + @Test + void testJavadocExample() { interface Sailboat { default void trimSails() {} } @@ -364,9 +1272,9 @@ public class CompositeProxyTest { } }; - Sloop sloop = CompositeProxy.create(Sloop.class, new Sailboat() {}, withMain, withJib); + Sloop sloop = CompositeProxy.create(Sloop.class, withMain, withJib); - Catboat catboat = CompositeProxy.create(Catboat.class, new Sailboat() {}, withMain); + Catboat catboat = CompositeProxy.create(Catboat.class, withMain); sloop.trimSails(); catboat.trimSails(); diff --git a/test/jdk/tools/jpackage/junit/tools/jdk/jpackage/test/JUnitUtils.java b/test/jdk/tools/jpackage/junit/tools/jdk/jpackage/test/JUnitUtils.java index 530a0d5cb1f..97041ea1a0e 100644 --- a/test/jdk/tools/jpackage/junit/tools/jdk/jpackage/test/JUnitUtils.java +++ b/test/jdk/tools/jpackage/junit/tools/jdk/jpackage/test/JUnitUtils.java @@ -27,6 +27,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import java.util.Map; import java.util.Objects; import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.params.converter.SimpleArgumentConverter; public final class JUnitUtils { @@ -121,6 +122,19 @@ public final class JUnitUtils { } + public static class StringArrayConverter extends SimpleArgumentConverter { + + @Override + protected Object convert(Object source, Class targetType) { + if (source instanceof String && String[].class.isAssignableFrom(targetType)) { + return ((String) source).split("\\s*,\\s*"); + } else { + throw new IllegalArgumentException(); + } + } + } + + private static final class ExceptionCauseRemover extends Exception { ExceptionCauseRemover(Exception ex) { From e893f4cf8465bf428b49191158c80060932215fc Mon Sep 17 00:00:00 2001 From: Alan Bateman Date: Sat, 11 Apr 2026 04:49:31 +0000 Subject: [PATCH 246/359] 8196182: ServiceLoader.iterator().hasNext()/.next() may throw a LinkageError 8350481: ServiceLoader throws NCDEF instead of ServiceConfigurationError Reviewed-by: liach, jpai --- .../classes/java/util/ServiceLoader.java | 10 +- .../util/ServiceLoader/LinkageErrorsTest.java | 214 ++++++++++++++++++ .../MalformedAnnotationProcessorTests.java | 10 +- 3 files changed, 224 insertions(+), 10 deletions(-) create mode 100644 test/jdk/java/util/ServiceLoader/LinkageErrorsTest.java diff --git a/src/java.base/share/classes/java/util/ServiceLoader.java b/src/java.base/share/classes/java/util/ServiceLoader.java index 5137adc1c08..5e4fa4ed2ef 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, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -621,9 +621,9 @@ public final class ServiceLoader Constructor ctor = null; try { ctor = clazz.getConstructor(); - } catch (NoSuchMethodException ex) { + } catch (NoSuchMethodException | LinkageError e) { String cn = clazz.getName(); - fail(service, cn + " Unable to get public no-arg constructor", ex); + fail(service, cn + " Unable to get public no-arg constructor", e); } if (inExplicitModule(clazz)) ctor.setAccessible(true); @@ -1086,8 +1086,8 @@ public final class ServiceLoader String cn = pending.next(); try { return Class.forName(cn, false, loader); - } catch (ClassNotFoundException x) { - fail(service, "Provider " + cn + " not found"); + } catch (ClassNotFoundException | LinkageError e) { + fail(service, "Provider " + cn + " not found", e); return null; } } diff --git a/test/jdk/java/util/ServiceLoader/LinkageErrorsTest.java b/test/jdk/java/util/ServiceLoader/LinkageErrorsTest.java new file mode 100644 index 00000000000..209dce75267 --- /dev/null +++ b/test/jdk/java/util/ServiceLoader/LinkageErrorsTest.java @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8196182 8350481 + * @summary Test ServiceLoader iterating over service providers when linkage error is thrown + * @library /test/lib + * @run junit/othervm ${test.main.class} + */ + +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Iterator; +import java.util.Map; +import java.util.ServiceConfigurationError; +import java.util.ServiceLoader; +import java.util.function.Consumer; +import java.util.function.Predicate; +import jdk.test.lib.compiler.InMemoryJavaCompiler; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + +class LinkageErrorsTest { + + /** + * Test iteration over service providers when loading a service provider class + * fails with a linkage error. + */ + @Test + void testLoadClassThrows() throws Exception { + Map sources = Map.of( + "Service", + """ + public interface Service {} + """, + "Super", + """ + class Super {} + """, + "Provider1", + """ + public class Provider1 implements Service { + public Provider1() {} + } + """, + "Provider2", + """ + public class Provider2 extends Super implements Service { + public Provider2() {} + } + """ + ); + Path classesDir = compile(sources); + + // delete Provider2's super class to prevent Provider2 from loading + Files.delete(classesDir.resolve("Super.class")); + + // create services configuration file that lists two providers + createServicesConfigFile(classesDir, "Service", "Provider1", "Provider2"); + + // load the service interface + var loader = new URLClassLoader(new URL[] { classesDir.toUri().toURL() }); + Class service = loader.loadClass("Service"); + assertSame(loader, service.getClassLoader()); + + // find and collect all service providers and ServiceConfigurationErrors + var providers = new ArrayList(); + var errors = new ArrayList(); + forEachProvider(loader, service, providers::add, errors::add); + + // Provider1 should be found + assertEquals(1, providers.size()); + assertEquals("Provider1", providers.get(0).getClass().getName()); + + // loading Provider2 expected to fail with LinkageError + assertEquals(1, errors.size()); + assertInstanceOf(LinkageError.class, errors.get(0).getCause()); + } + + /** + * Test iteration over service providers when finding the public no-arg constructor + * of a provider fails with a linkage error. + */ + @Test + void testFindConstructorThrows() throws Exception { + Map sources = Map.of( + "Service", + """ + public interface Service {} + """, + "Param", + """ + class Param {} + """, + "Provider1", + """ + public class Provider1 implements Service { + public Provider1() {} + } + """, + "Provider2", + """ + public class Provider2 implements Service { + public Provider2() {} + public Provider2(Param p) { } + } + """ + ); + Path classesDir = compile(sources); + + // delete the class file for the parameter of Provider's 1-param ctor + Files.delete(classesDir.resolve("Param.class")); + + // create services configuration file that lists two providers + createServicesConfigFile(classesDir, "Service", "Provider1", "Provider2"); + + // load the service interface + var loader = new URLClassLoader(new URL[] { classesDir.toUri().toURL() }); + Class service = loader.loadClass("Service"); + assertSame(loader, service.getClassLoader()); + + // find and collect all service providers and ServiceConfigurationErrors + var providers = new ArrayList(); + var errors = new ArrayList(); + forEachProvider(loader, service, providers::add, errors::add); + + // Provider1 should be found + assertEquals(1, providers.size()); + assertEquals("Provider1", providers.get(0).getClass().getName()); + + // loading Provider2 expected to fail with LinkageError + assertEquals(1, errors.size()); + assertInstanceOf(LinkageError.class, errors.get(0).getCause()); + } + + /** + * Compile the given java source files to a temporary directory. + */ + private Path compile(Map sources) throws IOException { + Map classes = InMemoryJavaCompiler.compile(sources); + Path dir = Files.createTempDirectory(Path.of("."), "classes"); + for (String cn : classes.keySet()) { + Path file = dir.resolve(cn.replace('.', File.separatorChar) + ".class"); + Files.createDirectories(file.getParent()); + Files.write(file, classes.get(cn)); + } + return dir; + } + + /** + * Create services configuration file for the given service and providers. + */ + private void createServicesConfigFile(Path dir, + String serviceName, + String... providerNames) throws IOException { + Path configFile = dir.resolve("META-INF", "services", serviceName); + Files.createDirectories(configFile.getParent()); + Files.write(configFile, Arrays.asList(providerNames)); + } + + /** + * Uses ServiceLoader to iterate over all service providers of the given service, + * invoking {@code providerConsumer} for each provider instantiated, and + * {@code errorConsumer} for each ServiceConfigurationError encountered. + */ + private void forEachProvider(ClassLoader loader, + Class service, + Consumer providerConsumer, + Consumer errorConsumer) { + Iterator iterator = ServiceLoader.load(service, loader).iterator(); + boolean done = false; + while (!done) { + try { + if (iterator.hasNext()) { + T provider = iterator.next(); + providerConsumer.accept(provider); + } else { + done = true; + } + } catch (ServiceConfigurationError e) { + errorConsumer.accept(e); + } + } + } +} diff --git a/test/langtools/tools/javac/annotations/8218152/MalformedAnnotationProcessorTests.java b/test/langtools/tools/javac/annotations/8218152/MalformedAnnotationProcessorTests.java index 68e4aea0ab2..85095cc5537 100644 --- a/test/langtools/tools/javac/annotations/8218152/MalformedAnnotationProcessorTests.java +++ b/test/langtools/tools/javac/annotations/8218152/MalformedAnnotationProcessorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * 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,8 +91,8 @@ public class MalformedAnnotationProcessorTests extends TestRunner{ .getOutputLines(Task.OutputKind.DIRECT); System.out.println(actualErrors.get(0)); - if (!actualErrors.get(0).contains("- compiler.err.proc.cant.load.class: " + - "Incompatible magic value")) { + if (!actualErrors.get(0).contains("- compiler.err.proc.bad.config.file: " + + "javax.annotation.processing.Processor: Provider BadAnnoProcessor not found")) { throw new AssertionError("Unexpected errors reported: " + actualErrors); } } @@ -162,8 +162,8 @@ public class MalformedAnnotationProcessorTests extends TestRunner{ .writeAll() .getOutputLines(Task.OutputKind.DIRECT); - if (!actualErrors.get(0).contains("- compiler.err.proc.cant.load.class: " + - "WrongClassFileVersion has been compiled by a more recent version")) { + if (!actualErrors.get(0).contains("- compiler.err.proc.bad.config.file: " + + "javax.annotation.processing.Processor: Provider WrongClassFileVersion not found")) { throw new AssertionError("Unexpected errors reported: " + actualErrors); } } From e7da7376cd5299df3c70bdd3e47d62e75b9a3ae7 Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Sat, 11 Apr 2026 05:30:38 +0000 Subject: [PATCH 247/359] 8370648: TestOldGrowthTriggers.java fails 'Trigger (Old): Old has overgrown' missing from stdout/stderr Reviewed-by: xpeng, wkemper, kdnilsen, ysr --- .../generational/TestOldGrowthTriggers.java | 58 +++++++++++-------- 1 file changed, 33 insertions(+), 25 deletions(-) diff --git a/test/hotspot/jtreg/gc/shenandoah/generational/TestOldGrowthTriggers.java b/test/hotspot/jtreg/gc/shenandoah/generational/TestOldGrowthTriggers.java index 7af81fabe13..2af784fd034 100644 --- a/test/hotspot/jtreg/gc/shenandoah/generational/TestOldGrowthTriggers.java +++ b/test/hotspot/jtreg/gc/shenandoah/generational/TestOldGrowthTriggers.java @@ -1,5 +1,6 @@ /* * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. * 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,15 +26,14 @@ /* * @test id=generational * @summary Test that growth of old-gen triggers old-gen marking - * @key intermittent * @requires vm.gc.Shenandoah * @requires vm.flagless * @library /test/lib * @run driver TestOldGrowthTriggers */ -import java.util.*; -import java.math.BigInteger; +import java.util.Arrays; +import java.util.BitSet; import jdk.test.lib.process.ProcessTools; import jdk.test.lib.process.OutputAnalyzer; @@ -41,36 +41,40 @@ import jdk.test.lib.process.OutputAnalyzer; public class TestOldGrowthTriggers { public static void makeOldAllocations() { - // Expect most of the BigInteger entries placed into array to be promoted, and most will eventually become garbage within old + // Expect most of the BitSet entries placed into array to be promoted, and most will eventually become garbage within old - final int ArraySize = 512 * 1024; // 512K entries - final int BitsInBigInteger = 128; - final int RefillIterations = 64; - BigInteger array[] = new BigInteger[ArraySize]; - Random r = new Random(46); + final int ArraySize = 1024; // 1K entries + final int RefillIterations = 128; + BitSet[] array = new BitSet[ArraySize]; for (int i = 0; i < ArraySize; i++) { - array[i] = new BigInteger(BitsInBigInteger, r); + array[i] = new BitSet(256 * 1024); } for (int refillCount = 0; refillCount < RefillIterations; refillCount++) { - // Each refill repopulates ArraySize randomly selected elements within array - for (int i = 0; i < ArraySize; i++) { - int replaceIndex = r.nextInt(ArraySize); - int deriveIndex = r.nextInt(ArraySize); + // Each refill repopulates ArraySize + for (int i = 1; i < ArraySize; i++) { + int replaceIndex = i; + int deriveIndex = i-1; + switch (i & 0x7) { - case 0,1,2: - // creates new old BigInteger, releases old BigInteger, - // may create ephemeral data while computing gcd - array[replaceIndex] = array[replaceIndex].gcd(array[deriveIndex]); - break; - case 3,4: - // creates new old BigInteger, releases old BigInteger - array[replaceIndex] = array[replaceIndex].multiply(array[deriveIndex]); - break; - case 5,6,7: + case 0,1,2 -> { + // creates new BitSet, releases old BitSet, + // create ephemeral data while computing + BitSet result = (BitSet) array[deriveIndex].clone(); + for (int j=0; j<10; j++) { + result = (BitSet) array[deriveIndex].clone(); + } + array[replaceIndex] = result; + } + case 3,4 -> { + // creates new BitSet, releases old BitSet + BitSet result = (BitSet) array[deriveIndex].clone(); + array[replaceIndex] = result; + } + case 5,6,7 -> { // do nothing, let all objects in the array age to increase pressure on old generation - break; + } } } } @@ -93,6 +97,8 @@ public class TestOldGrowthTriggers { } testOld("-Xlog:gc", + "-XX:ConcGCThreads=1", + "-XX:ParallelGCThreads=1", "-Xms96m", "-Xmx96m", "-XX:+UnlockDiagnosticVMOptions", @@ -108,6 +114,8 @@ public class TestOldGrowthTriggers { ); testOld("-Xlog:gc", + "-XX:ConcGCThreads=1", + "-XX:ParallelGCThreads=1", "-Xms96m", "-Xmx96m", "-XX:+UnlockDiagnosticVMOptions", From 1e2b0d2b67c7ae0843c9adbc641471040fbe7d71 Mon Sep 17 00:00:00 2001 From: Arno Zeller Date: Sat, 11 Apr 2026 19:42:35 +0000 Subject: [PATCH 248/359] 8382018: test/jdk/java/nio/file/spi/SetDefaultProvider.java leaves a directory in /tmp Reviewed-by: alanb, mbaesken --- test/jdk/java/nio/file/spi/testapp/testapp/Main.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/jdk/java/nio/file/spi/testapp/testapp/Main.java b/test/jdk/java/nio/file/spi/testapp/testapp/Main.java index 6f61d431707..5a48ff47384 100644 --- a/test/jdk/java/nio/file/spi/testapp/testapp/Main.java +++ b/test/jdk/java/nio/file/spi/testapp/testapp/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ public class Main { throw new RuntimeException("FileSystemProvider not overridden"); // exercise the file system - Path dir = Files.createTempDirectory("tmp"); + Path dir = Files.createTempDirectory(Path.of(""), "tmp"); if (dir.getFileSystem() != fs) throw new RuntimeException("'dir' not in default file system"); System.out.println("created: " + dir); From fb2460663c68dc909107b3bb39d322db2038ae79 Mon Sep 17 00:00:00 2001 From: Daniel Gredler Date: Sun, 12 Apr 2026 23:16:05 +0000 Subject: [PATCH 249/359] 8381623: Additional immutability in sun.font: ExtendedTextSourceLabel, GlyphLayout Reviewed-by: serb, prr --- .../sun/font/ExtendedTextSourceLabel.java | 39 +++++++------------ .../share/classes/sun/font/GlyphLayout.java | 8 ++-- 2 files changed, 17 insertions(+), 30 deletions(-) diff --git a/src/java.desktop/share/classes/sun/font/ExtendedTextSourceLabel.java b/src/java.desktop/share/classes/sun/font/ExtendedTextSourceLabel.java index f3569941321..78ae70629b6 100644 --- a/src/java.desktop/share/classes/sun/font/ExtendedTextSourceLabel.java +++ b/src/java.desktop/share/classes/sun/font/ExtendedTextSourceLabel.java @@ -57,15 +57,16 @@ import java.util.Map; * Align bounds is a rect that defines how to align this to margins. * it generally allows some overhang that logical bounds would prevent. */ -class ExtendedTextSourceLabel implements TextLineComponent, Decoration.Label { +final class ExtendedTextSourceLabel implements TextLineComponent, Decoration.Label { private final TextSource source; private final Decoration decorator; // caches - private Font font; - private AffineTransform baseTX; - private CoreMetrics cm; + private final Font font; + private final AffineTransform baseTX; + private final CoreMetrics cm; + private final float advTracking; private Rectangle2D lb; private Rectangle2D ab; @@ -74,34 +75,18 @@ class ExtendedTextSourceLabel implements TextLineComponent, Decoration.Label { private StandardGlyphVector gv; private float[] charinfo; - private float advTracking; - /** * Create from a TextSource. */ public ExtendedTextSourceLabel(TextSource source, Decoration decorator) { this.source = source; this.decorator = decorator; - finishInit(); - } - - /** - * Create from a TextSource, optionally using cached data from oldLabel starting at the offset. - * If present oldLabel must have been created from a run of text that includes the text used in - * the new label. Start in source corresponds to logical character offset in oldLabel. - */ - public ExtendedTextSourceLabel(TextSource source, ExtendedTextSourceLabel oldLabel, int offset) { - // currently no optimization. - this.source = source; - this.decorator = oldLabel.decorator; - finishInit(); - } - - private void finishInit() { - font = source.getFont(); + Font font = source.getFont(); Map atts = font.getAttributes(); - baseTX = AttributeValues.getBaselineTransform(atts); + AffineTransform baseTX = AttributeValues.getBaselineTransform(atts); + + CoreMetrics cm; if (baseTX == null){ cm = source.getCoreMetrics(); } else { @@ -110,13 +95,15 @@ class ExtendedTextSourceLabel implements TextLineComponent, Decoration.Label { charTX = new AffineTransform(); } font = font.deriveFont(charTX); - LineMetrics lm = font.getLineMetrics(source.getChars(), source.getStart(), source.getStart() + source.getLength(), source.getFRC()); cm = CoreMetrics.get(lm); } - advTracking = font.getSize() * AttributeValues.getTracking(atts); + this.font = font; + this.baseTX = baseTX; + this.cm = cm; + this.advTracking = font.getSize() * AttributeValues.getTracking(atts); } /** diff --git a/src/java.desktop/share/classes/sun/font/GlyphLayout.java b/src/java.desktop/share/classes/sun/font/GlyphLayout.java index 5bff127f143..851201fe347 100644 --- a/src/java.desktop/share/classes/sun/font/GlyphLayout.java +++ b/src/java.desktop/share/classes/sun/font/GlyphLayout.java @@ -125,10 +125,10 @@ public final class GlyphLayout { } private static final class SDCache { - public AffineTransform dtx; - public AffineTransform gtx; - public Point2D.Float delta; - public FontStrikeDesc sd; + private final AffineTransform dtx; + private final AffineTransform gtx; + private final Point2D.Float delta; + private final FontStrikeDesc sd; private SDCache(Font font, FontRenderContext frc) { // !!! add getVectorTransform and hasVectorTransform to frc? then From d75bb86ca69d5b547c4f46217387849333afa1f3 Mon Sep 17 00:00:00 2001 From: Arno Zeller Date: Mon, 13 Apr 2026 05:36:15 +0000 Subject: [PATCH 250/359] 8380896: Reduce runtime for MonitorVmStartTerminate.java on hosts with a lot of VMs Reviewed-by: lmesnik, sspitsyn --- .../MonitoredVm/MonitorVmStartTerminate.java | 36 +++++++++++-------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/test/jdk/sun/jvmstat/monitor/MonitoredVm/MonitorVmStartTerminate.java b/test/jdk/sun/jvmstat/monitor/MonitoredVm/MonitorVmStartTerminate.java index 88f1ed22e35..f436bd32e1b 100644 --- a/test/jdk/sun/jvmstat/monitor/MonitoredVm/MonitorVmStartTerminate.java +++ b/test/jdk/sun/jvmstat/monitor/MonitoredVm/MonitorVmStartTerminate.java @@ -148,8 +148,17 @@ public final class MonitorVmStartTerminate { } private void releaseStarted(Integer id) { + String monitoredArgs = readMainArgs(id); + if (monitoredArgs == null || monitoredArgs.equals("Unknown")) { + System.out.println("releaseStarted: not a test pid: " + id); + return; + } + for (JavaProcess jp : processes) { - if (hasMainArgs(id, jp.getMainArgsIdentifier())) { + if (jp.getId() != null) { + continue; + } + if (monitoredArgs.contains(jp.getMainArgsIdentifier())) { // store id for terminated identification jp.setId(id); System.out.println("RELEASED started (id=" + jp.getId() + ", args=" + jp.getMainArgsIdentifier() + ")"); @@ -177,40 +186,39 @@ public final class MonitorVmStartTerminate { } } - private boolean hasMainArgs(Integer id, String args) { - VmIdentifier vmid = null; + private String readMainArgs(Integer id) { + VmIdentifier vmid; try { vmid = new VmIdentifier("//" + id.intValue()); } catch (URISyntaxException e) { - System.out.println("hasMainArgs(" + id + "): " + e); - return false; + System.out.println("readMainArgs(" + id + "): " + e); + return null; } - // Retry a failing attempt to check arguments for a match, + // Retry a failing attempt to read arguments, // as not recognizing a test process will cause timeout and failure. for (int i = 0; i < ARGS_ATTEMPTS; i++) { try { MonitoredVm target = host.getMonitoredVm(vmid); String monitoredArgs = MonitoredVmUtil.mainArgs(target); - System.out.println("hasMainArgs(" + id + "): has main args: '" + monitoredArgs + "'"); + System.out.println("readMainArgs(" + id + "): has main args: '" + monitoredArgs + "'"); if (monitoredArgs == null || monitoredArgs.equals("Unknown")) { - System.out.println("hasMainArgs(" + id + "): retry" ); + System.out.println("readMainArgs(" + id + "): retry"); takeNap(); continue; - } else if (monitoredArgs.contains(args)) { - return true; } else { - return false; + return monitoredArgs; } } catch (MonitorException e) { // Process probably not running or not ours, e.g. // sun.jvmstat.monitor.MonitorException: Could not attach to PID // Only log if something else, to avoid filling log: - if (!e.getMessage().contains("Could not attach")) { - System.out.println("hasMainArgs(" + id + "): " + e); + String message = e.getMessage(); + if (message == null || !message.contains("Could not attach")) { + System.out.println("readMainArgs(" + id + "): " + e); } } } - return false; + return null; } } From 6371da9a44bf1feb487ed6bea67bddd3344d9aee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Walln=C3=B6fer?= Date: Mon, 13 Apr 2026 06:14:13 +0000 Subject: [PATCH 251/359] 8378228: Replace jQuery UI autocomplete component in JavaDoc search Reviewed-by: nbenalla --- .../doclets/formats/html/HtmlDoclet.java | 13 +- .../doclets/formats/html/HtmlIds.java | 7 +- .../doclets/formats/html/Navigation.java | 40 +- .../doclets/formats/html/SearchWriter.java | 14 +- .../doclets/formats/html/markup/Head.java | 9 +- .../formats/html/markup/HtmlStyles.java | 12 +- .../html/resources/jquery/jquery-3.7.1.js | 10716 ---------------- .../html/resources/jquery/jquery-3.7.1.min.js | 2 - .../html/resources/jquery/jquery-ui.css | 148 - .../html/resources/jquery/jquery-ui.js | 2653 ---- .../html/resources/jquery/jquery-ui.min.css | 6 - .../html/resources/jquery/jquery-ui.min.js | 6 - .../formats/html/resources/script.js.template | 16 +- .../formats/html/resources/search-page.js | 348 - .../formats/html/resources/search.js.template | 603 +- .../formats/html/resources/stylesheet.css | 280 +- .../toolkit/resources/doclets.properties | 11 +- .../doclets/toolkit/util/DocPaths.java | 21 +- src/jdk.javadoc/share/legal/jquery.md | 26 - src/jdk.javadoc/share/legal/jqueryUI.md | 49 - .../CheckLibraryVersions.java | 6 +- .../CheckStylesheetClasses.java | 15 +- .../javadoc/doclet/testFonts/TestFonts.java | 3 +- .../testPassthruFiles/TestPassThruFiles.java | 10 +- .../javadoc/doclet/testSearch/TestSearch.java | 53 +- .../doclet/testStylesheet/TestStylesheet.java | 3 +- .../jdk/javadoc/tool/api/basic/APITest.java | 9 +- 27 files changed, 747 insertions(+), 14332 deletions(-) delete mode 100644 src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/jquery/jquery-3.7.1.js delete mode 100644 src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/jquery/jquery-3.7.1.min.js delete mode 100644 src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/jquery/jquery-ui.css delete mode 100644 src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/jquery/jquery-ui.js delete mode 100644 src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/jquery/jquery-ui.min.css delete mode 100644 src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/jquery/jquery-ui.min.js delete mode 100644 src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/search-page.js delete mode 100644 src/jdk.javadoc/share/legal/jquery.md delete mode 100644 src/jdk.javadoc/share/legal/jqueryUI.md diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDoclet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDoclet.java index 66fcd90e2e8..17d56ff11ba 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDoclet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDoclet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -335,16 +335,9 @@ public class HtmlDoclet extends AbstractDoclet { if (options.createIndex()) { copyResource(DocPaths.SEARCH_JS_TEMPLATE, DocPaths.SCRIPT_FILES.resolve(DocPaths.SEARCH_JS), true); - copyResource(DocPaths.SEARCH_PAGE_JS, DocPaths.SCRIPT_FILES.resolve(DocPaths.SEARCH_PAGE_JS), true); copyResource(DocPaths.GLASS_SVG, DocPaths.RESOURCE_FILES.resolve(DocPaths.GLASS_SVG), false); copyResource(DocPaths.X_SVG, DocPaths.RESOURCE_FILES.resolve(DocPaths.X_SVG), false); - // No newline replacement for JQuery files - copyResource(DocPaths.JQUERY_DIR.resolve(DocPaths.JQUERY_JS), - DocPaths.SCRIPT_FILES.resolve(DocPaths.JQUERY_JS), false); - copyResource(DocPaths.JQUERY_DIR.resolve(DocPaths.JQUERY_UI_JS), - DocPaths.SCRIPT_FILES.resolve(DocPaths.JQUERY_UI_JS), false); - copyResource(DocPaths.JQUERY_DIR.resolve(DocPaths.JQUERY_UI_CSS), - DocPaths.RESOURCE_FILES.resolve(DocPaths.JQUERY_UI_CSS), false); } + } copyLegalFiles(options.createIndex(), options.syntaxHighlight()); // Print a notice if the documentation contains diagnostic markers @@ -369,7 +362,7 @@ public class HtmlDoclet extends AbstractDoclet { case "", "default" -> { // use a known resource as a stand-in, because we cannot get the URL for a resources directory var url = HtmlDoclet.class.getResource( - DocPaths.RESOURCES.resolve(DocPaths.LEGAL).resolve(DocPaths.JQUERY_MD).getPath()); + DocPaths.RESOURCES.resolve(DocPaths.LEGAL).resolve(DocPaths.DEJAVU_MD).getPath()); if (url != null) { try { legalNoticesDir = Path.of(url.toURI()).getParent(); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlIds.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlIds.java index a3fba7eca14..50e6207b833 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlIds.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlIds.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * 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,11 @@ public class HtmlIds { static final HtmlId RELATED_PACKAGE_SUMMARY = HtmlId.of("related-package-summary"); static final HtmlId RESET_SEARCH = HtmlId.of("reset-search"); static final HtmlId SEARCH_INPUT = HtmlId.of("search-input"); + static final HtmlId SEARCH_INPUT_CONTAINER = HtmlId.of("search-input-container"); + static final HtmlId SEARCH_MODULES = HtmlId.of("search-modules"); + static final HtmlId SEARCH_PAGE_LINK = HtmlId.of("search-page-link"); + static final HtmlId SEARCH_RESULT_CONTAINER = HtmlId.of("search-result-container"); + static final HtmlId SEARCH_RESULT_SECTION = HtmlId.of("search-result-section"); static final HtmlId SERVICES = HtmlId.of("services-summary"); static final HtmlId SKIP_NAVBAR_TOP = HtmlId.of("skip-navbar-top"); static final HtmlId THEME_BUTTON = HtmlId.of("theme-button"); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Navigation.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Navigation.java index 30318bbaeea..cde5b287e25 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Navigation.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Navigation.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,6 +45,8 @@ import jdk.javadoc.internal.html.Content; import jdk.javadoc.internal.html.ContentBuilder; import jdk.javadoc.internal.html.Entity; import jdk.javadoc.internal.html.HtmlAttr; +import jdk.javadoc.internal.html.HtmlId; +import jdk.javadoc.internal.html.HtmlTag; import jdk.javadoc.internal.html.HtmlTree; import jdk.javadoc.internal.html.Text; @@ -535,6 +537,42 @@ public class Navigation { .add(inputText) .add(inputReset); target.add(searchDiv); + target.add(HtmlTree.DIV(HtmlIds.SEARCH_RESULT_SECTION) + .add(HtmlTree.DIV(HtmlStyles.searchForm) + .add(HtmlTree.DIV(HtmlTree.LABEL(HtmlIds.SEARCH_INPUT.name(), + contents.getContent("doclet.search.for")))) + .add(HtmlTree.DIV(HtmlIds.SEARCH_INPUT_CONTAINER).addUnchecked(Text.EMPTY)) + .add(createModuleSelector())) + .add(HtmlTree.DIV(HtmlIds.SEARCH_RESULT_CONTAINER).addUnchecked(Text.EMPTY)) + .add(HtmlTree.DIV(HtmlStyles.searchLinks) + .add(HtmlTree.DIV(links.createLink(pathToRoot.resolve(DocPaths.SEARCH_PAGE), + contents.getContent("doclet.search.linkSearchPageLabel")) + .setId(HtmlIds.SEARCH_PAGE_LINK))) + .add(options.noHelp() || !options.helpFile().isEmpty() + ? HtmlTree.DIV(Text.EMPTY).addUnchecked(Text.EMPTY) + : HtmlTree.DIV(links.createLink(pathToRoot.resolve(DocPaths.HELP_DOC).fragment("search"), + contents.getContent("doclet.search.linkSearchHelpLabel")))))); + } + + private Content createModuleSelector() { + if (!configuration.showModules || configuration.modules.size() < 2) { + return Text.EMPTY; + } + var content = new ContentBuilder(HtmlTree.DIV(HtmlTree.LABEL(HtmlIds.SEARCH_MODULES.name(), + contents.getContent("doclet.search.in_modules")))); + var select = HtmlTree.of(HtmlTag.SELECT) + .setId(HtmlIds.SEARCH_MODULES) + .put(HtmlAttr.ARIA_LABEL, configuration.getDocResources().getText("doclet.selectModule")) + .add(HtmlTree.of(HtmlTag.OPTION) + .put(HtmlAttr.VALUE, "") + .add(contents.getContent("doclet.search.all_modules"))); + + for (ModuleElement module : configuration.modules) { + select.add(HtmlTree.of(HtmlTag.OPTION) + .put(HtmlAttr.VALUE, module.getQualifiedName().toString()) + .add(Text.of(module.getQualifiedName().toString()))); + } + return content.add(HtmlTree.DIV(select)); } /** diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SearchWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SearchWriter.java index 433a641530d..5fa0daacf98 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SearchWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SearchWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -92,17 +92,15 @@ public class SearchWriter extends HtmlDocletWriter { .add(resourceSection) .add(HtmlTree.P(contents.getContent("doclet.search.loading")) .setId(HtmlId.of("page-search-notify"))) - .add(HtmlTree.DIV(HtmlTree.DIV(HtmlId.of("result-container")) + .add(HtmlTree.DIV(HtmlTree.DIV(HtmlIds.SEARCH_RESULT_CONTAINER) .addUnchecked(Text.EMPTY)) - .setId(HtmlId.of("result-section")) - .put(HtmlAttr.STYLE, "display: none;") - .add(HtmlTree.SCRIPT(pathToRoot.resolve(DocPaths.SCRIPT_FILES) - .resolve(DocPaths.SEARCH_PAGE_JS).getPath()))); + .setId(HtmlIds.SEARCH_RESULT_SECTION) + .put(HtmlAttr.STYLE, "display: none;")); } private Content createModuleSelector() { - if (!configuration.showModules) { + if (!configuration.showModules || configuration.modules.size() < 2) { return Text.EMPTY; } @@ -118,7 +116,7 @@ public class SearchWriter extends HtmlDocletWriter { .put(HtmlAttr.VALUE, module.getQualifiedName().toString()) .add(Text.of(module.getQualifiedName().toString()))); } - return new ContentBuilder(contents.getContent("doclet.search.in", select)); + return new ContentBuilder(contents.getContent("doclet.search.in_modules"), select); } private Content createResourceSection() { diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Head.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Head.java index cda4bc9a5be..bff32cbd7bf 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Head.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Head.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * 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,11 +336,6 @@ public class Head extends Content { } private void addStylesheets(HtmlTree head) { - if (index) { - // Add JQuery-UI stylesheet first so its rules can be overridden. - addStylesheet(head, DocPaths.RESOURCE_FILES.resolve(DocPaths.JQUERY_UI_CSS)); - } - if (mainStylesheet == null) { mainStylesheet = DocPaths.STYLESHEET; } @@ -381,8 +376,6 @@ public class Head extends Content { .append("loadScripts();\n") .append("initTheme();\n"); } - addScriptElement(head, DocPaths.JQUERY_JS); - addScriptElement(head, DocPaths.JQUERY_UI_JS); } for (HtmlConfiguration.JavaScriptFile javaScriptFile : additionalScripts) { addScriptElement(head, javaScriptFile); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlStyles.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlStyles.java index 9b59cb0cb47..2b154db7de7 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlStyles.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlStyles.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -734,6 +734,16 @@ public enum HtmlStyles implements HtmlStyle { */ pageSearchInfo, + /** + * The class for a {@code div} element in the search widget containing the search form inputs. + */ + searchForm, + + /** + * The class for a {@code div} element in the search widget containing search-related links. + */ + searchLinks, + /** * The class for a link in the static "Index" pages to a custom searchable item, * such as defined with an {@code @index} tag. diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/jquery/jquery-3.7.1.js b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/jquery/jquery-3.7.1.js deleted file mode 100644 index 1a86433c223..00000000000 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/jquery/jquery-3.7.1.js +++ /dev/null @@ -1,10716 +0,0 @@ -/*! - * jQuery JavaScript Library v3.7.1 - * https://jquery.com/ - * - * Copyright OpenJS Foundation and other contributors - * Released under the MIT license - * https://jquery.org/license - * - * Date: 2023-08-28T13:37Z - */ -( function( global, factory ) { - - "use strict"; - - if ( typeof module === "object" && typeof module.exports === "object" ) { - - // For CommonJS and CommonJS-like environments where a proper `window` - // is present, execute the factory and get jQuery. - // For environments that do not have a `window` with a `document` - // (such as Node.js), expose a factory as module.exports. - // This accentuates the need for the creation of a real `window`. - // e.g. var jQuery = require("jquery")(window); - // See ticket trac-14549 for more info. - module.exports = global.document ? - factory( global, true ) : - function( w ) { - if ( !w.document ) { - throw new Error( "jQuery requires a window with a document" ); - } - return factory( w ); - }; - } else { - factory( global ); - } - -// Pass this if window is not defined yet -} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) { - -// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1 -// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode -// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common -// enough that all such attempts are guarded in a try block. -"use strict"; - -var arr = []; - -var getProto = Object.getPrototypeOf; - -var slice = arr.slice; - -var flat = arr.flat ? function( array ) { - return arr.flat.call( array ); -} : function( array ) { - return arr.concat.apply( [], array ); -}; - - -var push = arr.push; - -var indexOf = arr.indexOf; - -var class2type = {}; - -var toString = class2type.toString; - -var hasOwn = class2type.hasOwnProperty; - -var fnToString = hasOwn.toString; - -var ObjectFunctionString = fnToString.call( Object ); - -var support = {}; - -var isFunction = function isFunction( obj ) { - - // Support: Chrome <=57, Firefox <=52 - // In some browsers, typeof returns "function" for HTML elements - // (i.e., `typeof document.createElement( "object" ) === "function"`). - // We don't want to classify *any* DOM node as a function. - // Support: QtWeb <=3.8.5, WebKit <=534.34, wkhtmltopdf tool <=0.12.5 - // Plus for old WebKit, typeof returns "function" for HTML collections - // (e.g., `typeof document.getElementsByTagName("div") === "function"`). (gh-4756) - return typeof obj === "function" && typeof obj.nodeType !== "number" && - typeof obj.item !== "function"; - }; - - -var isWindow = function isWindow( obj ) { - return obj != null && obj === obj.window; - }; - - -var document = window.document; - - - - var preservedScriptAttributes = { - type: true, - src: true, - nonce: true, - noModule: true - }; - - function DOMEval( code, node, doc ) { - doc = doc || document; - - var i, val, - script = doc.createElement( "script" ); - - script.text = code; - if ( node ) { - for ( i in preservedScriptAttributes ) { - - // Support: Firefox 64+, Edge 18+ - // Some browsers don't support the "nonce" property on scripts. - // On the other hand, just using `getAttribute` is not enough as - // the `nonce` attribute is reset to an empty string whenever it - // becomes browsing-context connected. - // See https://github.com/whatwg/html/issues/2369 - // See https://html.spec.whatwg.org/#nonce-attributes - // The `node.getAttribute` check was added for the sake of - // `jQuery.globalEval` so that it can fake a nonce-containing node - // via an object. - val = node[ i ] || node.getAttribute && node.getAttribute( i ); - if ( val ) { - script.setAttribute( i, val ); - } - } - } - doc.head.appendChild( script ).parentNode.removeChild( script ); - } - - -function toType( obj ) { - if ( obj == null ) { - return obj + ""; - } - - // Support: Android <=2.3 only (functionish RegExp) - return typeof obj === "object" || typeof obj === "function" ? - class2type[ toString.call( obj ) ] || "object" : - typeof obj; -} -/* global Symbol */ -// Defining this global in .eslintrc.json would create a danger of using the global -// unguarded in another place, it seems safer to define global only for this module - - - -var version = "3.7.1", - - rhtmlSuffix = /HTML$/i, - - // Define a local copy of jQuery - jQuery = function( selector, context ) { - - // The jQuery object is actually just the init constructor 'enhanced' - // Need init if jQuery is called (just allow error to be thrown if not included) - return new jQuery.fn.init( selector, context ); - }; - -jQuery.fn = jQuery.prototype = { - - // The current version of jQuery being used - jquery: version, - - constructor: jQuery, - - // The default length of a jQuery object is 0 - length: 0, - - toArray: function() { - return slice.call( this ); - }, - - // Get the Nth element in the matched element set OR - // Get the whole matched element set as a clean array - get: function( num ) { - - // Return all the elements in a clean array - if ( num == null ) { - return slice.call( this ); - } - - // Return just the one element from the set - return num < 0 ? this[ num + this.length ] : this[ num ]; - }, - - // Take an array of elements and push it onto the stack - // (returning the new matched element set) - pushStack: function( elems ) { - - // Build a new jQuery matched element set - var ret = jQuery.merge( this.constructor(), elems ); - - // Add the old object onto the stack (as a reference) - ret.prevObject = this; - - // Return the newly-formed element set - return ret; - }, - - // Execute a callback for every element in the matched set. - each: function( callback ) { - return jQuery.each( this, callback ); - }, - - map: function( callback ) { - return this.pushStack( jQuery.map( this, function( elem, i ) { - return callback.call( elem, i, elem ); - } ) ); - }, - - slice: function() { - return this.pushStack( slice.apply( this, arguments ) ); - }, - - first: function() { - return this.eq( 0 ); - }, - - last: function() { - return this.eq( -1 ); - }, - - even: function() { - return this.pushStack( jQuery.grep( this, function( _elem, i ) { - return ( i + 1 ) % 2; - } ) ); - }, - - odd: function() { - return this.pushStack( jQuery.grep( this, function( _elem, i ) { - return i % 2; - } ) ); - }, - - eq: function( i ) { - var len = this.length, - j = +i + ( i < 0 ? len : 0 ); - return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); - }, - - end: function() { - return this.prevObject || this.constructor(); - }, - - // For internal use only. - // Behaves like an Array's method, not like a jQuery method. - push: push, - sort: arr.sort, - splice: arr.splice -}; - -jQuery.extend = jQuery.fn.extend = function() { - var options, name, src, copy, copyIsArray, clone, - target = arguments[ 0 ] || {}, - i = 1, - length = arguments.length, - deep = false; - - // Handle a deep copy situation - if ( typeof target === "boolean" ) { - deep = target; - - // Skip the boolean and the target - target = arguments[ i ] || {}; - i++; - } - - // Handle case when target is a string or something (possible in deep copy) - if ( typeof target !== "object" && !isFunction( target ) ) { - target = {}; - } - - // Extend jQuery itself if only one argument is passed - if ( i === length ) { - target = this; - i--; - } - - for ( ; i < length; i++ ) { - - // Only deal with non-null/undefined values - if ( ( options = arguments[ i ] ) != null ) { - - // Extend the base object - for ( name in options ) { - copy = options[ name ]; - - // Prevent Object.prototype pollution - // Prevent never-ending loop - if ( name === "__proto__" || target === copy ) { - continue; - } - - // Recurse if we're merging plain objects or arrays - if ( deep && copy && ( jQuery.isPlainObject( copy ) || - ( copyIsArray = Array.isArray( copy ) ) ) ) { - src = target[ name ]; - - // Ensure proper type for the source value - if ( copyIsArray && !Array.isArray( src ) ) { - clone = []; - } else if ( !copyIsArray && !jQuery.isPlainObject( src ) ) { - clone = {}; - } else { - clone = src; - } - copyIsArray = false; - - // Never move original objects, clone them - target[ name ] = jQuery.extend( deep, clone, copy ); - - // Don't bring in undefined values - } else if ( copy !== undefined ) { - target[ name ] = copy; - } - } - } - } - - // Return the modified object - return target; -}; - -jQuery.extend( { - - // Unique for each copy of jQuery on the page - expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), - - // Assume jQuery is ready without the ready module - isReady: true, - - error: function( msg ) { - throw new Error( msg ); - }, - - noop: function() {}, - - isPlainObject: function( obj ) { - var proto, Ctor; - - // Detect obvious negatives - // Use toString instead of jQuery.type to catch host objects - if ( !obj || toString.call( obj ) !== "[object Object]" ) { - return false; - } - - proto = getProto( obj ); - - // Objects with no prototype (e.g., `Object.create( null )`) are plain - if ( !proto ) { - return true; - } - - // Objects with prototype are plain iff they were constructed by a global Object function - Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; - return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; - }, - - isEmptyObject: function( obj ) { - var name; - - for ( name in obj ) { - return false; - } - return true; - }, - - // Evaluates a script in a provided context; falls back to the global one - // if not specified. - globalEval: function( code, options, doc ) { - DOMEval( code, { nonce: options && options.nonce }, doc ); - }, - - each: function( obj, callback ) { - var length, i = 0; - - if ( isArrayLike( obj ) ) { - length = obj.length; - for ( ; i < length; i++ ) { - if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { - break; - } - } - } else { - for ( i in obj ) { - if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { - break; - } - } - } - - return obj; - }, - - - // Retrieve the text value of an array of DOM nodes - text: function( elem ) { - var node, - ret = "", - i = 0, - nodeType = elem.nodeType; - - if ( !nodeType ) { - - // If no nodeType, this is expected to be an array - while ( ( node = elem[ i++ ] ) ) { - - // Do not traverse comment nodes - ret += jQuery.text( node ); - } - } - if ( nodeType === 1 || nodeType === 11 ) { - return elem.textContent; - } - if ( nodeType === 9 ) { - return elem.documentElement.textContent; - } - if ( nodeType === 3 || nodeType === 4 ) { - return elem.nodeValue; - } - - // Do not include comment or processing instruction nodes - - return ret; - }, - - // results is for internal usage only - makeArray: function( arr, results ) { - var ret = results || []; - - if ( arr != null ) { - if ( isArrayLike( Object( arr ) ) ) { - jQuery.merge( ret, - typeof arr === "string" ? - [ arr ] : arr - ); - } else { - push.call( ret, arr ); - } - } - - return ret; - }, - - inArray: function( elem, arr, i ) { - return arr == null ? -1 : indexOf.call( arr, elem, i ); - }, - - isXMLDoc: function( elem ) { - var namespace = elem && elem.namespaceURI, - docElem = elem && ( elem.ownerDocument || elem ).documentElement; - - // Assume HTML when documentElement doesn't yet exist, such as inside - // document fragments. - return !rhtmlSuffix.test( namespace || docElem && docElem.nodeName || "HTML" ); - }, - - // Support: Android <=4.0 only, PhantomJS 1 only - // push.apply(_, arraylike) throws on ancient WebKit - merge: function( first, second ) { - var len = +second.length, - j = 0, - i = first.length; - - for ( ; j < len; j++ ) { - first[ i++ ] = second[ j ]; - } - - first.length = i; - - return first; - }, - - grep: function( elems, callback, invert ) { - var callbackInverse, - matches = [], - i = 0, - length = elems.length, - callbackExpect = !invert; - - // Go through the array, only saving the items - // that pass the validator function - for ( ; i < length; i++ ) { - callbackInverse = !callback( elems[ i ], i ); - if ( callbackInverse !== callbackExpect ) { - matches.push( elems[ i ] ); - } - } - - return matches; - }, - - // arg is for internal usage only - map: function( elems, callback, arg ) { - var length, value, - i = 0, - ret = []; - - // Go through the array, translating each of the items to their new values - if ( isArrayLike( elems ) ) { - length = elems.length; - for ( ; i < length; i++ ) { - value = callback( elems[ i ], i, arg ); - - if ( value != null ) { - ret.push( value ); - } - } - - // Go through every key on the object, - } else { - for ( i in elems ) { - value = callback( elems[ i ], i, arg ); - - if ( value != null ) { - ret.push( value ); - } - } - } - - // Flatten any nested arrays - return flat( ret ); - }, - - // A global GUID counter for objects - guid: 1, - - // jQuery.support is not used in Core but other projects attach their - // properties to it so it needs to exist. - support: support -} ); - -if ( typeof Symbol === "function" ) { - jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; -} - -// Populate the class2type map -jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), - function( _i, name ) { - class2type[ "[object " + name + "]" ] = name.toLowerCase(); - } ); - -function isArrayLike( obj ) { - - // Support: real iOS 8.2 only (not reproducible in simulator) - // `in` check used to prevent JIT error (gh-2145) - // hasOwn isn't used here due to false negatives - // regarding Nodelist length in IE - var length = !!obj && "length" in obj && obj.length, - type = toType( obj ); - - if ( isFunction( obj ) || isWindow( obj ) ) { - return false; - } - - return type === "array" || length === 0 || - typeof length === "number" && length > 0 && ( length - 1 ) in obj; -} - - -function nodeName( elem, name ) { - - return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); - -} -var pop = arr.pop; - - -var sort = arr.sort; - - -var splice = arr.splice; - - -var whitespace = "[\\x20\\t\\r\\n\\f]"; - - -var rtrimCSS = new RegExp( - "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", - "g" -); - - - - -// Note: an element does not contain itself -jQuery.contains = function( a, b ) { - var bup = b && b.parentNode; - - return a === bup || !!( bup && bup.nodeType === 1 && ( - - // Support: IE 9 - 11+ - // IE doesn't have `contains` on SVG. - a.contains ? - a.contains( bup ) : - a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 - ) ); -}; - - - - -// CSS string/identifier serialization -// https://drafts.csswg.org/cssom/#common-serializing-idioms -var rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\x80-\uFFFF\w-]/g; - -function fcssescape( ch, asCodePoint ) { - if ( asCodePoint ) { - - // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER - if ( ch === "\0" ) { - return "\uFFFD"; - } - - // Control characters and (dependent upon position) numbers get escaped as code points - return ch.slice( 0, -1 ) + "\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; - } - - // Other potentially-special ASCII characters get backslash-escaped - return "\\" + ch; -} - -jQuery.escapeSelector = function( sel ) { - return ( sel + "" ).replace( rcssescape, fcssescape ); -}; - - - - -var preferredDoc = document, - pushNative = push; - -( function() { - -var i, - Expr, - outermostContext, - sortInput, - hasDuplicate, - push = pushNative, - - // Local document vars - document, - documentElement, - documentIsHTML, - rbuggyQSA, - matches, - - // Instance-specific data - expando = jQuery.expando, - dirruns = 0, - done = 0, - classCache = createCache(), - tokenCache = createCache(), - compilerCache = createCache(), - nonnativeSelectorCache = createCache(), - sortOrder = function( a, b ) { - if ( a === b ) { - hasDuplicate = true; - } - return 0; - }, - - booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|" + - "loop|multiple|open|readonly|required|scoped", - - // Regular expressions - - // https://www.w3.org/TR/css-syntax-3/#ident-token-diagram - identifier = "(?:\\\\[\\da-fA-F]{1,6}" + whitespace + - "?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+", - - // Attribute selectors: https://www.w3.org/TR/selectors/#attribute-selectors - attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + - - // Operator (capture 2) - "*([*^$|!~]?=)" + whitespace + - - // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]" - "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + - whitespace + "*\\]", - - pseudos = ":(" + identifier + ")(?:\\((" + - - // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: - // 1. quoted (capture 3; capture 4 or capture 5) - "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + - - // 2. simple (capture 6) - "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + - - // 3. anything else (capture 2) - ".*" + - ")\\)|)", - - // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter - rwhitespace = new RegExp( whitespace + "+", "g" ), - - rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), - rleadingCombinator = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + - whitespace + "*" ), - rdescend = new RegExp( whitespace + "|>" ), - - rpseudo = new RegExp( pseudos ), - ridentifier = new RegExp( "^" + identifier + "$" ), - - matchExpr = { - ID: new RegExp( "^#(" + identifier + ")" ), - CLASS: new RegExp( "^\\.(" + identifier + ")" ), - TAG: new RegExp( "^(" + identifier + "|[*])" ), - ATTR: new RegExp( "^" + attributes ), - PSEUDO: new RegExp( "^" + pseudos ), - CHILD: new RegExp( - "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + - whitespace + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + - whitespace + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), - bool: new RegExp( "^(?:" + booleans + ")$", "i" ), - - // For use in libraries implementing .is() - // We use this for POS matching in `select` - needsContext: new RegExp( "^" + whitespace + - "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace + - "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) - }, - - rinputs = /^(?:input|select|textarea|button)$/i, - rheader = /^h\d$/i, - - // Easily-parseable/retrievable ID or TAG or CLASS selectors - rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, - - rsibling = /[+~]/, - - // CSS escapes - // https://www.w3.org/TR/CSS21/syndata.html#escaped-characters - runescape = new RegExp( "\\\\[\\da-fA-F]{1,6}" + whitespace + - "?|\\\\([^\\r\\n\\f])", "g" ), - funescape = function( escape, nonHex ) { - var high = "0x" + escape.slice( 1 ) - 0x10000; - - if ( nonHex ) { - - // Strip the backslash prefix from a non-hex escape sequence - return nonHex; - } - - // Replace a hexadecimal escape sequence with the encoded Unicode code point - // Support: IE <=11+ - // For values outside the Basic Multilingual Plane (BMP), manually construct a - // surrogate pair - return high < 0 ? - String.fromCharCode( high + 0x10000 ) : - String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); - }, - - // Used for iframes; see `setDocument`. - // Support: IE 9 - 11+, Edge 12 - 18+ - // Removing the function wrapper causes a "Permission Denied" - // error in IE/Edge. - unloadHandler = function() { - setDocument(); - }, - - inDisabledFieldset = addCombinator( - function( elem ) { - return elem.disabled === true && nodeName( elem, "fieldset" ); - }, - { dir: "parentNode", next: "legend" } - ); - -// Support: IE <=9 only -// Accessing document.activeElement can throw unexpectedly -// https://bugs.jquery.com/ticket/13393 -function safeActiveElement() { - try { - return document.activeElement; - } catch ( err ) { } -} - -// Optimize for push.apply( _, NodeList ) -try { - push.apply( - ( arr = slice.call( preferredDoc.childNodes ) ), - preferredDoc.childNodes - ); - - // Support: Android <=4.0 - // Detect silently failing push.apply - // eslint-disable-next-line no-unused-expressions - arr[ preferredDoc.childNodes.length ].nodeType; -} catch ( e ) { - push = { - apply: function( target, els ) { - pushNative.apply( target, slice.call( els ) ); - }, - call: function( target ) { - pushNative.apply( target, slice.call( arguments, 1 ) ); - } - }; -} - -function find( selector, context, results, seed ) { - var m, i, elem, nid, match, groups, newSelector, - newContext = context && context.ownerDocument, - - // nodeType defaults to 9, since context defaults to document - nodeType = context ? context.nodeType : 9; - - results = results || []; - - // Return early from calls with invalid selector or context - if ( typeof selector !== "string" || !selector || - nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { - - return results; - } - - // Try to shortcut find operations (as opposed to filters) in HTML documents - if ( !seed ) { - setDocument( context ); - context = context || document; - - if ( documentIsHTML ) { - - // If the selector is sufficiently simple, try using a "get*By*" DOM method - // (excepting DocumentFragment context, where the methods don't exist) - if ( nodeType !== 11 && ( match = rquickExpr.exec( selector ) ) ) { - - // ID selector - if ( ( m = match[ 1 ] ) ) { - - // Document context - if ( nodeType === 9 ) { - if ( ( elem = context.getElementById( m ) ) ) { - - // Support: IE 9 only - // getElementById can match elements by name instead of ID - if ( elem.id === m ) { - push.call( results, elem ); - return results; - } - } else { - return results; - } - - // Element context - } else { - - // Support: IE 9 only - // getElementById can match elements by name instead of ID - if ( newContext && ( elem = newContext.getElementById( m ) ) && - find.contains( context, elem ) && - elem.id === m ) { - - push.call( results, elem ); - return results; - } - } - - // Type selector - } else if ( match[ 2 ] ) { - push.apply( results, context.getElementsByTagName( selector ) ); - return results; - - // Class selector - } else if ( ( m = match[ 3 ] ) && context.getElementsByClassName ) { - push.apply( results, context.getElementsByClassName( m ) ); - return results; - } - } - - // Take advantage of querySelectorAll - if ( !nonnativeSelectorCache[ selector + " " ] && - ( !rbuggyQSA || !rbuggyQSA.test( selector ) ) ) { - - newSelector = selector; - newContext = context; - - // qSA considers elements outside a scoping root when evaluating child or - // descendant combinators, which is not what we want. - // In such cases, we work around the behavior by prefixing every selector in the - // list with an ID selector referencing the scope context. - // The technique has to be used as well when a leading combinator is used - // as such selectors are not recognized by querySelectorAll. - // Thanks to Andrew Dupont for this technique. - if ( nodeType === 1 && - ( rdescend.test( selector ) || rleadingCombinator.test( selector ) ) ) { - - // Expand context for sibling selectors - newContext = rsibling.test( selector ) && testContext( context.parentNode ) || - context; - - // We can use :scope instead of the ID hack if the browser - // supports it & if we're not changing the context. - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when - // strict-comparing two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - if ( newContext != context || !support.scope ) { - - // Capture the context ID, setting it first if necessary - if ( ( nid = context.getAttribute( "id" ) ) ) { - nid = jQuery.escapeSelector( nid ); - } else { - context.setAttribute( "id", ( nid = expando ) ); - } - } - - // Prefix every selector in the list - groups = tokenize( selector ); - i = groups.length; - while ( i-- ) { - groups[ i ] = ( nid ? "#" + nid : ":scope" ) + " " + - toSelector( groups[ i ] ); - } - newSelector = groups.join( "," ); - } - - try { - push.apply( results, - newContext.querySelectorAll( newSelector ) - ); - return results; - } catch ( qsaError ) { - nonnativeSelectorCache( selector, true ); - } finally { - if ( nid === expando ) { - context.removeAttribute( "id" ); - } - } - } - } - } - - // All others - return select( selector.replace( rtrimCSS, "$1" ), context, results, seed ); -} - -/** - * Create key-value caches of limited size - * @returns {function(string, object)} Returns the Object data after storing it on itself with - * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) - * deleting the oldest entry - */ -function createCache() { - var keys = []; - - function cache( key, value ) { - - // Use (key + " ") to avoid collision with native prototype properties - // (see https://github.com/jquery/sizzle/issues/157) - if ( keys.push( key + " " ) > Expr.cacheLength ) { - - // Only keep the most recent entries - delete cache[ keys.shift() ]; - } - return ( cache[ key + " " ] = value ); - } - return cache; -} - -/** - * Mark a function for special use by jQuery selector module - * @param {Function} fn The function to mark - */ -function markFunction( fn ) { - fn[ expando ] = true; - return fn; -} - -/** - * Support testing using an element - * @param {Function} fn Passed the created element and returns a boolean result - */ -function assert( fn ) { - var el = document.createElement( "fieldset" ); - - try { - return !!fn( el ); - } catch ( e ) { - return false; - } finally { - - // Remove from its parent by default - if ( el.parentNode ) { - el.parentNode.removeChild( el ); - } - - // release memory in IE - el = null; - } -} - -/** - * Returns a function to use in pseudos for input types - * @param {String} type - */ -function createInputPseudo( type ) { - return function( elem ) { - return nodeName( elem, "input" ) && elem.type === type; - }; -} - -/** - * Returns a function to use in pseudos for buttons - * @param {String} type - */ -function createButtonPseudo( type ) { - return function( elem ) { - return ( nodeName( elem, "input" ) || nodeName( elem, "button" ) ) && - elem.type === type; - }; -} - -/** - * Returns a function to use in pseudos for :enabled/:disabled - * @param {Boolean} disabled true for :disabled; false for :enabled - */ -function createDisabledPseudo( disabled ) { - - // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable - return function( elem ) { - - // Only certain elements can match :enabled or :disabled - // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled - // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled - if ( "form" in elem ) { - - // Check for inherited disabledness on relevant non-disabled elements: - // * listed form-associated elements in a disabled fieldset - // https://html.spec.whatwg.org/multipage/forms.html#category-listed - // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled - // * option elements in a disabled optgroup - // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled - // All such elements have a "form" property. - if ( elem.parentNode && elem.disabled === false ) { - - // Option elements defer to a parent optgroup if present - if ( "label" in elem ) { - if ( "label" in elem.parentNode ) { - return elem.parentNode.disabled === disabled; - } else { - return elem.disabled === disabled; - } - } - - // Support: IE 6 - 11+ - // Use the isDisabled shortcut property to check for disabled fieldset ancestors - return elem.isDisabled === disabled || - - // Where there is no isDisabled, check manually - elem.isDisabled !== !disabled && - inDisabledFieldset( elem ) === disabled; - } - - return elem.disabled === disabled; - - // Try to winnow out elements that can't be disabled before trusting the disabled property. - // Some victims get caught in our net (label, legend, menu, track), but it shouldn't - // even exist on them, let alone have a boolean value. - } else if ( "label" in elem ) { - return elem.disabled === disabled; - } - - // Remaining elements are neither :enabled nor :disabled - return false; - }; -} - -/** - * Returns a function to use in pseudos for positionals - * @param {Function} fn - */ -function createPositionalPseudo( fn ) { - return markFunction( function( argument ) { - argument = +argument; - return markFunction( function( seed, matches ) { - var j, - matchIndexes = fn( [], seed.length, argument ), - i = matchIndexes.length; - - // Match elements found at the specified indexes - while ( i-- ) { - if ( seed[ ( j = matchIndexes[ i ] ) ] ) { - seed[ j ] = !( matches[ j ] = seed[ j ] ); - } - } - } ); - } ); -} - -/** - * Checks a node for validity as a jQuery selector context - * @param {Element|Object=} context - * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value - */ -function testContext( context ) { - return context && typeof context.getElementsByTagName !== "undefined" && context; -} - -/** - * Sets document-related variables once based on the current document - * @param {Element|Object} [node] An element or document object to use to set the document - * @returns {Object} Returns the current document - */ -function setDocument( node ) { - var subWindow, - doc = node ? node.ownerDocument || node : preferredDoc; - - // Return early if doc is invalid or already selected - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - if ( doc == document || doc.nodeType !== 9 || !doc.documentElement ) { - return document; - } - - // Update global variables - document = doc; - documentElement = document.documentElement; - documentIsHTML = !jQuery.isXMLDoc( document ); - - // Support: iOS 7 only, IE 9 - 11+ - // Older browsers didn't support unprefixed `matches`. - matches = documentElement.matches || - documentElement.webkitMatchesSelector || - documentElement.msMatchesSelector; - - // Support: IE 9 - 11+, Edge 12 - 18+ - // Accessing iframe documents after unload throws "permission denied" errors - // (see trac-13936). - // Limit the fix to IE & Edge Legacy; despite Edge 15+ implementing `matches`, - // all IE 9+ and Edge Legacy versions implement `msMatchesSelector` as well. - if ( documentElement.msMatchesSelector && - - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - preferredDoc != document && - ( subWindow = document.defaultView ) && subWindow.top !== subWindow ) { - - // Support: IE 9 - 11+, Edge 12 - 18+ - subWindow.addEventListener( "unload", unloadHandler ); - } - - // Support: IE <10 - // Check if getElementById returns elements by name - // The broken getElementById methods don't pick up programmatically-set names, - // so use a roundabout getElementsByName test - support.getById = assert( function( el ) { - documentElement.appendChild( el ).id = jQuery.expando; - return !document.getElementsByName || - !document.getElementsByName( jQuery.expando ).length; - } ); - - // Support: IE 9 only - // Check to see if it's possible to do matchesSelector - // on a disconnected node. - support.disconnectedMatch = assert( function( el ) { - return matches.call( el, "*" ); - } ); - - // Support: IE 9 - 11+, Edge 12 - 18+ - // IE/Edge don't support the :scope pseudo-class. - support.scope = assert( function() { - return document.querySelectorAll( ":scope" ); - } ); - - // Support: Chrome 105 - 111 only, Safari 15.4 - 16.3 only - // Make sure the `:has()` argument is parsed unforgivingly. - // We include `*` in the test to detect buggy implementations that are - // _selectively_ forgiving (specifically when the list includes at least - // one valid selector). - // Note that we treat complete lack of support for `:has()` as if it were - // spec-compliant support, which is fine because use of `:has()` in such - // environments will fail in the qSA path and fall back to jQuery traversal - // anyway. - support.cssHas = assert( function() { - try { - document.querySelector( ":has(*,:jqfake)" ); - return false; - } catch ( e ) { - return true; - } - } ); - - // ID filter and find - if ( support.getById ) { - Expr.filter.ID = function( id ) { - var attrId = id.replace( runescape, funescape ); - return function( elem ) { - return elem.getAttribute( "id" ) === attrId; - }; - }; - Expr.find.ID = function( id, context ) { - if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { - var elem = context.getElementById( id ); - return elem ? [ elem ] : []; - } - }; - } else { - Expr.filter.ID = function( id ) { - var attrId = id.replace( runescape, funescape ); - return function( elem ) { - var node = typeof elem.getAttributeNode !== "undefined" && - elem.getAttributeNode( "id" ); - return node && node.value === attrId; - }; - }; - - // Support: IE 6 - 7 only - // getElementById is not reliable as a find shortcut - Expr.find.ID = function( id, context ) { - if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { - var node, i, elems, - elem = context.getElementById( id ); - - if ( elem ) { - - // Verify the id attribute - node = elem.getAttributeNode( "id" ); - if ( node && node.value === id ) { - return [ elem ]; - } - - // Fall back on getElementsByName - elems = context.getElementsByName( id ); - i = 0; - while ( ( elem = elems[ i++ ] ) ) { - node = elem.getAttributeNode( "id" ); - if ( node && node.value === id ) { - return [ elem ]; - } - } - } - - return []; - } - }; - } - - // Tag - Expr.find.TAG = function( tag, context ) { - if ( typeof context.getElementsByTagName !== "undefined" ) { - return context.getElementsByTagName( tag ); - - // DocumentFragment nodes don't have gEBTN - } else { - return context.querySelectorAll( tag ); - } - }; - - // Class - Expr.find.CLASS = function( className, context ) { - if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { - return context.getElementsByClassName( className ); - } - }; - - /* QSA/matchesSelector - ---------------------------------------------------------------------- */ - - // QSA and matchesSelector support - - rbuggyQSA = []; - - // Build QSA regex - // Regex strategy adopted from Diego Perini - assert( function( el ) { - - var input; - - documentElement.appendChild( el ).innerHTML = - "" + - ""; - - // Support: iOS <=7 - 8 only - // Boolean attributes and "value" are not treated correctly in some XML documents - if ( !el.querySelectorAll( "[selected]" ).length ) { - rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); - } - - // Support: iOS <=7 - 8 only - if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) { - rbuggyQSA.push( "~=" ); - } - - // Support: iOS 8 only - // https://bugs.webkit.org/show_bug.cgi?id=136851 - // In-page `selector#id sibling-combinator selector` fails - if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) { - rbuggyQSA.push( ".#.+[+~]" ); - } - - // Support: Chrome <=105+, Firefox <=104+, Safari <=15.4+ - // In some of the document kinds, these selectors wouldn't work natively. - // This is probably OK but for backwards compatibility we want to maintain - // handling them through jQuery traversal in jQuery 3.x. - if ( !el.querySelectorAll( ":checked" ).length ) { - rbuggyQSA.push( ":checked" ); - } - - // Support: Windows 8 Native Apps - // The type and name attributes are restricted during .innerHTML assignment - input = document.createElement( "input" ); - input.setAttribute( "type", "hidden" ); - el.appendChild( input ).setAttribute( "name", "D" ); - - // Support: IE 9 - 11+ - // IE's :disabled selector does not pick up the children of disabled fieldsets - // Support: Chrome <=105+, Firefox <=104+, Safari <=15.4+ - // In some of the document kinds, these selectors wouldn't work natively. - // This is probably OK but for backwards compatibility we want to maintain - // handling them through jQuery traversal in jQuery 3.x. - documentElement.appendChild( el ).disabled = true; - if ( el.querySelectorAll( ":disabled" ).length !== 2 ) { - rbuggyQSA.push( ":enabled", ":disabled" ); - } - - // Support: IE 11+, Edge 15 - 18+ - // IE 11/Edge don't find elements on a `[name='']` query in some cases. - // Adding a temporary attribute to the document before the selection works - // around the issue. - // Interestingly, IE 10 & older don't seem to have the issue. - input = document.createElement( "input" ); - input.setAttribute( "name", "" ); - el.appendChild( input ); - if ( !el.querySelectorAll( "[name='']" ).length ) { - rbuggyQSA.push( "\\[" + whitespace + "*name" + whitespace + "*=" + - whitespace + "*(?:''|\"\")" ); - } - } ); - - if ( !support.cssHas ) { - - // Support: Chrome 105 - 110+, Safari 15.4 - 16.3+ - // Our regular `try-catch` mechanism fails to detect natively-unsupported - // pseudo-classes inside `:has()` (such as `:has(:contains("Foo"))`) - // in browsers that parse the `:has()` argument as a forgiving selector list. - // https://drafts.csswg.org/selectors/#relational now requires the argument - // to be parsed unforgivingly, but browsers have not yet fully adjusted. - rbuggyQSA.push( ":has" ); - } - - rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join( "|" ) ); - - /* Sorting - ---------------------------------------------------------------------- */ - - // Document order sorting - sortOrder = function( a, b ) { - - // Flag for duplicate removal - if ( a === b ) { - hasDuplicate = true; - return 0; - } - - // Sort on method existence if only one input has compareDocumentPosition - var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; - if ( compare ) { - return compare; - } - - // Calculate position if both inputs belong to the same document - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - compare = ( a.ownerDocument || a ) == ( b.ownerDocument || b ) ? - a.compareDocumentPosition( b ) : - - // Otherwise we know they are disconnected - 1; - - // Disconnected nodes - if ( compare & 1 || - ( !support.sortDetached && b.compareDocumentPosition( a ) === compare ) ) { - - // Choose the first element that is related to our preferred document - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - if ( a === document || a.ownerDocument == preferredDoc && - find.contains( preferredDoc, a ) ) { - return -1; - } - - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - if ( b === document || b.ownerDocument == preferredDoc && - find.contains( preferredDoc, b ) ) { - return 1; - } - - // Maintain original order - return sortInput ? - ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) : - 0; - } - - return compare & 4 ? -1 : 1; - }; - - return document; -} - -find.matches = function( expr, elements ) { - return find( expr, null, null, elements ); -}; - -find.matchesSelector = function( elem, expr ) { - setDocument( elem ); - - if ( documentIsHTML && - !nonnativeSelectorCache[ expr + " " ] && - ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { - - try { - var ret = matches.call( elem, expr ); - - // IE 9's matchesSelector returns false on disconnected nodes - if ( ret || support.disconnectedMatch || - - // As well, disconnected nodes are said to be in a document - // fragment in IE 9 - elem.document && elem.document.nodeType !== 11 ) { - return ret; - } - } catch ( e ) { - nonnativeSelectorCache( expr, true ); - } - } - - return find( expr, document, null, [ elem ] ).length > 0; -}; - -find.contains = function( context, elem ) { - - // Set document vars if needed - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - if ( ( context.ownerDocument || context ) != document ) { - setDocument( context ); - } - return jQuery.contains( context, elem ); -}; - - -find.attr = function( elem, name ) { - - // Set document vars if needed - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - if ( ( elem.ownerDocument || elem ) != document ) { - setDocument( elem ); - } - - var fn = Expr.attrHandle[ name.toLowerCase() ], - - // Don't get fooled by Object.prototype properties (see trac-13807) - val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? - fn( elem, name, !documentIsHTML ) : - undefined; - - if ( val !== undefined ) { - return val; - } - - return elem.getAttribute( name ); -}; - -find.error = function( msg ) { - throw new Error( "Syntax error, unrecognized expression: " + msg ); -}; - -/** - * Document sorting and removing duplicates - * @param {ArrayLike} results - */ -jQuery.uniqueSort = function( results ) { - var elem, - duplicates = [], - j = 0, - i = 0; - - // Unless we *know* we can detect duplicates, assume their presence - // - // Support: Android <=4.0+ - // Testing for detecting duplicates is unpredictable so instead assume we can't - // depend on duplicate detection in all browsers without a stable sort. - hasDuplicate = !support.sortStable; - sortInput = !support.sortStable && slice.call( results, 0 ); - sort.call( results, sortOrder ); - - if ( hasDuplicate ) { - while ( ( elem = results[ i++ ] ) ) { - if ( elem === results[ i ] ) { - j = duplicates.push( i ); - } - } - while ( j-- ) { - splice.call( results, duplicates[ j ], 1 ); - } - } - - // Clear input after sorting to release objects - // See https://github.com/jquery/sizzle/pull/225 - sortInput = null; - - return results; -}; - -jQuery.fn.uniqueSort = function() { - return this.pushStack( jQuery.uniqueSort( slice.apply( this ) ) ); -}; - -Expr = jQuery.expr = { - - // Can be adjusted by the user - cacheLength: 50, - - createPseudo: markFunction, - - match: matchExpr, - - attrHandle: {}, - - find: {}, - - relative: { - ">": { dir: "parentNode", first: true }, - " ": { dir: "parentNode" }, - "+": { dir: "previousSibling", first: true }, - "~": { dir: "previousSibling" } - }, - - preFilter: { - ATTR: function( match ) { - match[ 1 ] = match[ 1 ].replace( runescape, funescape ); - - // Move the given value to match[3] whether quoted or unquoted - match[ 3 ] = ( match[ 3 ] || match[ 4 ] || match[ 5 ] || "" ) - .replace( runescape, funescape ); - - if ( match[ 2 ] === "~=" ) { - match[ 3 ] = " " + match[ 3 ] + " "; - } - - return match.slice( 0, 4 ); - }, - - CHILD: function( match ) { - - /* matches from matchExpr["CHILD"] - 1 type (only|nth|...) - 2 what (child|of-type) - 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) - 4 xn-component of xn+y argument ([+-]?\d*n|) - 5 sign of xn-component - 6 x of xn-component - 7 sign of y-component - 8 y of y-component - */ - match[ 1 ] = match[ 1 ].toLowerCase(); - - if ( match[ 1 ].slice( 0, 3 ) === "nth" ) { - - // nth-* requires argument - if ( !match[ 3 ] ) { - find.error( match[ 0 ] ); - } - - // numeric x and y parameters for Expr.filter.CHILD - // remember that false/true cast respectively to 0/1 - match[ 4 ] = +( match[ 4 ] ? - match[ 5 ] + ( match[ 6 ] || 1 ) : - 2 * ( match[ 3 ] === "even" || match[ 3 ] === "odd" ) - ); - match[ 5 ] = +( ( match[ 7 ] + match[ 8 ] ) || match[ 3 ] === "odd" ); - - // other types prohibit arguments - } else if ( match[ 3 ] ) { - find.error( match[ 0 ] ); - } - - return match; - }, - - PSEUDO: function( match ) { - var excess, - unquoted = !match[ 6 ] && match[ 2 ]; - - if ( matchExpr.CHILD.test( match[ 0 ] ) ) { - return null; - } - - // Accept quoted arguments as-is - if ( match[ 3 ] ) { - match[ 2 ] = match[ 4 ] || match[ 5 ] || ""; - - // Strip excess characters from unquoted arguments - } else if ( unquoted && rpseudo.test( unquoted ) && - - // Get excess from tokenize (recursively) - ( excess = tokenize( unquoted, true ) ) && - - // advance to the next closing parenthesis - ( excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length ) ) { - - // excess is a negative index - match[ 0 ] = match[ 0 ].slice( 0, excess ); - match[ 2 ] = unquoted.slice( 0, excess ); - } - - // Return only captures needed by the pseudo filter method (type and argument) - return match.slice( 0, 3 ); - } - }, - - filter: { - - TAG: function( nodeNameSelector ) { - var expectedNodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); - return nodeNameSelector === "*" ? - function() { - return true; - } : - function( elem ) { - return nodeName( elem, expectedNodeName ); - }; - }, - - CLASS: function( className ) { - var pattern = classCache[ className + " " ]; - - return pattern || - ( pattern = new RegExp( "(^|" + whitespace + ")" + className + - "(" + whitespace + "|$)" ) ) && - classCache( className, function( elem ) { - return pattern.test( - typeof elem.className === "string" && elem.className || - typeof elem.getAttribute !== "undefined" && - elem.getAttribute( "class" ) || - "" - ); - } ); - }, - - ATTR: function( name, operator, check ) { - return function( elem ) { - var result = find.attr( elem, name ); - - if ( result == null ) { - return operator === "!="; - } - if ( !operator ) { - return true; - } - - result += ""; - - if ( operator === "=" ) { - return result === check; - } - if ( operator === "!=" ) { - return result !== check; - } - if ( operator === "^=" ) { - return check && result.indexOf( check ) === 0; - } - if ( operator === "*=" ) { - return check && result.indexOf( check ) > -1; - } - if ( operator === "$=" ) { - return check && result.slice( -check.length ) === check; - } - if ( operator === "~=" ) { - return ( " " + result.replace( rwhitespace, " " ) + " " ) - .indexOf( check ) > -1; - } - if ( operator === "|=" ) { - return result === check || result.slice( 0, check.length + 1 ) === check + "-"; - } - - return false; - }; - }, - - CHILD: function( type, what, _argument, first, last ) { - var simple = type.slice( 0, 3 ) !== "nth", - forward = type.slice( -4 ) !== "last", - ofType = what === "of-type"; - - return first === 1 && last === 0 ? - - // Shortcut for :nth-*(n) - function( elem ) { - return !!elem.parentNode; - } : - - function( elem, _context, xml ) { - var cache, outerCache, node, nodeIndex, start, - dir = simple !== forward ? "nextSibling" : "previousSibling", - parent = elem.parentNode, - name = ofType && elem.nodeName.toLowerCase(), - useCache = !xml && !ofType, - diff = false; - - if ( parent ) { - - // :(first|last|only)-(child|of-type) - if ( simple ) { - while ( dir ) { - node = elem; - while ( ( node = node[ dir ] ) ) { - if ( ofType ? - nodeName( node, name ) : - node.nodeType === 1 ) { - - return false; - } - } - - // Reverse direction for :only-* (if we haven't yet done so) - start = dir = type === "only" && !start && "nextSibling"; - } - return true; - } - - start = [ forward ? parent.firstChild : parent.lastChild ]; - - // non-xml :nth-child(...) stores cache data on `parent` - if ( forward && useCache ) { - - // Seek `elem` from a previously-cached index - outerCache = parent[ expando ] || ( parent[ expando ] = {} ); - cache = outerCache[ type ] || []; - nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; - diff = nodeIndex && cache[ 2 ]; - node = nodeIndex && parent.childNodes[ nodeIndex ]; - - while ( ( node = ++nodeIndex && node && node[ dir ] || - - // Fallback to seeking `elem` from the start - ( diff = nodeIndex = 0 ) || start.pop() ) ) { - - // When found, cache indexes on `parent` and break - if ( node.nodeType === 1 && ++diff && node === elem ) { - outerCache[ type ] = [ dirruns, nodeIndex, diff ]; - break; - } - } - - } else { - - // Use previously-cached element index if available - if ( useCache ) { - outerCache = elem[ expando ] || ( elem[ expando ] = {} ); - cache = outerCache[ type ] || []; - nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; - diff = nodeIndex; - } - - // xml :nth-child(...) - // or :nth-last-child(...) or :nth(-last)?-of-type(...) - if ( diff === false ) { - - // Use the same loop as above to seek `elem` from the start - while ( ( node = ++nodeIndex && node && node[ dir ] || - ( diff = nodeIndex = 0 ) || start.pop() ) ) { - - if ( ( ofType ? - nodeName( node, name ) : - node.nodeType === 1 ) && - ++diff ) { - - // Cache the index of each encountered element - if ( useCache ) { - outerCache = node[ expando ] || - ( node[ expando ] = {} ); - outerCache[ type ] = [ dirruns, diff ]; - } - - if ( node === elem ) { - break; - } - } - } - } - } - - // Incorporate the offset, then check against cycle size - diff -= last; - return diff === first || ( diff % first === 0 && diff / first >= 0 ); - } - }; - }, - - PSEUDO: function( pseudo, argument ) { - - // pseudo-class names are case-insensitive - // https://www.w3.org/TR/selectors/#pseudo-classes - // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters - // Remember that setFilters inherits from pseudos - var args, - fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || - find.error( "unsupported pseudo: " + pseudo ); - - // The user may use createPseudo to indicate that - // arguments are needed to create the filter function - // just as jQuery does - if ( fn[ expando ] ) { - return fn( argument ); - } - - // But maintain support for old signatures - if ( fn.length > 1 ) { - args = [ pseudo, pseudo, "", argument ]; - return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? - markFunction( function( seed, matches ) { - var idx, - matched = fn( seed, argument ), - i = matched.length; - while ( i-- ) { - idx = indexOf.call( seed, matched[ i ] ); - seed[ idx ] = !( matches[ idx ] = matched[ i ] ); - } - } ) : - function( elem ) { - return fn( elem, 0, args ); - }; - } - - return fn; - } - }, - - pseudos: { - - // Potentially complex pseudos - not: markFunction( function( selector ) { - - // Trim the selector passed to compile - // to avoid treating leading and trailing - // spaces as combinators - var input = [], - results = [], - matcher = compile( selector.replace( rtrimCSS, "$1" ) ); - - return matcher[ expando ] ? - markFunction( function( seed, matches, _context, xml ) { - var elem, - unmatched = matcher( seed, null, xml, [] ), - i = seed.length; - - // Match elements unmatched by `matcher` - while ( i-- ) { - if ( ( elem = unmatched[ i ] ) ) { - seed[ i ] = !( matches[ i ] = elem ); - } - } - } ) : - function( elem, _context, xml ) { - input[ 0 ] = elem; - matcher( input, null, xml, results ); - - // Don't keep the element - // (see https://github.com/jquery/sizzle/issues/299) - input[ 0 ] = null; - return !results.pop(); - }; - } ), - - has: markFunction( function( selector ) { - return function( elem ) { - return find( selector, elem ).length > 0; - }; - } ), - - contains: markFunction( function( text ) { - text = text.replace( runescape, funescape ); - return function( elem ) { - return ( elem.textContent || jQuery.text( elem ) ).indexOf( text ) > -1; - }; - } ), - - // "Whether an element is represented by a :lang() selector - // is based solely on the element's language value - // being equal to the identifier C, - // or beginning with the identifier C immediately followed by "-". - // The matching of C against the element's language value is performed case-insensitively. - // The identifier C does not have to be a valid language name." - // https://www.w3.org/TR/selectors/#lang-pseudo - lang: markFunction( function( lang ) { - - // lang value must be a valid identifier - if ( !ridentifier.test( lang || "" ) ) { - find.error( "unsupported lang: " + lang ); - } - lang = lang.replace( runescape, funescape ).toLowerCase(); - return function( elem ) { - var elemLang; - do { - if ( ( elemLang = documentIsHTML ? - elem.lang : - elem.getAttribute( "xml:lang" ) || elem.getAttribute( "lang" ) ) ) { - - elemLang = elemLang.toLowerCase(); - return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; - } - } while ( ( elem = elem.parentNode ) && elem.nodeType === 1 ); - return false; - }; - } ), - - // Miscellaneous - target: function( elem ) { - var hash = window.location && window.location.hash; - return hash && hash.slice( 1 ) === elem.id; - }, - - root: function( elem ) { - return elem === documentElement; - }, - - focus: function( elem ) { - return elem === safeActiveElement() && - document.hasFocus() && - !!( elem.type || elem.href || ~elem.tabIndex ); - }, - - // Boolean properties - enabled: createDisabledPseudo( false ), - disabled: createDisabledPseudo( true ), - - checked: function( elem ) { - - // In CSS3, :checked should return both checked and selected elements - // https://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked - return ( nodeName( elem, "input" ) && !!elem.checked ) || - ( nodeName( elem, "option" ) && !!elem.selected ); - }, - - selected: function( elem ) { - - // Support: IE <=11+ - // Accessing the selectedIndex property - // forces the browser to treat the default option as - // selected when in an optgroup. - if ( elem.parentNode ) { - // eslint-disable-next-line no-unused-expressions - elem.parentNode.selectedIndex; - } - - return elem.selected === true; - }, - - // Contents - empty: function( elem ) { - - // https://www.w3.org/TR/selectors/#empty-pseudo - // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), - // but not by others (comment: 8; processing instruction: 7; etc.) - // nodeType < 6 works because attributes (2) do not appear as children - for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { - if ( elem.nodeType < 6 ) { - return false; - } - } - return true; - }, - - parent: function( elem ) { - return !Expr.pseudos.empty( elem ); - }, - - // Element/input types - header: function( elem ) { - return rheader.test( elem.nodeName ); - }, - - input: function( elem ) { - return rinputs.test( elem.nodeName ); - }, - - button: function( elem ) { - return nodeName( elem, "input" ) && elem.type === "button" || - nodeName( elem, "button" ); - }, - - text: function( elem ) { - var attr; - return nodeName( elem, "input" ) && elem.type === "text" && - - // Support: IE <10 only - // New HTML5 attribute values (e.g., "search") appear - // with elem.type === "text" - ( ( attr = elem.getAttribute( "type" ) ) == null || - attr.toLowerCase() === "text" ); - }, - - // Position-in-collection - first: createPositionalPseudo( function() { - return [ 0 ]; - } ), - - last: createPositionalPseudo( function( _matchIndexes, length ) { - return [ length - 1 ]; - } ), - - eq: createPositionalPseudo( function( _matchIndexes, length, argument ) { - return [ argument < 0 ? argument + length : argument ]; - } ), - - even: createPositionalPseudo( function( matchIndexes, length ) { - var i = 0; - for ( ; i < length; i += 2 ) { - matchIndexes.push( i ); - } - return matchIndexes; - } ), - - odd: createPositionalPseudo( function( matchIndexes, length ) { - var i = 1; - for ( ; i < length; i += 2 ) { - matchIndexes.push( i ); - } - return matchIndexes; - } ), - - lt: createPositionalPseudo( function( matchIndexes, length, argument ) { - var i; - - if ( argument < 0 ) { - i = argument + length; - } else if ( argument > length ) { - i = length; - } else { - i = argument; - } - - for ( ; --i >= 0; ) { - matchIndexes.push( i ); - } - return matchIndexes; - } ), - - gt: createPositionalPseudo( function( matchIndexes, length, argument ) { - var i = argument < 0 ? argument + length : argument; - for ( ; ++i < length; ) { - matchIndexes.push( i ); - } - return matchIndexes; - } ) - } -}; - -Expr.pseudos.nth = Expr.pseudos.eq; - -// Add button/input type pseudos -for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { - Expr.pseudos[ i ] = createInputPseudo( i ); -} -for ( i in { submit: true, reset: true } ) { - Expr.pseudos[ i ] = createButtonPseudo( i ); -} - -// Easy API for creating new setFilters -function setFilters() {} -setFilters.prototype = Expr.filters = Expr.pseudos; -Expr.setFilters = new setFilters(); - -function tokenize( selector, parseOnly ) { - var matched, match, tokens, type, - soFar, groups, preFilters, - cached = tokenCache[ selector + " " ]; - - if ( cached ) { - return parseOnly ? 0 : cached.slice( 0 ); - } - - soFar = selector; - groups = []; - preFilters = Expr.preFilter; - - while ( soFar ) { - - // Comma and first run - if ( !matched || ( match = rcomma.exec( soFar ) ) ) { - if ( match ) { - - // Don't consume trailing commas as valid - soFar = soFar.slice( match[ 0 ].length ) || soFar; - } - groups.push( ( tokens = [] ) ); - } - - matched = false; - - // Combinators - if ( ( match = rleadingCombinator.exec( soFar ) ) ) { - matched = match.shift(); - tokens.push( { - value: matched, - - // Cast descendant combinators to space - type: match[ 0 ].replace( rtrimCSS, " " ) - } ); - soFar = soFar.slice( matched.length ); - } - - // Filters - for ( type in Expr.filter ) { - if ( ( match = matchExpr[ type ].exec( soFar ) ) && ( !preFilters[ type ] || - ( match = preFilters[ type ]( match ) ) ) ) { - matched = match.shift(); - tokens.push( { - value: matched, - type: type, - matches: match - } ); - soFar = soFar.slice( matched.length ); - } - } - - if ( !matched ) { - break; - } - } - - // Return the length of the invalid excess - // if we're just parsing - // Otherwise, throw an error or return tokens - if ( parseOnly ) { - return soFar.length; - } - - return soFar ? - find.error( selector ) : - - // Cache the tokens - tokenCache( selector, groups ).slice( 0 ); -} - -function toSelector( tokens ) { - var i = 0, - len = tokens.length, - selector = ""; - for ( ; i < len; i++ ) { - selector += tokens[ i ].value; - } - return selector; -} - -function addCombinator( matcher, combinator, base ) { - var dir = combinator.dir, - skip = combinator.next, - key = skip || dir, - checkNonElements = base && key === "parentNode", - doneName = done++; - - return combinator.first ? - - // Check against closest ancestor/preceding element - function( elem, context, xml ) { - while ( ( elem = elem[ dir ] ) ) { - if ( elem.nodeType === 1 || checkNonElements ) { - return matcher( elem, context, xml ); - } - } - return false; - } : - - // Check against all ancestor/preceding elements - function( elem, context, xml ) { - var oldCache, outerCache, - newCache = [ dirruns, doneName ]; - - // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching - if ( xml ) { - while ( ( elem = elem[ dir ] ) ) { - if ( elem.nodeType === 1 || checkNonElements ) { - if ( matcher( elem, context, xml ) ) { - return true; - } - } - } - } else { - while ( ( elem = elem[ dir ] ) ) { - if ( elem.nodeType === 1 || checkNonElements ) { - outerCache = elem[ expando ] || ( elem[ expando ] = {} ); - - if ( skip && nodeName( elem, skip ) ) { - elem = elem[ dir ] || elem; - } else if ( ( oldCache = outerCache[ key ] ) && - oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { - - // Assign to newCache so results back-propagate to previous elements - return ( newCache[ 2 ] = oldCache[ 2 ] ); - } else { - - // Reuse newcache so results back-propagate to previous elements - outerCache[ key ] = newCache; - - // A match means we're done; a fail means we have to keep checking - if ( ( newCache[ 2 ] = matcher( elem, context, xml ) ) ) { - return true; - } - } - } - } - } - return false; - }; -} - -function elementMatcher( matchers ) { - return matchers.length > 1 ? - function( elem, context, xml ) { - var i = matchers.length; - while ( i-- ) { - if ( !matchers[ i ]( elem, context, xml ) ) { - return false; - } - } - return true; - } : - matchers[ 0 ]; -} - -function multipleContexts( selector, contexts, results ) { - var i = 0, - len = contexts.length; - for ( ; i < len; i++ ) { - find( selector, contexts[ i ], results ); - } - return results; -} - -function condense( unmatched, map, filter, context, xml ) { - var elem, - newUnmatched = [], - i = 0, - len = unmatched.length, - mapped = map != null; - - for ( ; i < len; i++ ) { - if ( ( elem = unmatched[ i ] ) ) { - if ( !filter || filter( elem, context, xml ) ) { - newUnmatched.push( elem ); - if ( mapped ) { - map.push( i ); - } - } - } - } - - return newUnmatched; -} - -function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { - if ( postFilter && !postFilter[ expando ] ) { - postFilter = setMatcher( postFilter ); - } - if ( postFinder && !postFinder[ expando ] ) { - postFinder = setMatcher( postFinder, postSelector ); - } - return markFunction( function( seed, results, context, xml ) { - var temp, i, elem, matcherOut, - preMap = [], - postMap = [], - preexisting = results.length, - - // Get initial elements from seed or context - elems = seed || - multipleContexts( selector || "*", - context.nodeType ? [ context ] : context, [] ), - - // Prefilter to get matcher input, preserving a map for seed-results synchronization - matcherIn = preFilter && ( seed || !selector ) ? - condense( elems, preMap, preFilter, context, xml ) : - elems; - - if ( matcher ) { - - // If we have a postFinder, or filtered seed, or non-seed postFilter - // or preexisting results, - matcherOut = postFinder || ( seed ? preFilter : preexisting || postFilter ) ? - - // ...intermediate processing is necessary - [] : - - // ...otherwise use results directly - results; - - // Find primary matches - matcher( matcherIn, matcherOut, context, xml ); - } else { - matcherOut = matcherIn; - } - - // Apply postFilter - if ( postFilter ) { - temp = condense( matcherOut, postMap ); - postFilter( temp, [], context, xml ); - - // Un-match failing elements by moving them back to matcherIn - i = temp.length; - while ( i-- ) { - if ( ( elem = temp[ i ] ) ) { - matcherOut[ postMap[ i ] ] = !( matcherIn[ postMap[ i ] ] = elem ); - } - } - } - - if ( seed ) { - if ( postFinder || preFilter ) { - if ( postFinder ) { - - // Get the final matcherOut by condensing this intermediate into postFinder contexts - temp = []; - i = matcherOut.length; - while ( i-- ) { - if ( ( elem = matcherOut[ i ] ) ) { - - // Restore matcherIn since elem is not yet a final match - temp.push( ( matcherIn[ i ] = elem ) ); - } - } - postFinder( null, ( matcherOut = [] ), temp, xml ); - } - - // Move matched elements from seed to results to keep them synchronized - i = matcherOut.length; - while ( i-- ) { - if ( ( elem = matcherOut[ i ] ) && - ( temp = postFinder ? indexOf.call( seed, elem ) : preMap[ i ] ) > -1 ) { - - seed[ temp ] = !( results[ temp ] = elem ); - } - } - } - - // Add elements to results, through postFinder if defined - } else { - matcherOut = condense( - matcherOut === results ? - matcherOut.splice( preexisting, matcherOut.length ) : - matcherOut - ); - if ( postFinder ) { - postFinder( null, results, matcherOut, xml ); - } else { - push.apply( results, matcherOut ); - } - } - } ); -} - -function matcherFromTokens( tokens ) { - var checkContext, matcher, j, - len = tokens.length, - leadingRelative = Expr.relative[ tokens[ 0 ].type ], - implicitRelative = leadingRelative || Expr.relative[ " " ], - i = leadingRelative ? 1 : 0, - - // The foundational matcher ensures that elements are reachable from top-level context(s) - matchContext = addCombinator( function( elem ) { - return elem === checkContext; - }, implicitRelative, true ), - matchAnyContext = addCombinator( function( elem ) { - return indexOf.call( checkContext, elem ) > -1; - }, implicitRelative, true ), - matchers = [ function( elem, context, xml ) { - - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - var ret = ( !leadingRelative && ( xml || context != outermostContext ) ) || ( - ( checkContext = context ).nodeType ? - matchContext( elem, context, xml ) : - matchAnyContext( elem, context, xml ) ); - - // Avoid hanging onto element - // (see https://github.com/jquery/sizzle/issues/299) - checkContext = null; - return ret; - } ]; - - for ( ; i < len; i++ ) { - if ( ( matcher = Expr.relative[ tokens[ i ].type ] ) ) { - matchers = [ addCombinator( elementMatcher( matchers ), matcher ) ]; - } else { - matcher = Expr.filter[ tokens[ i ].type ].apply( null, tokens[ i ].matches ); - - // Return special upon seeing a positional matcher - if ( matcher[ expando ] ) { - - // Find the next relative operator (if any) for proper handling - j = ++i; - for ( ; j < len; j++ ) { - if ( Expr.relative[ tokens[ j ].type ] ) { - break; - } - } - return setMatcher( - i > 1 && elementMatcher( matchers ), - i > 1 && toSelector( - - // If the preceding token was a descendant combinator, insert an implicit any-element `*` - tokens.slice( 0, i - 1 ) - .concat( { value: tokens[ i - 2 ].type === " " ? "*" : "" } ) - ).replace( rtrimCSS, "$1" ), - matcher, - i < j && matcherFromTokens( tokens.slice( i, j ) ), - j < len && matcherFromTokens( ( tokens = tokens.slice( j ) ) ), - j < len && toSelector( tokens ) - ); - } - matchers.push( matcher ); - } - } - - return elementMatcher( matchers ); -} - -function matcherFromGroupMatchers( elementMatchers, setMatchers ) { - var bySet = setMatchers.length > 0, - byElement = elementMatchers.length > 0, - superMatcher = function( seed, context, xml, results, outermost ) { - var elem, j, matcher, - matchedCount = 0, - i = "0", - unmatched = seed && [], - setMatched = [], - contextBackup = outermostContext, - - // We must always have either seed elements or outermost context - elems = seed || byElement && Expr.find.TAG( "*", outermost ), - - // Use integer dirruns iff this is the outermost matcher - dirrunsUnique = ( dirruns += contextBackup == null ? 1 : Math.random() || 0.1 ), - len = elems.length; - - if ( outermost ) { - - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - outermostContext = context == document || context || outermost; - } - - // Add elements passing elementMatchers directly to results - // Support: iOS <=7 - 9 only - // Tolerate NodeList properties (IE: "length"; Safari: ) matching - // elements by id. (see trac-14142) - for ( ; i !== len && ( elem = elems[ i ] ) != null; i++ ) { - if ( byElement && elem ) { - j = 0; - - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - if ( !context && elem.ownerDocument != document ) { - setDocument( elem ); - xml = !documentIsHTML; - } - while ( ( matcher = elementMatchers[ j++ ] ) ) { - if ( matcher( elem, context || document, xml ) ) { - push.call( results, elem ); - break; - } - } - if ( outermost ) { - dirruns = dirrunsUnique; - } - } - - // Track unmatched elements for set filters - if ( bySet ) { - - // They will have gone through all possible matchers - if ( ( elem = !matcher && elem ) ) { - matchedCount--; - } - - // Lengthen the array for every element, matched or not - if ( seed ) { - unmatched.push( elem ); - } - } - } - - // `i` is now the count of elements visited above, and adding it to `matchedCount` - // makes the latter nonnegative. - matchedCount += i; - - // Apply set filters to unmatched elements - // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount` - // equals `i`), unless we didn't visit _any_ elements in the above loop because we have - // no element matchers and no seed. - // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that - // case, which will result in a "00" `matchedCount` that differs from `i` but is also - // numerically zero. - if ( bySet && i !== matchedCount ) { - j = 0; - while ( ( matcher = setMatchers[ j++ ] ) ) { - matcher( unmatched, setMatched, context, xml ); - } - - if ( seed ) { - - // Reintegrate element matches to eliminate the need for sorting - if ( matchedCount > 0 ) { - while ( i-- ) { - if ( !( unmatched[ i ] || setMatched[ i ] ) ) { - setMatched[ i ] = pop.call( results ); - } - } - } - - // Discard index placeholder values to get only actual matches - setMatched = condense( setMatched ); - } - - // Add matches to results - push.apply( results, setMatched ); - - // Seedless set matches succeeding multiple successful matchers stipulate sorting - if ( outermost && !seed && setMatched.length > 0 && - ( matchedCount + setMatchers.length ) > 1 ) { - - jQuery.uniqueSort( results ); - } - } - - // Override manipulation of globals by nested matchers - if ( outermost ) { - dirruns = dirrunsUnique; - outermostContext = contextBackup; - } - - return unmatched; - }; - - return bySet ? - markFunction( superMatcher ) : - superMatcher; -} - -function compile( selector, match /* Internal Use Only */ ) { - var i, - setMatchers = [], - elementMatchers = [], - cached = compilerCache[ selector + " " ]; - - if ( !cached ) { - - // Generate a function of recursive functions that can be used to check each element - if ( !match ) { - match = tokenize( selector ); - } - i = match.length; - while ( i-- ) { - cached = matcherFromTokens( match[ i ] ); - if ( cached[ expando ] ) { - setMatchers.push( cached ); - } else { - elementMatchers.push( cached ); - } - } - - // Cache the compiled function - cached = compilerCache( selector, - matcherFromGroupMatchers( elementMatchers, setMatchers ) ); - - // Save selector and tokenization - cached.selector = selector; - } - return cached; -} - -/** - * A low-level selection function that works with jQuery's compiled - * selector functions - * @param {String|Function} selector A selector or a pre-compiled - * selector function built with jQuery selector compile - * @param {Element} context - * @param {Array} [results] - * @param {Array} [seed] A set of elements to match against - */ -function select( selector, context, results, seed ) { - var i, tokens, token, type, find, - compiled = typeof selector === "function" && selector, - match = !seed && tokenize( ( selector = compiled.selector || selector ) ); - - results = results || []; - - // Try to minimize operations if there is only one selector in the list and no seed - // (the latter of which guarantees us context) - if ( match.length === 1 ) { - - // Reduce context if the leading compound selector is an ID - tokens = match[ 0 ] = match[ 0 ].slice( 0 ); - if ( tokens.length > 2 && ( token = tokens[ 0 ] ).type === "ID" && - context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[ 1 ].type ] ) { - - context = ( Expr.find.ID( - token.matches[ 0 ].replace( runescape, funescape ), - context - ) || [] )[ 0 ]; - if ( !context ) { - return results; - - // Precompiled matchers will still verify ancestry, so step up a level - } else if ( compiled ) { - context = context.parentNode; - } - - selector = selector.slice( tokens.shift().value.length ); - } - - // Fetch a seed set for right-to-left matching - i = matchExpr.needsContext.test( selector ) ? 0 : tokens.length; - while ( i-- ) { - token = tokens[ i ]; - - // Abort if we hit a combinator - if ( Expr.relative[ ( type = token.type ) ] ) { - break; - } - if ( ( find = Expr.find[ type ] ) ) { - - // Search, expanding context for leading sibling combinators - if ( ( seed = find( - token.matches[ 0 ].replace( runescape, funescape ), - rsibling.test( tokens[ 0 ].type ) && - testContext( context.parentNode ) || context - ) ) ) { - - // If seed is empty or no tokens remain, we can return early - tokens.splice( i, 1 ); - selector = seed.length && toSelector( tokens ); - if ( !selector ) { - push.apply( results, seed ); - return results; - } - - break; - } - } - } - } - - // Compile and execute a filtering function if one is not provided - // Provide `match` to avoid retokenization if we modified the selector above - ( compiled || compile( selector, match ) )( - seed, - context, - !documentIsHTML, - results, - !context || rsibling.test( selector ) && testContext( context.parentNode ) || context - ); - return results; -} - -// One-time assignments - -// Support: Android <=4.0 - 4.1+ -// Sort stability -support.sortStable = expando.split( "" ).sort( sortOrder ).join( "" ) === expando; - -// Initialize against the default document -setDocument(); - -// Support: Android <=4.0 - 4.1+ -// Detached nodes confoundingly follow *each other* -support.sortDetached = assert( function( el ) { - - // Should return 1, but returns 4 (following) - return el.compareDocumentPosition( document.createElement( "fieldset" ) ) & 1; -} ); - -jQuery.find = find; - -// Deprecated -jQuery.expr[ ":" ] = jQuery.expr.pseudos; -jQuery.unique = jQuery.uniqueSort; - -// These have always been private, but they used to be documented as part of -// Sizzle so let's maintain them for now for backwards compatibility purposes. -find.compile = compile; -find.select = select; -find.setDocument = setDocument; -find.tokenize = tokenize; - -find.escape = jQuery.escapeSelector; -find.getText = jQuery.text; -find.isXML = jQuery.isXMLDoc; -find.selectors = jQuery.expr; -find.support = jQuery.support; -find.uniqueSort = jQuery.uniqueSort; - - /* eslint-enable */ - -} )(); - - -var dir = function( elem, dir, until ) { - var matched = [], - truncate = until !== undefined; - - while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) { - if ( elem.nodeType === 1 ) { - if ( truncate && jQuery( elem ).is( until ) ) { - break; - } - matched.push( elem ); - } - } - return matched; -}; - - -var siblings = function( n, elem ) { - var matched = []; - - for ( ; n; n = n.nextSibling ) { - if ( n.nodeType === 1 && n !== elem ) { - matched.push( n ); - } - } - - return matched; -}; - - -var rneedsContext = jQuery.expr.match.needsContext; - -var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i ); - - - -// Implement the identical functionality for filter and not -function winnow( elements, qualifier, not ) { - if ( isFunction( qualifier ) ) { - return jQuery.grep( elements, function( elem, i ) { - return !!qualifier.call( elem, i, elem ) !== not; - } ); - } - - // Single element - if ( qualifier.nodeType ) { - return jQuery.grep( elements, function( elem ) { - return ( elem === qualifier ) !== not; - } ); - } - - // Arraylike of elements (jQuery, arguments, Array) - if ( typeof qualifier !== "string" ) { - return jQuery.grep( elements, function( elem ) { - return ( indexOf.call( qualifier, elem ) > -1 ) !== not; - } ); - } - - // Filtered directly for both simple and complex selectors - return jQuery.filter( qualifier, elements, not ); -} - -jQuery.filter = function( expr, elems, not ) { - var elem = elems[ 0 ]; - - if ( not ) { - expr = ":not(" + expr + ")"; - } - - if ( elems.length === 1 && elem.nodeType === 1 ) { - return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : []; - } - - return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { - return elem.nodeType === 1; - } ) ); -}; - -jQuery.fn.extend( { - find: function( selector ) { - var i, ret, - len = this.length, - self = this; - - if ( typeof selector !== "string" ) { - return this.pushStack( jQuery( selector ).filter( function() { - for ( i = 0; i < len; i++ ) { - if ( jQuery.contains( self[ i ], this ) ) { - return true; - } - } - } ) ); - } - - ret = this.pushStack( [] ); - - for ( i = 0; i < len; i++ ) { - jQuery.find( selector, self[ i ], ret ); - } - - return len > 1 ? jQuery.uniqueSort( ret ) : ret; - }, - filter: function( selector ) { - return this.pushStack( winnow( this, selector || [], false ) ); - }, - not: function( selector ) { - return this.pushStack( winnow( this, selector || [], true ) ); - }, - is: function( selector ) { - return !!winnow( - this, - - // If this is a positional/relative selector, check membership in the returned set - // so $("p:first").is("p:last") won't return true for a doc with two "p". - typeof selector === "string" && rneedsContext.test( selector ) ? - jQuery( selector ) : - selector || [], - false - ).length; - } -} ); - - -// Initialize a jQuery object - - -// A central reference to the root jQuery(document) -var rootjQuery, - - // A simple way to check for HTML strings - // Prioritize #id over to avoid XSS via location.hash (trac-9521) - // Strict HTML recognition (trac-11290: must start with <) - // Shortcut simple #id case for speed - rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, - - init = jQuery.fn.init = function( selector, context, root ) { - var match, elem; - - // HANDLE: $(""), $(null), $(undefined), $(false) - if ( !selector ) { - return this; - } - - // Method init() accepts an alternate rootjQuery - // so migrate can support jQuery.sub (gh-2101) - root = root || rootjQuery; - - // Handle HTML strings - if ( typeof selector === "string" ) { - if ( selector[ 0 ] === "<" && - selector[ selector.length - 1 ] === ">" && - selector.length >= 3 ) { - - // Assume that strings that start and end with <> are HTML and skip the regex check - match = [ null, selector, null ]; - - } else { - match = rquickExpr.exec( selector ); - } - - // Match html or make sure no context is specified for #id - if ( match && ( match[ 1 ] || !context ) ) { - - // HANDLE: $(html) -> $(array) - if ( match[ 1 ] ) { - context = context instanceof jQuery ? context[ 0 ] : context; - - // Option to run scripts is true for back-compat - // Intentionally let the error be thrown if parseHTML is not present - jQuery.merge( this, jQuery.parseHTML( - match[ 1 ], - context && context.nodeType ? context.ownerDocument || context : document, - true - ) ); - - // HANDLE: $(html, props) - if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) { - for ( match in context ) { - - // Properties of context are called as methods if possible - if ( isFunction( this[ match ] ) ) { - this[ match ]( context[ match ] ); - - // ...and otherwise set as attributes - } else { - this.attr( match, context[ match ] ); - } - } - } - - return this; - - // HANDLE: $(#id) - } else { - elem = document.getElementById( match[ 2 ] ); - - if ( elem ) { - - // Inject the element directly into the jQuery object - this[ 0 ] = elem; - this.length = 1; - } - return this; - } - - // HANDLE: $(expr, $(...)) - } else if ( !context || context.jquery ) { - return ( context || root ).find( selector ); - - // HANDLE: $(expr, context) - // (which is just equivalent to: $(context).find(expr) - } else { - return this.constructor( context ).find( selector ); - } - - // HANDLE: $(DOMElement) - } else if ( selector.nodeType ) { - this[ 0 ] = selector; - this.length = 1; - return this; - - // HANDLE: $(function) - // Shortcut for document ready - } else if ( isFunction( selector ) ) { - return root.ready !== undefined ? - root.ready( selector ) : - - // Execute immediately if ready is not present - selector( jQuery ); - } - - return jQuery.makeArray( selector, this ); - }; - -// Give the init function the jQuery prototype for later instantiation -init.prototype = jQuery.fn; - -// Initialize central reference -rootjQuery = jQuery( document ); - - -var rparentsprev = /^(?:parents|prev(?:Until|All))/, - - // Methods guaranteed to produce a unique set when starting from a unique set - guaranteedUnique = { - children: true, - contents: true, - next: true, - prev: true - }; - -jQuery.fn.extend( { - has: function( target ) { - var targets = jQuery( target, this ), - l = targets.length; - - return this.filter( function() { - var i = 0; - for ( ; i < l; i++ ) { - if ( jQuery.contains( this, targets[ i ] ) ) { - return true; - } - } - } ); - }, - - closest: function( selectors, context ) { - var cur, - i = 0, - l = this.length, - matched = [], - targets = typeof selectors !== "string" && jQuery( selectors ); - - // Positional selectors never match, since there's no _selection_ context - if ( !rneedsContext.test( selectors ) ) { - for ( ; i < l; i++ ) { - for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) { - - // Always skip document fragments - if ( cur.nodeType < 11 && ( targets ? - targets.index( cur ) > -1 : - - // Don't pass non-elements to jQuery#find - cur.nodeType === 1 && - jQuery.find.matchesSelector( cur, selectors ) ) ) { - - matched.push( cur ); - break; - } - } - } - } - - return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched ); - }, - - // Determine the position of an element within the set - index: function( elem ) { - - // No argument, return index in parent - if ( !elem ) { - return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; - } - - // Index in selector - if ( typeof elem === "string" ) { - return indexOf.call( jQuery( elem ), this[ 0 ] ); - } - - // Locate the position of the desired element - return indexOf.call( this, - - // If it receives a jQuery object, the first element is used - elem.jquery ? elem[ 0 ] : elem - ); - }, - - add: function( selector, context ) { - return this.pushStack( - jQuery.uniqueSort( - jQuery.merge( this.get(), jQuery( selector, context ) ) - ) - ); - }, - - addBack: function( selector ) { - return this.add( selector == null ? - this.prevObject : this.prevObject.filter( selector ) - ); - } -} ); - -function sibling( cur, dir ) { - while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {} - return cur; -} - -jQuery.each( { - parent: function( elem ) { - var parent = elem.parentNode; - return parent && parent.nodeType !== 11 ? parent : null; - }, - parents: function( elem ) { - return dir( elem, "parentNode" ); - }, - parentsUntil: function( elem, _i, until ) { - return dir( elem, "parentNode", until ); - }, - next: function( elem ) { - return sibling( elem, "nextSibling" ); - }, - prev: function( elem ) { - return sibling( elem, "previousSibling" ); - }, - nextAll: function( elem ) { - return dir( elem, "nextSibling" ); - }, - prevAll: function( elem ) { - return dir( elem, "previousSibling" ); - }, - nextUntil: function( elem, _i, until ) { - return dir( elem, "nextSibling", until ); - }, - prevUntil: function( elem, _i, until ) { - return dir( elem, "previousSibling", until ); - }, - siblings: function( elem ) { - return siblings( ( elem.parentNode || {} ).firstChild, elem ); - }, - children: function( elem ) { - return siblings( elem.firstChild ); - }, - contents: function( elem ) { - if ( elem.contentDocument != null && - - // Support: IE 11+ - // elements with no `data` attribute has an object - // `contentDocument` with a `null` prototype. - getProto( elem.contentDocument ) ) { - - return elem.contentDocument; - } - - // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only - // Treat the template element as a regular one in browsers that - // don't support it. - if ( nodeName( elem, "template" ) ) { - elem = elem.content || elem; - } - - return jQuery.merge( [], elem.childNodes ); - } -}, function( name, fn ) { - jQuery.fn[ name ] = function( until, selector ) { - var matched = jQuery.map( this, fn, until ); - - if ( name.slice( -5 ) !== "Until" ) { - selector = until; - } - - if ( selector && typeof selector === "string" ) { - matched = jQuery.filter( selector, matched ); - } - - if ( this.length > 1 ) { - - // Remove duplicates - if ( !guaranteedUnique[ name ] ) { - jQuery.uniqueSort( matched ); - } - - // Reverse order for parents* and prev-derivatives - if ( rparentsprev.test( name ) ) { - matched.reverse(); - } - } - - return this.pushStack( matched ); - }; -} ); -var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g ); - - - -// Convert String-formatted options into Object-formatted ones -function createOptions( options ) { - var object = {}; - jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) { - object[ flag ] = true; - } ); - return object; -} - -/* - * Create a callback list using the following parameters: - * - * options: an optional list of space-separated options that will change how - * the callback list behaves or a more traditional option object - * - * By default a callback list will act like an event callback list and can be - * "fired" multiple times. - * - * Possible options: - * - * once: will ensure the callback list can only be fired once (like a Deferred) - * - * memory: will keep track of previous values and will call any callback added - * after the list has been fired right away with the latest "memorized" - * values (like a Deferred) - * - * unique: will ensure a callback can only be added once (no duplicate in the list) - * - * stopOnFalse: interrupt callings when a callback returns false - * - */ -jQuery.Callbacks = function( options ) { - - // Convert options from String-formatted to Object-formatted if needed - // (we check in cache first) - options = typeof options === "string" ? - createOptions( options ) : - jQuery.extend( {}, options ); - - var // Flag to know if list is currently firing - firing, - - // Last fire value for non-forgettable lists - memory, - - // Flag to know if list was already fired - fired, - - // Flag to prevent firing - locked, - - // Actual callback list - list = [], - - // Queue of execution data for repeatable lists - queue = [], - - // Index of currently firing callback (modified by add/remove as needed) - firingIndex = -1, - - // Fire callbacks - fire = function() { - - // Enforce single-firing - locked = locked || options.once; - - // Execute callbacks for all pending executions, - // respecting firingIndex overrides and runtime changes - fired = firing = true; - for ( ; queue.length; firingIndex = -1 ) { - memory = queue.shift(); - while ( ++firingIndex < list.length ) { - - // Run callback and check for early termination - if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && - options.stopOnFalse ) { - - // Jump to end and forget the data so .add doesn't re-fire - firingIndex = list.length; - memory = false; - } - } - } - - // Forget the data if we're done with it - if ( !options.memory ) { - memory = false; - } - - firing = false; - - // Clean up if we're done firing for good - if ( locked ) { - - // Keep an empty list if we have data for future add calls - if ( memory ) { - list = []; - - // Otherwise, this object is spent - } else { - list = ""; - } - } - }, - - // Actual Callbacks object - self = { - - // Add a callback or a collection of callbacks to the list - add: function() { - if ( list ) { - - // If we have memory from a past run, we should fire after adding - if ( memory && !firing ) { - firingIndex = list.length - 1; - queue.push( memory ); - } - - ( function add( args ) { - jQuery.each( args, function( _, arg ) { - if ( isFunction( arg ) ) { - if ( !options.unique || !self.has( arg ) ) { - list.push( arg ); - } - } else if ( arg && arg.length && toType( arg ) !== "string" ) { - - // Inspect recursively - add( arg ); - } - } ); - } )( arguments ); - - if ( memory && !firing ) { - fire(); - } - } - return this; - }, - - // Remove a callback from the list - remove: function() { - jQuery.each( arguments, function( _, arg ) { - var index; - while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { - list.splice( index, 1 ); - - // Handle firing indexes - if ( index <= firingIndex ) { - firingIndex--; - } - } - } ); - return this; - }, - - // Check if a given callback is in the list. - // If no argument is given, return whether or not list has callbacks attached. - has: function( fn ) { - return fn ? - jQuery.inArray( fn, list ) > -1 : - list.length > 0; - }, - - // Remove all callbacks from the list - empty: function() { - if ( list ) { - list = []; - } - return this; - }, - - // Disable .fire and .add - // Abort any current/pending executions - // Clear all callbacks and values - disable: function() { - locked = queue = []; - list = memory = ""; - return this; - }, - disabled: function() { - return !list; - }, - - // Disable .fire - // Also disable .add unless we have memory (since it would have no effect) - // Abort any pending executions - lock: function() { - locked = queue = []; - if ( !memory && !firing ) { - list = memory = ""; - } - return this; - }, - locked: function() { - return !!locked; - }, - - // Call all callbacks with the given context and arguments - fireWith: function( context, args ) { - if ( !locked ) { - args = args || []; - args = [ context, args.slice ? args.slice() : args ]; - queue.push( args ); - if ( !firing ) { - fire(); - } - } - return this; - }, - - // Call all the callbacks with the given arguments - fire: function() { - self.fireWith( this, arguments ); - return this; - }, - - // To know if the callbacks have already been called at least once - fired: function() { - return !!fired; - } - }; - - return self; -}; - - -function Identity( v ) { - return v; -} -function Thrower( ex ) { - throw ex; -} - -function adoptValue( value, resolve, reject, noValue ) { - var method; - - try { - - // Check for promise aspect first to privilege synchronous behavior - if ( value && isFunction( ( method = value.promise ) ) ) { - method.call( value ).done( resolve ).fail( reject ); - - // Other thenables - } else if ( value && isFunction( ( method = value.then ) ) ) { - method.call( value, resolve, reject ); - - // Other non-thenables - } else { - - // Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer: - // * false: [ value ].slice( 0 ) => resolve( value ) - // * true: [ value ].slice( 1 ) => resolve() - resolve.apply( undefined, [ value ].slice( noValue ) ); - } - - // For Promises/A+, convert exceptions into rejections - // Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in - // Deferred#then to conditionally suppress rejection. - } catch ( value ) { - - // Support: Android 4.0 only - // Strict mode functions invoked without .call/.apply get global-object context - reject.apply( undefined, [ value ] ); - } -} - -jQuery.extend( { - - Deferred: function( func ) { - var tuples = [ - - // action, add listener, callbacks, - // ... .then handlers, argument index, [final state] - [ "notify", "progress", jQuery.Callbacks( "memory" ), - jQuery.Callbacks( "memory" ), 2 ], - [ "resolve", "done", jQuery.Callbacks( "once memory" ), - jQuery.Callbacks( "once memory" ), 0, "resolved" ], - [ "reject", "fail", jQuery.Callbacks( "once memory" ), - jQuery.Callbacks( "once memory" ), 1, "rejected" ] - ], - state = "pending", - promise = { - state: function() { - return state; - }, - always: function() { - deferred.done( arguments ).fail( arguments ); - return this; - }, - "catch": function( fn ) { - return promise.then( null, fn ); - }, - - // Keep pipe for back-compat - pipe: function( /* fnDone, fnFail, fnProgress */ ) { - var fns = arguments; - - return jQuery.Deferred( function( newDefer ) { - jQuery.each( tuples, function( _i, tuple ) { - - // Map tuples (progress, done, fail) to arguments (done, fail, progress) - var fn = isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ]; - - // deferred.progress(function() { bind to newDefer or newDefer.notify }) - // deferred.done(function() { bind to newDefer or newDefer.resolve }) - // deferred.fail(function() { bind to newDefer or newDefer.reject }) - deferred[ tuple[ 1 ] ]( function() { - var returned = fn && fn.apply( this, arguments ); - if ( returned && isFunction( returned.promise ) ) { - returned.promise() - .progress( newDefer.notify ) - .done( newDefer.resolve ) - .fail( newDefer.reject ); - } else { - newDefer[ tuple[ 0 ] + "With" ]( - this, - fn ? [ returned ] : arguments - ); - } - } ); - } ); - fns = null; - } ).promise(); - }, - then: function( onFulfilled, onRejected, onProgress ) { - var maxDepth = 0; - function resolve( depth, deferred, handler, special ) { - return function() { - var that = this, - args = arguments, - mightThrow = function() { - var returned, then; - - // Support: Promises/A+ section 2.3.3.3.3 - // https://promisesaplus.com/#point-59 - // Ignore double-resolution attempts - if ( depth < maxDepth ) { - return; - } - - returned = handler.apply( that, args ); - - // Support: Promises/A+ section 2.3.1 - // https://promisesaplus.com/#point-48 - if ( returned === deferred.promise() ) { - throw new TypeError( "Thenable self-resolution" ); - } - - // Support: Promises/A+ sections 2.3.3.1, 3.5 - // https://promisesaplus.com/#point-54 - // https://promisesaplus.com/#point-75 - // Retrieve `then` only once - then = returned && - - // Support: Promises/A+ section 2.3.4 - // https://promisesaplus.com/#point-64 - // Only check objects and functions for thenability - ( typeof returned === "object" || - typeof returned === "function" ) && - returned.then; - - // Handle a returned thenable - if ( isFunction( then ) ) { - - // Special processors (notify) just wait for resolution - if ( special ) { - then.call( - returned, - resolve( maxDepth, deferred, Identity, special ), - resolve( maxDepth, deferred, Thrower, special ) - ); - - // Normal processors (resolve) also hook into progress - } else { - - // ...and disregard older resolution values - maxDepth++; - - then.call( - returned, - resolve( maxDepth, deferred, Identity, special ), - resolve( maxDepth, deferred, Thrower, special ), - resolve( maxDepth, deferred, Identity, - deferred.notifyWith ) - ); - } - - // Handle all other returned values - } else { - - // Only substitute handlers pass on context - // and multiple values (non-spec behavior) - if ( handler !== Identity ) { - that = undefined; - args = [ returned ]; - } - - // Process the value(s) - // Default process is resolve - ( special || deferred.resolveWith )( that, args ); - } - }, - - // Only normal processors (resolve) catch and reject exceptions - process = special ? - mightThrow : - function() { - try { - mightThrow(); - } catch ( e ) { - - if ( jQuery.Deferred.exceptionHook ) { - jQuery.Deferred.exceptionHook( e, - process.error ); - } - - // Support: Promises/A+ section 2.3.3.3.4.1 - // https://promisesaplus.com/#point-61 - // Ignore post-resolution exceptions - if ( depth + 1 >= maxDepth ) { - - // Only substitute handlers pass on context - // and multiple values (non-spec behavior) - if ( handler !== Thrower ) { - that = undefined; - args = [ e ]; - } - - deferred.rejectWith( that, args ); - } - } - }; - - // Support: Promises/A+ section 2.3.3.3.1 - // https://promisesaplus.com/#point-57 - // Re-resolve promises immediately to dodge false rejection from - // subsequent errors - if ( depth ) { - process(); - } else { - - // Call an optional hook to record the error, in case of exception - // since it's otherwise lost when execution goes async - if ( jQuery.Deferred.getErrorHook ) { - process.error = jQuery.Deferred.getErrorHook(); - - // The deprecated alias of the above. While the name suggests - // returning the stack, not an error instance, jQuery just passes - // it directly to `console.warn` so both will work; an instance - // just better cooperates with source maps. - } else if ( jQuery.Deferred.getStackHook ) { - process.error = jQuery.Deferred.getStackHook(); - } - window.setTimeout( process ); - } - }; - } - - return jQuery.Deferred( function( newDefer ) { - - // progress_handlers.add( ... ) - tuples[ 0 ][ 3 ].add( - resolve( - 0, - newDefer, - isFunction( onProgress ) ? - onProgress : - Identity, - newDefer.notifyWith - ) - ); - - // fulfilled_handlers.add( ... ) - tuples[ 1 ][ 3 ].add( - resolve( - 0, - newDefer, - isFunction( onFulfilled ) ? - onFulfilled : - Identity - ) - ); - - // rejected_handlers.add( ... ) - tuples[ 2 ][ 3 ].add( - resolve( - 0, - newDefer, - isFunction( onRejected ) ? - onRejected : - Thrower - ) - ); - } ).promise(); - }, - - // Get a promise for this deferred - // If obj is provided, the promise aspect is added to the object - promise: function( obj ) { - return obj != null ? jQuery.extend( obj, promise ) : promise; - } - }, - deferred = {}; - - // Add list-specific methods - jQuery.each( tuples, function( i, tuple ) { - var list = tuple[ 2 ], - stateString = tuple[ 5 ]; - - // promise.progress = list.add - // promise.done = list.add - // promise.fail = list.add - promise[ tuple[ 1 ] ] = list.add; - - // Handle state - if ( stateString ) { - list.add( - function() { - - // state = "resolved" (i.e., fulfilled) - // state = "rejected" - state = stateString; - }, - - // rejected_callbacks.disable - // fulfilled_callbacks.disable - tuples[ 3 - i ][ 2 ].disable, - - // rejected_handlers.disable - // fulfilled_handlers.disable - tuples[ 3 - i ][ 3 ].disable, - - // progress_callbacks.lock - tuples[ 0 ][ 2 ].lock, - - // progress_handlers.lock - tuples[ 0 ][ 3 ].lock - ); - } - - // progress_handlers.fire - // fulfilled_handlers.fire - // rejected_handlers.fire - list.add( tuple[ 3 ].fire ); - - // deferred.notify = function() { deferred.notifyWith(...) } - // deferred.resolve = function() { deferred.resolveWith(...) } - // deferred.reject = function() { deferred.rejectWith(...) } - deferred[ tuple[ 0 ] ] = function() { - deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments ); - return this; - }; - - // deferred.notifyWith = list.fireWith - // deferred.resolveWith = list.fireWith - // deferred.rejectWith = list.fireWith - deferred[ tuple[ 0 ] + "With" ] = list.fireWith; - } ); - - // Make the deferred a promise - promise.promise( deferred ); - - // Call given func if any - if ( func ) { - func.call( deferred, deferred ); - } - - // All done! - return deferred; - }, - - // Deferred helper - when: function( singleValue ) { - var - - // count of uncompleted subordinates - remaining = arguments.length, - - // count of unprocessed arguments - i = remaining, - - // subordinate fulfillment data - resolveContexts = Array( i ), - resolveValues = slice.call( arguments ), - - // the primary Deferred - primary = jQuery.Deferred(), - - // subordinate callback factory - updateFunc = function( i ) { - return function( value ) { - resolveContexts[ i ] = this; - resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; - if ( !( --remaining ) ) { - primary.resolveWith( resolveContexts, resolveValues ); - } - }; - }; - - // Single- and empty arguments are adopted like Promise.resolve - if ( remaining <= 1 ) { - adoptValue( singleValue, primary.done( updateFunc( i ) ).resolve, primary.reject, - !remaining ); - - // Use .then() to unwrap secondary thenables (cf. gh-3000) - if ( primary.state() === "pending" || - isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { - - return primary.then(); - } - } - - // Multiple arguments are aggregated like Promise.all array elements - while ( i-- ) { - adoptValue( resolveValues[ i ], updateFunc( i ), primary.reject ); - } - - return primary.promise(); - } -} ); - - -// These usually indicate a programmer mistake during development, -// warn about them ASAP rather than swallowing them by default. -var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/; - -// If `jQuery.Deferred.getErrorHook` is defined, `asyncError` is an error -// captured before the async barrier to get the original error cause -// which may otherwise be hidden. -jQuery.Deferred.exceptionHook = function( error, asyncError ) { - - // Support: IE 8 - 9 only - // Console exists when dev tools are open, which can happen at any time - if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) { - window.console.warn( "jQuery.Deferred exception: " + error.message, - error.stack, asyncError ); - } -}; - - - - -jQuery.readyException = function( error ) { - window.setTimeout( function() { - throw error; - } ); -}; - - - - -// The deferred used on DOM ready -var readyList = jQuery.Deferred(); - -jQuery.fn.ready = function( fn ) { - - readyList - .then( fn ) - - // Wrap jQuery.readyException in a function so that the lookup - // happens at the time of error handling instead of callback - // registration. - .catch( function( error ) { - jQuery.readyException( error ); - } ); - - return this; -}; - -jQuery.extend( { - - // Is the DOM ready to be used? Set to true once it occurs. - isReady: false, - - // A counter to track how many items to wait for before - // the ready event fires. See trac-6781 - readyWait: 1, - - // Handle when the DOM is ready - ready: function( wait ) { - - // Abort if there are pending holds or we're already ready - if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { - return; - } - - // Remember that the DOM is ready - jQuery.isReady = true; - - // If a normal DOM Ready event fired, decrement, and wait if need be - if ( wait !== true && --jQuery.readyWait > 0 ) { - return; - } - - // If there are functions bound, to execute - readyList.resolveWith( document, [ jQuery ] ); - } -} ); - -jQuery.ready.then = readyList.then; - -// The ready event handler and self cleanup method -function completed() { - document.removeEventListener( "DOMContentLoaded", completed ); - window.removeEventListener( "load", completed ); - jQuery.ready(); -} - -// Catch cases where $(document).ready() is called -// after the browser event has already occurred. -// Support: IE <=9 - 10 only -// Older IE sometimes signals "interactive" too soon -if ( document.readyState === "complete" || - ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { - - // Handle it asynchronously to allow scripts the opportunity to delay ready - window.setTimeout( jQuery.ready ); - -} else { - - // Use the handy event callback - document.addEventListener( "DOMContentLoaded", completed ); - - // A fallback to window.onload, that will always work - window.addEventListener( "load", completed ); -} - - - - -// Multifunctional method to get and set values of a collection -// The value/s can optionally be executed if it's a function -var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { - var i = 0, - len = elems.length, - bulk = key == null; - - // Sets many values - if ( toType( key ) === "object" ) { - chainable = true; - for ( i in key ) { - access( elems, fn, i, key[ i ], true, emptyGet, raw ); - } - - // Sets one value - } else if ( value !== undefined ) { - chainable = true; - - if ( !isFunction( value ) ) { - raw = true; - } - - if ( bulk ) { - - // Bulk operations run against the entire set - if ( raw ) { - fn.call( elems, value ); - fn = null; - - // ...except when executing function values - } else { - bulk = fn; - fn = function( elem, _key, value ) { - return bulk.call( jQuery( elem ), value ); - }; - } - } - - if ( fn ) { - for ( ; i < len; i++ ) { - fn( - elems[ i ], key, raw ? - value : - value.call( elems[ i ], i, fn( elems[ i ], key ) ) - ); - } - } - } - - if ( chainable ) { - return elems; - } - - // Gets - if ( bulk ) { - return fn.call( elems ); - } - - return len ? fn( elems[ 0 ], key ) : emptyGet; -}; - - -// Matches dashed string for camelizing -var rmsPrefix = /^-ms-/, - rdashAlpha = /-([a-z])/g; - -// Used by camelCase as callback to replace() -function fcamelCase( _all, letter ) { - return letter.toUpperCase(); -} - -// Convert dashed to camelCase; used by the css and data modules -// Support: IE <=9 - 11, Edge 12 - 15 -// Microsoft forgot to hump their vendor prefix (trac-9572) -function camelCase( string ) { - return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); -} -var acceptData = function( owner ) { - - // Accepts only: - // - Node - // - Node.ELEMENT_NODE - // - Node.DOCUMENT_NODE - // - Object - // - Any - return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType ); -}; - - - - -function Data() { - this.expando = jQuery.expando + Data.uid++; -} - -Data.uid = 1; - -Data.prototype = { - - cache: function( owner ) { - - // Check if the owner object already has a cache - var value = owner[ this.expando ]; - - // If not, create one - if ( !value ) { - value = {}; - - // We can accept data for non-element nodes in modern browsers, - // but we should not, see trac-8335. - // Always return an empty object. - if ( acceptData( owner ) ) { - - // If it is a node unlikely to be stringify-ed or looped over - // use plain assignment - if ( owner.nodeType ) { - owner[ this.expando ] = value; - - // Otherwise secure it in a non-enumerable property - // configurable must be true to allow the property to be - // deleted when data is removed - } else { - Object.defineProperty( owner, this.expando, { - value: value, - configurable: true - } ); - } - } - } - - return value; - }, - set: function( owner, data, value ) { - var prop, - cache = this.cache( owner ); - - // Handle: [ owner, key, value ] args - // Always use camelCase key (gh-2257) - if ( typeof data === "string" ) { - cache[ camelCase( data ) ] = value; - - // Handle: [ owner, { properties } ] args - } else { - - // Copy the properties one-by-one to the cache object - for ( prop in data ) { - cache[ camelCase( prop ) ] = data[ prop ]; - } - } - return cache; - }, - get: function( owner, key ) { - return key === undefined ? - this.cache( owner ) : - - // Always use camelCase key (gh-2257) - owner[ this.expando ] && owner[ this.expando ][ camelCase( key ) ]; - }, - access: function( owner, key, value ) { - - // In cases where either: - // - // 1. No key was specified - // 2. A string key was specified, but no value provided - // - // Take the "read" path and allow the get method to determine - // which value to return, respectively either: - // - // 1. The entire cache object - // 2. The data stored at the key - // - if ( key === undefined || - ( ( key && typeof key === "string" ) && value === undefined ) ) { - - return this.get( owner, key ); - } - - // When the key is not a string, or both a key and value - // are specified, set or extend (existing objects) with either: - // - // 1. An object of properties - // 2. A key and value - // - this.set( owner, key, value ); - - // Since the "set" path can have two possible entry points - // return the expected data based on which path was taken[*] - return value !== undefined ? value : key; - }, - remove: function( owner, key ) { - var i, - cache = owner[ this.expando ]; - - if ( cache === undefined ) { - return; - } - - if ( key !== undefined ) { - - // Support array or space separated string of keys - if ( Array.isArray( key ) ) { - - // If key is an array of keys... - // We always set camelCase keys, so remove that. - key = key.map( camelCase ); - } else { - key = camelCase( key ); - - // If a key with the spaces exists, use it. - // Otherwise, create an array by matching non-whitespace - key = key in cache ? - [ key ] : - ( key.match( rnothtmlwhite ) || [] ); - } - - i = key.length; - - while ( i-- ) { - delete cache[ key[ i ] ]; - } - } - - // Remove the expando if there's no more data - if ( key === undefined || jQuery.isEmptyObject( cache ) ) { - - // Support: Chrome <=35 - 45 - // Webkit & Blink performance suffers when deleting properties - // from DOM nodes, so set to undefined instead - // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted) - if ( owner.nodeType ) { - owner[ this.expando ] = undefined; - } else { - delete owner[ this.expando ]; - } - } - }, - hasData: function( owner ) { - var cache = owner[ this.expando ]; - return cache !== undefined && !jQuery.isEmptyObject( cache ); - } -}; -var dataPriv = new Data(); - -var dataUser = new Data(); - - - -// Implementation Summary -// -// 1. Enforce API surface and semantic compatibility with 1.9.x branch -// 2. Improve the module's maintainability by reducing the storage -// paths to a single mechanism. -// 3. Use the same single mechanism to support "private" and "user" data. -// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData) -// 5. Avoid exposing implementation details on user objects (eg. expando properties) -// 6. Provide a clear path for implementation upgrade to WeakMap in 2014 - -var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, - rmultiDash = /[A-Z]/g; - -function getData( data ) { - if ( data === "true" ) { - return true; - } - - if ( data === "false" ) { - return false; - } - - if ( data === "null" ) { - return null; - } - - // Only convert to a number if it doesn't change the string - if ( data === +data + "" ) { - return +data; - } - - if ( rbrace.test( data ) ) { - return JSON.parse( data ); - } - - return data; -} - -function dataAttr( elem, key, data ) { - var name; - - // If nothing was found internally, try to fetch any - // data from the HTML5 data-* attribute - if ( data === undefined && elem.nodeType === 1 ) { - name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase(); - data = elem.getAttribute( name ); - - if ( typeof data === "string" ) { - try { - data = getData( data ); - } catch ( e ) {} - - // Make sure we set the data so it isn't changed later - dataUser.set( elem, key, data ); - } else { - data = undefined; - } - } - return data; -} - -jQuery.extend( { - hasData: function( elem ) { - return dataUser.hasData( elem ) || dataPriv.hasData( elem ); - }, - - data: function( elem, name, data ) { - return dataUser.access( elem, name, data ); - }, - - removeData: function( elem, name ) { - dataUser.remove( elem, name ); - }, - - // TODO: Now that all calls to _data and _removeData have been replaced - // with direct calls to dataPriv methods, these can be deprecated. - _data: function( elem, name, data ) { - return dataPriv.access( elem, name, data ); - }, - - _removeData: function( elem, name ) { - dataPriv.remove( elem, name ); - } -} ); - -jQuery.fn.extend( { - data: function( key, value ) { - var i, name, data, - elem = this[ 0 ], - attrs = elem && elem.attributes; - - // Gets all values - if ( key === undefined ) { - if ( this.length ) { - data = dataUser.get( elem ); - - if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) { - i = attrs.length; - while ( i-- ) { - - // Support: IE 11 only - // The attrs elements can be null (trac-14894) - if ( attrs[ i ] ) { - name = attrs[ i ].name; - if ( name.indexOf( "data-" ) === 0 ) { - name = camelCase( name.slice( 5 ) ); - dataAttr( elem, name, data[ name ] ); - } - } - } - dataPriv.set( elem, "hasDataAttrs", true ); - } - } - - return data; - } - - // Sets multiple values - if ( typeof key === "object" ) { - return this.each( function() { - dataUser.set( this, key ); - } ); - } - - return access( this, function( value ) { - var data; - - // The calling jQuery object (element matches) is not empty - // (and therefore has an element appears at this[ 0 ]) and the - // `value` parameter was not undefined. An empty jQuery object - // will result in `undefined` for elem = this[ 0 ] which will - // throw an exception if an attempt to read a data cache is made. - if ( elem && value === undefined ) { - - // Attempt to get data from the cache - // The key will always be camelCased in Data - data = dataUser.get( elem, key ); - if ( data !== undefined ) { - return data; - } - - // Attempt to "discover" the data in - // HTML5 custom data-* attrs - data = dataAttr( elem, key ); - if ( data !== undefined ) { - return data; - } - - // We tried really hard, but the data doesn't exist. - return; - } - - // Set the data... - this.each( function() { - - // We always store the camelCased key - dataUser.set( this, key, value ); - } ); - }, null, value, arguments.length > 1, null, true ); - }, - - removeData: function( key ) { - return this.each( function() { - dataUser.remove( this, key ); - } ); - } -} ); - - -jQuery.extend( { - queue: function( elem, type, data ) { - var queue; - - if ( elem ) { - type = ( type || "fx" ) + "queue"; - queue = dataPriv.get( elem, type ); - - // Speed up dequeue by getting out quickly if this is just a lookup - if ( data ) { - if ( !queue || Array.isArray( data ) ) { - queue = dataPriv.access( elem, type, jQuery.makeArray( data ) ); - } else { - queue.push( data ); - } - } - return queue || []; - } - }, - - dequeue: function( elem, type ) { - type = type || "fx"; - - var queue = jQuery.queue( elem, type ), - startLength = queue.length, - fn = queue.shift(), - hooks = jQuery._queueHooks( elem, type ), - next = function() { - jQuery.dequeue( elem, type ); - }; - - // If the fx queue is dequeued, always remove the progress sentinel - if ( fn === "inprogress" ) { - fn = queue.shift(); - startLength--; - } - - if ( fn ) { - - // Add a progress sentinel to prevent the fx queue from being - // automatically dequeued - if ( type === "fx" ) { - queue.unshift( "inprogress" ); - } - - // Clear up the last queue stop function - delete hooks.stop; - fn.call( elem, next, hooks ); - } - - if ( !startLength && hooks ) { - hooks.empty.fire(); - } - }, - - // Not public - generate a queueHooks object, or return the current one - _queueHooks: function( elem, type ) { - var key = type + "queueHooks"; - return dataPriv.get( elem, key ) || dataPriv.access( elem, key, { - empty: jQuery.Callbacks( "once memory" ).add( function() { - dataPriv.remove( elem, [ type + "queue", key ] ); - } ) - } ); - } -} ); - -jQuery.fn.extend( { - queue: function( type, data ) { - var setter = 2; - - if ( typeof type !== "string" ) { - data = type; - type = "fx"; - setter--; - } - - if ( arguments.length < setter ) { - return jQuery.queue( this[ 0 ], type ); - } - - return data === undefined ? - this : - this.each( function() { - var queue = jQuery.queue( this, type, data ); - - // Ensure a hooks for this queue - jQuery._queueHooks( this, type ); - - if ( type === "fx" && queue[ 0 ] !== "inprogress" ) { - jQuery.dequeue( this, type ); - } - } ); - }, - dequeue: function( type ) { - return this.each( function() { - jQuery.dequeue( this, type ); - } ); - }, - clearQueue: function( type ) { - return this.queue( type || "fx", [] ); - }, - - // Get a promise resolved when queues of a certain type - // are emptied (fx is the type by default) - promise: function( type, obj ) { - var tmp, - count = 1, - defer = jQuery.Deferred(), - elements = this, - i = this.length, - resolve = function() { - if ( !( --count ) ) { - defer.resolveWith( elements, [ elements ] ); - } - }; - - if ( typeof type !== "string" ) { - obj = type; - type = undefined; - } - type = type || "fx"; - - while ( i-- ) { - tmp = dataPriv.get( elements[ i ], type + "queueHooks" ); - if ( tmp && tmp.empty ) { - count++; - tmp.empty.add( resolve ); - } - } - resolve(); - return defer.promise( obj ); - } -} ); -var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source; - -var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); - - -var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; - -var documentElement = document.documentElement; - - - - var isAttached = function( elem ) { - return jQuery.contains( elem.ownerDocument, elem ); - }, - composed = { composed: true }; - - // Support: IE 9 - 11+, Edge 12 - 18+, iOS 10.0 - 10.2 only - // Check attachment across shadow DOM boundaries when possible (gh-3504) - // Support: iOS 10.0-10.2 only - // Early iOS 10 versions support `attachShadow` but not `getRootNode`, - // leading to errors. We need to check for `getRootNode`. - if ( documentElement.getRootNode ) { - isAttached = function( elem ) { - return jQuery.contains( elem.ownerDocument, elem ) || - elem.getRootNode( composed ) === elem.ownerDocument; - }; - } -var isHiddenWithinTree = function( elem, el ) { - - // isHiddenWithinTree might be called from jQuery#filter function; - // in that case, element will be second argument - elem = el || elem; - - // Inline style trumps all - return elem.style.display === "none" || - elem.style.display === "" && - - // Otherwise, check computed style - // Support: Firefox <=43 - 45 - // Disconnected elements can have computed display: none, so first confirm that elem is - // in the document. - isAttached( elem ) && - - jQuery.css( elem, "display" ) === "none"; - }; - - - -function adjustCSS( elem, prop, valueParts, tween ) { - var adjusted, scale, - maxIterations = 20, - currentValue = tween ? - function() { - return tween.cur(); - } : - function() { - return jQuery.css( elem, prop, "" ); - }, - initial = currentValue(), - unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), - - // Starting value computation is required for potential unit mismatches - initialInUnit = elem.nodeType && - ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && - rcssNum.exec( jQuery.css( elem, prop ) ); - - if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { - - // Support: Firefox <=54 - // Halve the iteration target value to prevent interference from CSS upper bounds (gh-2144) - initial = initial / 2; - - // Trust units reported by jQuery.css - unit = unit || initialInUnit[ 3 ]; - - // Iteratively approximate from a nonzero starting point - initialInUnit = +initial || 1; - - while ( maxIterations-- ) { - - // Evaluate and update our best guess (doubling guesses that zero out). - // Finish if the scale equals or crosses 1 (making the old*new product non-positive). - jQuery.style( elem, prop, initialInUnit + unit ); - if ( ( 1 - scale ) * ( 1 - ( scale = currentValue() / initial || 0.5 ) ) <= 0 ) { - maxIterations = 0; - } - initialInUnit = initialInUnit / scale; - - } - - initialInUnit = initialInUnit * 2; - jQuery.style( elem, prop, initialInUnit + unit ); - - // Make sure we update the tween properties later on - valueParts = valueParts || []; - } - - if ( valueParts ) { - initialInUnit = +initialInUnit || +initial || 0; - - // Apply relative offset (+=/-=) if specified - adjusted = valueParts[ 1 ] ? - initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] : - +valueParts[ 2 ]; - if ( tween ) { - tween.unit = unit; - tween.start = initialInUnit; - tween.end = adjusted; - } - } - return adjusted; -} - - -var defaultDisplayMap = {}; - -function getDefaultDisplay( elem ) { - var temp, - doc = elem.ownerDocument, - nodeName = elem.nodeName, - display = defaultDisplayMap[ nodeName ]; - - if ( display ) { - return display; - } - - temp = doc.body.appendChild( doc.createElement( nodeName ) ); - display = jQuery.css( temp, "display" ); - - temp.parentNode.removeChild( temp ); - - if ( display === "none" ) { - display = "block"; - } - defaultDisplayMap[ nodeName ] = display; - - return display; -} - -function showHide( elements, show ) { - var display, elem, - values = [], - index = 0, - length = elements.length; - - // Determine new display value for elements that need to change - for ( ; index < length; index++ ) { - elem = elements[ index ]; - if ( !elem.style ) { - continue; - } - - display = elem.style.display; - if ( show ) { - - // Since we force visibility upon cascade-hidden elements, an immediate (and slow) - // check is required in this first loop unless we have a nonempty display value (either - // inline or about-to-be-restored) - if ( display === "none" ) { - values[ index ] = dataPriv.get( elem, "display" ) || null; - if ( !values[ index ] ) { - elem.style.display = ""; - } - } - if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) { - values[ index ] = getDefaultDisplay( elem ); - } - } else { - if ( display !== "none" ) { - values[ index ] = "none"; - - // Remember what we're overwriting - dataPriv.set( elem, "display", display ); - } - } - } - - // Set the display of the elements in a second loop to avoid constant reflow - for ( index = 0; index < length; index++ ) { - if ( values[ index ] != null ) { - elements[ index ].style.display = values[ index ]; - } - } - - return elements; -} - -jQuery.fn.extend( { - show: function() { - return showHide( this, true ); - }, - hide: function() { - return showHide( this ); - }, - toggle: function( state ) { - if ( typeof state === "boolean" ) { - return state ? this.show() : this.hide(); - } - - return this.each( function() { - if ( isHiddenWithinTree( this ) ) { - jQuery( this ).show(); - } else { - jQuery( this ).hide(); - } - } ); - } -} ); -var rcheckableType = ( /^(?:checkbox|radio)$/i ); - -var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]*)/i ); - -var rscriptType = ( /^$|^module$|\/(?:java|ecma)script/i ); - - - -( function() { - var fragment = document.createDocumentFragment(), - div = fragment.appendChild( document.createElement( "div" ) ), - input = document.createElement( "input" ); - - // Support: Android 4.0 - 4.3 only - // Check state lost if the name is set (trac-11217) - // Support: Windows Web Apps (WWA) - // `name` and `type` must use .setAttribute for WWA (trac-14901) - input.setAttribute( "type", "radio" ); - input.setAttribute( "checked", "checked" ); - input.setAttribute( "name", "t" ); - - div.appendChild( input ); - - // Support: Android <=4.1 only - // Older WebKit doesn't clone checked state correctly in fragments - support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; - - // Support: IE <=11 only - // Make sure textarea (and checkbox) defaultValue is properly cloned - div.innerHTML = ""; - support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; - - // Support: IE <=9 only - // IE <=9 replaces "; - support.option = !!div.lastChild; -} )(); - - -// We have to close these tags to support XHTML (trac-13200) -var wrapMap = { - - // XHTML parsers do not magically insert elements in the - // same way that tag soup parsers do. So we cannot shorten - // this by omitting or other required elements. - thead: [ 1, "", "
" ], - col: [ 2, "", "
" ], - tr: [ 2, "", "
" ], - td: [ 3, "", "
" ], - - _default: [ 0, "", "" ] -}; - -wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; -wrapMap.th = wrapMap.td; - -// Support: IE <=9 only -if ( !support.option ) { - wrapMap.optgroup = wrapMap.option = [ 1, "" ]; -} - - -function getAll( context, tag ) { - - // Support: IE <=9 - 11 only - // Use typeof to avoid zero-argument method invocation on host objects (trac-15151) - var ret; - - if ( typeof context.getElementsByTagName !== "undefined" ) { - ret = context.getElementsByTagName( tag || "*" ); - - } else if ( typeof context.querySelectorAll !== "undefined" ) { - ret = context.querySelectorAll( tag || "*" ); - - } else { - ret = []; - } - - if ( tag === undefined || tag && nodeName( context, tag ) ) { - return jQuery.merge( [ context ], ret ); - } - - return ret; -} - - -// Mark scripts as having already been evaluated -function setGlobalEval( elems, refElements ) { - var i = 0, - l = elems.length; - - for ( ; i < l; i++ ) { - dataPriv.set( - elems[ i ], - "globalEval", - !refElements || dataPriv.get( refElements[ i ], "globalEval" ) - ); - } -} - - -var rhtml = /<|&#?\w+;/; - -function buildFragment( elems, context, scripts, selection, ignored ) { - var elem, tmp, tag, wrap, attached, j, - fragment = context.createDocumentFragment(), - nodes = [], - i = 0, - l = elems.length; - - for ( ; i < l; i++ ) { - elem = elems[ i ]; - - if ( elem || elem === 0 ) { - - // Add nodes directly - if ( toType( elem ) === "object" ) { - - // Support: Android <=4.0 only, PhantomJS 1 only - // push.apply(_, arraylike) throws on ancient WebKit - jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); - - // Convert non-html into a text node - } else if ( !rhtml.test( elem ) ) { - nodes.push( context.createTextNode( elem ) ); - - // Convert html into DOM nodes - } else { - tmp = tmp || fragment.appendChild( context.createElement( "div" ) ); - - // Deserialize a standard representation - tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase(); - wrap = wrapMap[ tag ] || wrapMap._default; - tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ]; - - // Descend through wrappers to the right content - j = wrap[ 0 ]; - while ( j-- ) { - tmp = tmp.lastChild; - } - - // Support: Android <=4.0 only, PhantomJS 1 only - // push.apply(_, arraylike) throws on ancient WebKit - jQuery.merge( nodes, tmp.childNodes ); - - // Remember the top-level container - tmp = fragment.firstChild; - - // Ensure the created nodes are orphaned (trac-12392) - tmp.textContent = ""; - } - } - } - - // Remove wrapper from fragment - fragment.textContent = ""; - - i = 0; - while ( ( elem = nodes[ i++ ] ) ) { - - // Skip elements already in the context collection (trac-4087) - if ( selection && jQuery.inArray( elem, selection ) > -1 ) { - if ( ignored ) { - ignored.push( elem ); - } - continue; - } - - attached = isAttached( elem ); - - // Append to fragment - tmp = getAll( fragment.appendChild( elem ), "script" ); - - // Preserve script evaluation history - if ( attached ) { - setGlobalEval( tmp ); - } - - // Capture executables - if ( scripts ) { - j = 0; - while ( ( elem = tmp[ j++ ] ) ) { - if ( rscriptType.test( elem.type || "" ) ) { - scripts.push( elem ); - } - } - } - } - - return fragment; -} - - -var rtypenamespace = /^([^.]*)(?:\.(.+)|)/; - -function returnTrue() { - return true; -} - -function returnFalse() { - return false; -} - -function on( elem, types, selector, data, fn, one ) { - var origFn, type; - - // Types can be a map of types/handlers - if ( typeof types === "object" ) { - - // ( types-Object, selector, data ) - if ( typeof selector !== "string" ) { - - // ( types-Object, data ) - data = data || selector; - selector = undefined; - } - for ( type in types ) { - on( elem, type, selector, data, types[ type ], one ); - } - return elem; - } - - if ( data == null && fn == null ) { - - // ( types, fn ) - fn = selector; - data = selector = undefined; - } else if ( fn == null ) { - if ( typeof selector === "string" ) { - - // ( types, selector, fn ) - fn = data; - data = undefined; - } else { - - // ( types, data, fn ) - fn = data; - data = selector; - selector = undefined; - } - } - if ( fn === false ) { - fn = returnFalse; - } else if ( !fn ) { - return elem; - } - - if ( one === 1 ) { - origFn = fn; - fn = function( event ) { - - // Can use an empty set, since event contains the info - jQuery().off( event ); - return origFn.apply( this, arguments ); - }; - - // Use same guid so caller can remove using origFn - fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); - } - return elem.each( function() { - jQuery.event.add( this, types, fn, data, selector ); - } ); -} - -/* - * Helper functions for managing events -- not part of the public interface. - * Props to Dean Edwards' addEvent library for many of the ideas. - */ -jQuery.event = { - - global: {}, - - add: function( elem, types, handler, data, selector ) { - - var handleObjIn, eventHandle, tmp, - events, t, handleObj, - special, handlers, type, namespaces, origType, - elemData = dataPriv.get( elem ); - - // Only attach events to objects that accept data - if ( !acceptData( elem ) ) { - return; - } - - // Caller can pass in an object of custom data in lieu of the handler - if ( handler.handler ) { - handleObjIn = handler; - handler = handleObjIn.handler; - selector = handleObjIn.selector; - } - - // Ensure that invalid selectors throw exceptions at attach time - // Evaluate against documentElement in case elem is a non-element node (e.g., document) - if ( selector ) { - jQuery.find.matchesSelector( documentElement, selector ); - } - - // Make sure that the handler has a unique ID, used to find/remove it later - if ( !handler.guid ) { - handler.guid = jQuery.guid++; - } - - // Init the element's event structure and main handler, if this is the first - if ( !( events = elemData.events ) ) { - events = elemData.events = Object.create( null ); - } - if ( !( eventHandle = elemData.handle ) ) { - eventHandle = elemData.handle = function( e ) { - - // Discard the second event of a jQuery.event.trigger() and - // when an event is called after a page has unloaded - return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? - jQuery.event.dispatch.apply( elem, arguments ) : undefined; - }; - } - - // Handle multiple events separated by a space - types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; - t = types.length; - while ( t-- ) { - tmp = rtypenamespace.exec( types[ t ] ) || []; - type = origType = tmp[ 1 ]; - namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); - - // There *must* be a type, no attaching namespace-only handlers - if ( !type ) { - continue; - } - - // If event changes its type, use the special event handlers for the changed type - special = jQuery.event.special[ type ] || {}; - - // If selector defined, determine special event api type, otherwise given type - type = ( selector ? special.delegateType : special.bindType ) || type; - - // Update special based on newly reset type - special = jQuery.event.special[ type ] || {}; - - // handleObj is passed to all event handlers - handleObj = jQuery.extend( { - type: type, - origType: origType, - data: data, - handler: handler, - guid: handler.guid, - selector: selector, - needsContext: selector && jQuery.expr.match.needsContext.test( selector ), - namespace: namespaces.join( "." ) - }, handleObjIn ); - - // Init the event handler queue if we're the first - if ( !( handlers = events[ type ] ) ) { - handlers = events[ type ] = []; - handlers.delegateCount = 0; - - // Only use addEventListener if the special events handler returns false - if ( !special.setup || - special.setup.call( elem, data, namespaces, eventHandle ) === false ) { - - if ( elem.addEventListener ) { - elem.addEventListener( type, eventHandle ); - } - } - } - - if ( special.add ) { - special.add.call( elem, handleObj ); - - if ( !handleObj.handler.guid ) { - handleObj.handler.guid = handler.guid; - } - } - - // Add to the element's handler list, delegates in front - if ( selector ) { - handlers.splice( handlers.delegateCount++, 0, handleObj ); - } else { - handlers.push( handleObj ); - } - - // Keep track of which events have ever been used, for event optimization - jQuery.event.global[ type ] = true; - } - - }, - - // Detach an event or set of events from an element - remove: function( elem, types, handler, selector, mappedTypes ) { - - var j, origCount, tmp, - events, t, handleObj, - special, handlers, type, namespaces, origType, - elemData = dataPriv.hasData( elem ) && dataPriv.get( elem ); - - if ( !elemData || !( events = elemData.events ) ) { - return; - } - - // Once for each type.namespace in types; type may be omitted - types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; - t = types.length; - while ( t-- ) { - tmp = rtypenamespace.exec( types[ t ] ) || []; - type = origType = tmp[ 1 ]; - namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); - - // Unbind all events (on this namespace, if provided) for the element - if ( !type ) { - for ( type in events ) { - jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); - } - continue; - } - - special = jQuery.event.special[ type ] || {}; - type = ( selector ? special.delegateType : special.bindType ) || type; - handlers = events[ type ] || []; - tmp = tmp[ 2 ] && - new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ); - - // Remove matching events - origCount = j = handlers.length; - while ( j-- ) { - handleObj = handlers[ j ]; - - if ( ( mappedTypes || origType === handleObj.origType ) && - ( !handler || handler.guid === handleObj.guid ) && - ( !tmp || tmp.test( handleObj.namespace ) ) && - ( !selector || selector === handleObj.selector || - selector === "**" && handleObj.selector ) ) { - handlers.splice( j, 1 ); - - if ( handleObj.selector ) { - handlers.delegateCount--; - } - if ( special.remove ) { - special.remove.call( elem, handleObj ); - } - } - } - - // Remove generic event handler if we removed something and no more handlers exist - // (avoids potential for endless recursion during removal of special event handlers) - if ( origCount && !handlers.length ) { - if ( !special.teardown || - special.teardown.call( elem, namespaces, elemData.handle ) === false ) { - - jQuery.removeEvent( elem, type, elemData.handle ); - } - - delete events[ type ]; - } - } - - // Remove data and the expando if it's no longer used - if ( jQuery.isEmptyObject( events ) ) { - dataPriv.remove( elem, "handle events" ); - } - }, - - dispatch: function( nativeEvent ) { - - var i, j, ret, matched, handleObj, handlerQueue, - args = new Array( arguments.length ), - - // Make a writable jQuery.Event from the native event object - event = jQuery.event.fix( nativeEvent ), - - handlers = ( - dataPriv.get( this, "events" ) || Object.create( null ) - )[ event.type ] || [], - special = jQuery.event.special[ event.type ] || {}; - - // Use the fix-ed jQuery.Event rather than the (read-only) native event - args[ 0 ] = event; - - for ( i = 1; i < arguments.length; i++ ) { - args[ i ] = arguments[ i ]; - } - - event.delegateTarget = this; - - // Call the preDispatch hook for the mapped type, and let it bail if desired - if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { - return; - } - - // Determine handlers - handlerQueue = jQuery.event.handlers.call( this, event, handlers ); - - // Run delegates first; they may want to stop propagation beneath us - i = 0; - while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { - event.currentTarget = matched.elem; - - j = 0; - while ( ( handleObj = matched.handlers[ j++ ] ) && - !event.isImmediatePropagationStopped() ) { - - // If the event is namespaced, then each handler is only invoked if it is - // specially universal or its namespaces are a superset of the event's. - if ( !event.rnamespace || handleObj.namespace === false || - event.rnamespace.test( handleObj.namespace ) ) { - - event.handleObj = handleObj; - event.data = handleObj.data; - - ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle || - handleObj.handler ).apply( matched.elem, args ); - - if ( ret !== undefined ) { - if ( ( event.result = ret ) === false ) { - event.preventDefault(); - event.stopPropagation(); - } - } - } - } - } - - // Call the postDispatch hook for the mapped type - if ( special.postDispatch ) { - special.postDispatch.call( this, event ); - } - - return event.result; - }, - - handlers: function( event, handlers ) { - var i, handleObj, sel, matchedHandlers, matchedSelectors, - handlerQueue = [], - delegateCount = handlers.delegateCount, - cur = event.target; - - // Find delegate handlers - if ( delegateCount && - - // Support: IE <=9 - // Black-hole SVG instance trees (trac-13180) - cur.nodeType && - - // Support: Firefox <=42 - // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861) - // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click - // Support: IE 11 only - // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343) - !( event.type === "click" && event.button >= 1 ) ) { - - for ( ; cur !== this; cur = cur.parentNode || this ) { - - // Don't check non-elements (trac-13208) - // Don't process clicks on disabled elements (trac-6911, trac-8165, trac-11382, trac-11764) - if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) { - matchedHandlers = []; - matchedSelectors = {}; - for ( i = 0; i < delegateCount; i++ ) { - handleObj = handlers[ i ]; - - // Don't conflict with Object.prototype properties (trac-13203) - sel = handleObj.selector + " "; - - if ( matchedSelectors[ sel ] === undefined ) { - matchedSelectors[ sel ] = handleObj.needsContext ? - jQuery( sel, this ).index( cur ) > -1 : - jQuery.find( sel, this, null, [ cur ] ).length; - } - if ( matchedSelectors[ sel ] ) { - matchedHandlers.push( handleObj ); - } - } - if ( matchedHandlers.length ) { - handlerQueue.push( { elem: cur, handlers: matchedHandlers } ); - } - } - } - } - - // Add the remaining (directly-bound) handlers - cur = this; - if ( delegateCount < handlers.length ) { - handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } ); - } - - return handlerQueue; - }, - - addProp: function( name, hook ) { - Object.defineProperty( jQuery.Event.prototype, name, { - enumerable: true, - configurable: true, - - get: isFunction( hook ) ? - function() { - if ( this.originalEvent ) { - return hook( this.originalEvent ); - } - } : - function() { - if ( this.originalEvent ) { - return this.originalEvent[ name ]; - } - }, - - set: function( value ) { - Object.defineProperty( this, name, { - enumerable: true, - configurable: true, - writable: true, - value: value - } ); - } - } ); - }, - - fix: function( originalEvent ) { - return originalEvent[ jQuery.expando ] ? - originalEvent : - new jQuery.Event( originalEvent ); - }, - - special: { - load: { - - // Prevent triggered image.load events from bubbling to window.load - noBubble: true - }, - click: { - - // Utilize native event to ensure correct state for checkable inputs - setup: function( data ) { - - // For mutual compressibility with _default, replace `this` access with a local var. - // `|| data` is dead code meant only to preserve the variable through minification. - var el = this || data; - - // Claim the first handler - if ( rcheckableType.test( el.type ) && - el.click && nodeName( el, "input" ) ) { - - // dataPriv.set( el, "click", ... ) - leverageNative( el, "click", true ); - } - - // Return false to allow normal processing in the caller - return false; - }, - trigger: function( data ) { - - // For mutual compressibility with _default, replace `this` access with a local var. - // `|| data` is dead code meant only to preserve the variable through minification. - var el = this || data; - - // Force setup before triggering a click - if ( rcheckableType.test( el.type ) && - el.click && nodeName( el, "input" ) ) { - - leverageNative( el, "click" ); - } - - // Return non-false to allow normal event-path propagation - return true; - }, - - // For cross-browser consistency, suppress native .click() on links - // Also prevent it if we're currently inside a leveraged native-event stack - _default: function( event ) { - var target = event.target; - return rcheckableType.test( target.type ) && - target.click && nodeName( target, "input" ) && - dataPriv.get( target, "click" ) || - nodeName( target, "a" ); - } - }, - - beforeunload: { - postDispatch: function( event ) { - - // Support: Firefox 20+ - // Firefox doesn't alert if the returnValue field is not set. - if ( event.result !== undefined && event.originalEvent ) { - event.originalEvent.returnValue = event.result; - } - } - } - } -}; - -// Ensure the presence of an event listener that handles manually-triggered -// synthetic events by interrupting progress until reinvoked in response to -// *native* events that it fires directly, ensuring that state changes have -// already occurred before other listeners are invoked. -function leverageNative( el, type, isSetup ) { - - // Missing `isSetup` indicates a trigger call, which must force setup through jQuery.event.add - if ( !isSetup ) { - if ( dataPriv.get( el, type ) === undefined ) { - jQuery.event.add( el, type, returnTrue ); - } - return; - } - - // Register the controller as a special universal handler for all event namespaces - dataPriv.set( el, type, false ); - jQuery.event.add( el, type, { - namespace: false, - handler: function( event ) { - var result, - saved = dataPriv.get( this, type ); - - if ( ( event.isTrigger & 1 ) && this[ type ] ) { - - // Interrupt processing of the outer synthetic .trigger()ed event - if ( !saved ) { - - // Store arguments for use when handling the inner native event - // There will always be at least one argument (an event object), so this array - // will not be confused with a leftover capture object. - saved = slice.call( arguments ); - dataPriv.set( this, type, saved ); - - // Trigger the native event and capture its result - this[ type ](); - result = dataPriv.get( this, type ); - dataPriv.set( this, type, false ); - - if ( saved !== result ) { - - // Cancel the outer synthetic event - event.stopImmediatePropagation(); - event.preventDefault(); - - return result; - } - - // If this is an inner synthetic event for an event with a bubbling surrogate - // (focus or blur), assume that the surrogate already propagated from triggering - // the native event and prevent that from happening again here. - // This technically gets the ordering wrong w.r.t. to `.trigger()` (in which the - // bubbling surrogate propagates *after* the non-bubbling base), but that seems - // less bad than duplication. - } else if ( ( jQuery.event.special[ type ] || {} ).delegateType ) { - event.stopPropagation(); - } - - // If this is a native event triggered above, everything is now in order - // Fire an inner synthetic event with the original arguments - } else if ( saved ) { - - // ...and capture the result - dataPriv.set( this, type, jQuery.event.trigger( - saved[ 0 ], - saved.slice( 1 ), - this - ) ); - - // Abort handling of the native event by all jQuery handlers while allowing - // native handlers on the same element to run. On target, this is achieved - // by stopping immediate propagation just on the jQuery event. However, - // the native event is re-wrapped by a jQuery one on each level of the - // propagation so the only way to stop it for jQuery is to stop it for - // everyone via native `stopPropagation()`. This is not a problem for - // focus/blur which don't bubble, but it does also stop click on checkboxes - // and radios. We accept this limitation. - event.stopPropagation(); - event.isImmediatePropagationStopped = returnTrue; - } - } - } ); -} - -jQuery.removeEvent = function( elem, type, handle ) { - - // This "if" is needed for plain objects - if ( elem.removeEventListener ) { - elem.removeEventListener( type, handle ); - } -}; - -jQuery.Event = function( src, props ) { - - // Allow instantiation without the 'new' keyword - if ( !( this instanceof jQuery.Event ) ) { - return new jQuery.Event( src, props ); - } - - // Event object - if ( src && src.type ) { - this.originalEvent = src; - this.type = src.type; - - // Events bubbling up the document may have been marked as prevented - // by a handler lower down the tree; reflect the correct value. - this.isDefaultPrevented = src.defaultPrevented || - src.defaultPrevented === undefined && - - // Support: Android <=2.3 only - src.returnValue === false ? - returnTrue : - returnFalse; - - // Create target properties - // Support: Safari <=6 - 7 only - // Target should not be a text node (trac-504, trac-13143) - this.target = ( src.target && src.target.nodeType === 3 ) ? - src.target.parentNode : - src.target; - - this.currentTarget = src.currentTarget; - this.relatedTarget = src.relatedTarget; - - // Event type - } else { - this.type = src; - } - - // Put explicitly provided properties onto the event object - if ( props ) { - jQuery.extend( this, props ); - } - - // Create a timestamp if incoming event doesn't have one - this.timeStamp = src && src.timeStamp || Date.now(); - - // Mark it as fixed - this[ jQuery.expando ] = true; -}; - -// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding -// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html -jQuery.Event.prototype = { - constructor: jQuery.Event, - isDefaultPrevented: returnFalse, - isPropagationStopped: returnFalse, - isImmediatePropagationStopped: returnFalse, - isSimulated: false, - - preventDefault: function() { - var e = this.originalEvent; - - this.isDefaultPrevented = returnTrue; - - if ( e && !this.isSimulated ) { - e.preventDefault(); - } - }, - stopPropagation: function() { - var e = this.originalEvent; - - this.isPropagationStopped = returnTrue; - - if ( e && !this.isSimulated ) { - e.stopPropagation(); - } - }, - stopImmediatePropagation: function() { - var e = this.originalEvent; - - this.isImmediatePropagationStopped = returnTrue; - - if ( e && !this.isSimulated ) { - e.stopImmediatePropagation(); - } - - this.stopPropagation(); - } -}; - -// Includes all common event props including KeyEvent and MouseEvent specific props -jQuery.each( { - altKey: true, - bubbles: true, - cancelable: true, - changedTouches: true, - ctrlKey: true, - detail: true, - eventPhase: true, - metaKey: true, - pageX: true, - pageY: true, - shiftKey: true, - view: true, - "char": true, - code: true, - charCode: true, - key: true, - keyCode: true, - button: true, - buttons: true, - clientX: true, - clientY: true, - offsetX: true, - offsetY: true, - pointerId: true, - pointerType: true, - screenX: true, - screenY: true, - targetTouches: true, - toElement: true, - touches: true, - which: true -}, jQuery.event.addProp ); - -jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateType ) { - - function focusMappedHandler( nativeEvent ) { - if ( document.documentMode ) { - - // Support: IE 11+ - // Attach a single focusin/focusout handler on the document while someone wants - // focus/blur. This is because the former are synchronous in IE while the latter - // are async. In other browsers, all those handlers are invoked synchronously. - - // `handle` from private data would already wrap the event, but we need - // to change the `type` here. - var handle = dataPriv.get( this, "handle" ), - event = jQuery.event.fix( nativeEvent ); - event.type = nativeEvent.type === "focusin" ? "focus" : "blur"; - event.isSimulated = true; - - // First, handle focusin/focusout - handle( nativeEvent ); - - // ...then, handle focus/blur - // - // focus/blur don't bubble while focusin/focusout do; simulate the former by only - // invoking the handler at the lower level. - if ( event.target === event.currentTarget ) { - - // The setup part calls `leverageNative`, which, in turn, calls - // `jQuery.event.add`, so event handle will already have been set - // by this point. - handle( event ); - } - } else { - - // For non-IE browsers, attach a single capturing handler on the document - // while someone wants focusin/focusout. - jQuery.event.simulate( delegateType, nativeEvent.target, - jQuery.event.fix( nativeEvent ) ); - } - } - - jQuery.event.special[ type ] = { - - // Utilize native event if possible so blur/focus sequence is correct - setup: function() { - - var attaches; - - // Claim the first handler - // dataPriv.set( this, "focus", ... ) - // dataPriv.set( this, "blur", ... ) - leverageNative( this, type, true ); - - if ( document.documentMode ) { - - // Support: IE 9 - 11+ - // We use the same native handler for focusin & focus (and focusout & blur) - // so we need to coordinate setup & teardown parts between those events. - // Use `delegateType` as the key as `type` is already used by `leverageNative`. - attaches = dataPriv.get( this, delegateType ); - if ( !attaches ) { - this.addEventListener( delegateType, focusMappedHandler ); - } - dataPriv.set( this, delegateType, ( attaches || 0 ) + 1 ); - } else { - - // Return false to allow normal processing in the caller - return false; - } - }, - trigger: function() { - - // Force setup before trigger - leverageNative( this, type ); - - // Return non-false to allow normal event-path propagation - return true; - }, - - teardown: function() { - var attaches; - - if ( document.documentMode ) { - attaches = dataPriv.get( this, delegateType ) - 1; - if ( !attaches ) { - this.removeEventListener( delegateType, focusMappedHandler ); - dataPriv.remove( this, delegateType ); - } else { - dataPriv.set( this, delegateType, attaches ); - } - } else { - - // Return false to indicate standard teardown should be applied - return false; - } - }, - - // Suppress native focus or blur if we're currently inside - // a leveraged native-event stack - _default: function( event ) { - return dataPriv.get( event.target, type ); - }, - - delegateType: delegateType - }; - - // Support: Firefox <=44 - // Firefox doesn't have focus(in | out) events - // Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 - // - // Support: Chrome <=48 - 49, Safari <=9.0 - 9.1 - // focus(in | out) events fire after focus & blur events, - // which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order - // Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857 - // - // Support: IE 9 - 11+ - // To preserve relative focusin/focus & focusout/blur event order guaranteed on the 3.x branch, - // attach a single handler for both events in IE. - jQuery.event.special[ delegateType ] = { - setup: function() { - - // Handle: regular nodes (via `this.ownerDocument`), window - // (via `this.document`) & document (via `this`). - var doc = this.ownerDocument || this.document || this, - dataHolder = document.documentMode ? this : doc, - attaches = dataPriv.get( dataHolder, delegateType ); - - // Support: IE 9 - 11+ - // We use the same native handler for focusin & focus (and focusout & blur) - // so we need to coordinate setup & teardown parts between those events. - // Use `delegateType` as the key as `type` is already used by `leverageNative`. - if ( !attaches ) { - if ( document.documentMode ) { - this.addEventListener( delegateType, focusMappedHandler ); - } else { - doc.addEventListener( type, focusMappedHandler, true ); - } - } - dataPriv.set( dataHolder, delegateType, ( attaches || 0 ) + 1 ); - }, - teardown: function() { - var doc = this.ownerDocument || this.document || this, - dataHolder = document.documentMode ? this : doc, - attaches = dataPriv.get( dataHolder, delegateType ) - 1; - - if ( !attaches ) { - if ( document.documentMode ) { - this.removeEventListener( delegateType, focusMappedHandler ); - } else { - doc.removeEventListener( type, focusMappedHandler, true ); - } - dataPriv.remove( dataHolder, delegateType ); - } else { - dataPriv.set( dataHolder, delegateType, attaches ); - } - } - }; -} ); - -// Create mouseenter/leave events using mouseover/out and event-time checks -// so that event delegation works in jQuery. -// Do the same for pointerenter/pointerleave and pointerover/pointerout -// -// Support: Safari 7 only -// Safari sends mouseenter too often; see: -// https://bugs.chromium.org/p/chromium/issues/detail?id=470258 -// for the description of the bug (it existed in older Chrome versions as well). -jQuery.each( { - mouseenter: "mouseover", - mouseleave: "mouseout", - pointerenter: "pointerover", - pointerleave: "pointerout" -}, function( orig, fix ) { - jQuery.event.special[ orig ] = { - delegateType: fix, - bindType: fix, - - handle: function( event ) { - var ret, - target = this, - related = event.relatedTarget, - handleObj = event.handleObj; - - // For mouseenter/leave call the handler if related is outside the target. - // NB: No relatedTarget if the mouse left/entered the browser window - if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) { - event.type = handleObj.origType; - ret = handleObj.handler.apply( this, arguments ); - event.type = fix; - } - return ret; - } - }; -} ); - -jQuery.fn.extend( { - - on: function( types, selector, data, fn ) { - return on( this, types, selector, data, fn ); - }, - one: function( types, selector, data, fn ) { - return on( this, types, selector, data, fn, 1 ); - }, - off: function( types, selector, fn ) { - var handleObj, type; - if ( types && types.preventDefault && types.handleObj ) { - - // ( event ) dispatched jQuery.Event - handleObj = types.handleObj; - jQuery( types.delegateTarget ).off( - handleObj.namespace ? - handleObj.origType + "." + handleObj.namespace : - handleObj.origType, - handleObj.selector, - handleObj.handler - ); - return this; - } - if ( typeof types === "object" ) { - - // ( types-object [, selector] ) - for ( type in types ) { - this.off( type, selector, types[ type ] ); - } - return this; - } - if ( selector === false || typeof selector === "function" ) { - - // ( types [, fn] ) - fn = selector; - selector = undefined; - } - if ( fn === false ) { - fn = returnFalse; - } - return this.each( function() { - jQuery.event.remove( this, types, fn, selector ); - } ); - } -} ); - - -var - - // Support: IE <=10 - 11, Edge 12 - 13 only - // In IE/Edge using regex groups here causes severe slowdowns. - // See https://connect.microsoft.com/IE/feedback/details/1736512/ - rnoInnerhtml = /\s*$/g; - -// Prefer a tbody over its parent table for containing new rows -function manipulationTarget( elem, content ) { - if ( nodeName( elem, "table" ) && - nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) { - - return jQuery( elem ).children( "tbody" )[ 0 ] || elem; - } - - return elem; -} - -// Replace/restore the type attribute of script elements for safe DOM manipulation -function disableScript( elem ) { - elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type; - return elem; -} -function restoreScript( elem ) { - if ( ( elem.type || "" ).slice( 0, 5 ) === "true/" ) { - elem.type = elem.type.slice( 5 ); - } else { - elem.removeAttribute( "type" ); - } - - return elem; -} - -function cloneCopyEvent( src, dest ) { - var i, l, type, pdataOld, udataOld, udataCur, events; - - if ( dest.nodeType !== 1 ) { - return; - } - - // 1. Copy private data: events, handlers, etc. - if ( dataPriv.hasData( src ) ) { - pdataOld = dataPriv.get( src ); - events = pdataOld.events; - - if ( events ) { - dataPriv.remove( dest, "handle events" ); - - for ( type in events ) { - for ( i = 0, l = events[ type ].length; i < l; i++ ) { - jQuery.event.add( dest, type, events[ type ][ i ] ); - } - } - } - } - - // 2. Copy user data - if ( dataUser.hasData( src ) ) { - udataOld = dataUser.access( src ); - udataCur = jQuery.extend( {}, udataOld ); - - dataUser.set( dest, udataCur ); - } -} - -// Fix IE bugs, see support tests -function fixInput( src, dest ) { - var nodeName = dest.nodeName.toLowerCase(); - - // Fails to persist the checked state of a cloned checkbox or radio button. - if ( nodeName === "input" && rcheckableType.test( src.type ) ) { - dest.checked = src.checked; - - // Fails to return the selected option to the default selected state when cloning options - } else if ( nodeName === "input" || nodeName === "textarea" ) { - dest.defaultValue = src.defaultValue; - } -} - -function domManip( collection, args, callback, ignored ) { - - // Flatten any nested arrays - args = flat( args ); - - var fragment, first, scripts, hasScripts, node, doc, - i = 0, - l = collection.length, - iNoClone = l - 1, - value = args[ 0 ], - valueIsFunction = isFunction( value ); - - // We can't cloneNode fragments that contain checked, in WebKit - if ( valueIsFunction || - ( l > 1 && typeof value === "string" && - !support.checkClone && rchecked.test( value ) ) ) { - return collection.each( function( index ) { - var self = collection.eq( index ); - if ( valueIsFunction ) { - args[ 0 ] = value.call( this, index, self.html() ); - } - domManip( self, args, callback, ignored ); - } ); - } - - if ( l ) { - fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored ); - first = fragment.firstChild; - - if ( fragment.childNodes.length === 1 ) { - fragment = first; - } - - // Require either new content or an interest in ignored elements to invoke the callback - if ( first || ignored ) { - scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); - hasScripts = scripts.length; - - // Use the original fragment for the last item - // instead of the first because it can end up - // being emptied incorrectly in certain situations (trac-8070). - for ( ; i < l; i++ ) { - node = fragment; - - if ( i !== iNoClone ) { - node = jQuery.clone( node, true, true ); - - // Keep references to cloned scripts for later restoration - if ( hasScripts ) { - - // Support: Android <=4.0 only, PhantomJS 1 only - // push.apply(_, arraylike) throws on ancient WebKit - jQuery.merge( scripts, getAll( node, "script" ) ); - } - } - - callback.call( collection[ i ], node, i ); - } - - if ( hasScripts ) { - doc = scripts[ scripts.length - 1 ].ownerDocument; - - // Re-enable scripts - jQuery.map( scripts, restoreScript ); - - // Evaluate executable scripts on first document insertion - for ( i = 0; i < hasScripts; i++ ) { - node = scripts[ i ]; - if ( rscriptType.test( node.type || "" ) && - !dataPriv.access( node, "globalEval" ) && - jQuery.contains( doc, node ) ) { - - if ( node.src && ( node.type || "" ).toLowerCase() !== "module" ) { - - // Optional AJAX dependency, but won't run scripts if not present - if ( jQuery._evalUrl && !node.noModule ) { - jQuery._evalUrl( node.src, { - nonce: node.nonce || node.getAttribute( "nonce" ) - }, doc ); - } - } else { - - // Unwrap a CDATA section containing script contents. This shouldn't be - // needed as in XML documents they're already not visible when - // inspecting element contents and in HTML documents they have no - // meaning but we're preserving that logic for backwards compatibility. - // This will be removed completely in 4.0. See gh-4904. - DOMEval( node.textContent.replace( rcleanScript, "" ), node, doc ); - } - } - } - } - } - } - - return collection; -} - -function remove( elem, selector, keepData ) { - var node, - nodes = selector ? jQuery.filter( selector, elem ) : elem, - i = 0; - - for ( ; ( node = nodes[ i ] ) != null; i++ ) { - if ( !keepData && node.nodeType === 1 ) { - jQuery.cleanData( getAll( node ) ); - } - - if ( node.parentNode ) { - if ( keepData && isAttached( node ) ) { - setGlobalEval( getAll( node, "script" ) ); - } - node.parentNode.removeChild( node ); - } - } - - return elem; -} - -jQuery.extend( { - htmlPrefilter: function( html ) { - return html; - }, - - clone: function( elem, dataAndEvents, deepDataAndEvents ) { - var i, l, srcElements, destElements, - clone = elem.cloneNode( true ), - inPage = isAttached( elem ); - - // Fix IE cloning issues - if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && - !jQuery.isXMLDoc( elem ) ) { - - // We eschew jQuery#find here for performance reasons: - // https://jsperf.com/getall-vs-sizzle/2 - destElements = getAll( clone ); - srcElements = getAll( elem ); - - for ( i = 0, l = srcElements.length; i < l; i++ ) { - fixInput( srcElements[ i ], destElements[ i ] ); - } - } - - // Copy the events from the original to the clone - if ( dataAndEvents ) { - if ( deepDataAndEvents ) { - srcElements = srcElements || getAll( elem ); - destElements = destElements || getAll( clone ); - - for ( i = 0, l = srcElements.length; i < l; i++ ) { - cloneCopyEvent( srcElements[ i ], destElements[ i ] ); - } - } else { - cloneCopyEvent( elem, clone ); - } - } - - // Preserve script evaluation history - destElements = getAll( clone, "script" ); - if ( destElements.length > 0 ) { - setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); - } - - // Return the cloned set - return clone; - }, - - cleanData: function( elems ) { - var data, elem, type, - special = jQuery.event.special, - i = 0; - - for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) { - if ( acceptData( elem ) ) { - if ( ( data = elem[ dataPriv.expando ] ) ) { - if ( data.events ) { - for ( type in data.events ) { - if ( special[ type ] ) { - jQuery.event.remove( elem, type ); - - // This is a shortcut to avoid jQuery.event.remove's overhead - } else { - jQuery.removeEvent( elem, type, data.handle ); - } - } - } - - // Support: Chrome <=35 - 45+ - // Assign undefined instead of using delete, see Data#remove - elem[ dataPriv.expando ] = undefined; - } - if ( elem[ dataUser.expando ] ) { - - // Support: Chrome <=35 - 45+ - // Assign undefined instead of using delete, see Data#remove - elem[ dataUser.expando ] = undefined; - } - } - } - } -} ); - -jQuery.fn.extend( { - detach: function( selector ) { - return remove( this, selector, true ); - }, - - remove: function( selector ) { - return remove( this, selector ); - }, - - text: function( value ) { - return access( this, function( value ) { - return value === undefined ? - jQuery.text( this ) : - this.empty().each( function() { - if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { - this.textContent = value; - } - } ); - }, null, value, arguments.length ); - }, - - append: function() { - return domManip( this, arguments, function( elem ) { - if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { - var target = manipulationTarget( this, elem ); - target.appendChild( elem ); - } - } ); - }, - - prepend: function() { - return domManip( this, arguments, function( elem ) { - if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { - var target = manipulationTarget( this, elem ); - target.insertBefore( elem, target.firstChild ); - } - } ); - }, - - before: function() { - return domManip( this, arguments, function( elem ) { - if ( this.parentNode ) { - this.parentNode.insertBefore( elem, this ); - } - } ); - }, - - after: function() { - return domManip( this, arguments, function( elem ) { - if ( this.parentNode ) { - this.parentNode.insertBefore( elem, this.nextSibling ); - } - } ); - }, - - empty: function() { - var elem, - i = 0; - - for ( ; ( elem = this[ i ] ) != null; i++ ) { - if ( elem.nodeType === 1 ) { - - // Prevent memory leaks - jQuery.cleanData( getAll( elem, false ) ); - - // Remove any remaining nodes - elem.textContent = ""; - } - } - - return this; - }, - - clone: function( dataAndEvents, deepDataAndEvents ) { - dataAndEvents = dataAndEvents == null ? false : dataAndEvents; - deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; - - return this.map( function() { - return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); - } ); - }, - - html: function( value ) { - return access( this, function( value ) { - var elem = this[ 0 ] || {}, - i = 0, - l = this.length; - - if ( value === undefined && elem.nodeType === 1 ) { - return elem.innerHTML; - } - - // See if we can take a shortcut and just use innerHTML - if ( typeof value === "string" && !rnoInnerhtml.test( value ) && - !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { - - value = jQuery.htmlPrefilter( value ); - - try { - for ( ; i < l; i++ ) { - elem = this[ i ] || {}; - - // Remove element nodes and prevent memory leaks - if ( elem.nodeType === 1 ) { - jQuery.cleanData( getAll( elem, false ) ); - elem.innerHTML = value; - } - } - - elem = 0; - - // If using innerHTML throws an exception, use the fallback method - } catch ( e ) {} - } - - if ( elem ) { - this.empty().append( value ); - } - }, null, value, arguments.length ); - }, - - replaceWith: function() { - var ignored = []; - - // Make the changes, replacing each non-ignored context element with the new content - return domManip( this, arguments, function( elem ) { - var parent = this.parentNode; - - if ( jQuery.inArray( this, ignored ) < 0 ) { - jQuery.cleanData( getAll( this ) ); - if ( parent ) { - parent.replaceChild( elem, this ); - } - } - - // Force callback invocation - }, ignored ); - } -} ); - -jQuery.each( { - appendTo: "append", - prependTo: "prepend", - insertBefore: "before", - insertAfter: "after", - replaceAll: "replaceWith" -}, function( name, original ) { - jQuery.fn[ name ] = function( selector ) { - var elems, - ret = [], - insert = jQuery( selector ), - last = insert.length - 1, - i = 0; - - for ( ; i <= last; i++ ) { - elems = i === last ? this : this.clone( true ); - jQuery( insert[ i ] )[ original ]( elems ); - - // Support: Android <=4.0 only, PhantomJS 1 only - // .get() because push.apply(_, arraylike) throws on ancient WebKit - push.apply( ret, elems.get() ); - } - - return this.pushStack( ret ); - }; -} ); -var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); - -var rcustomProp = /^--/; - - -var getStyles = function( elem ) { - - // Support: IE <=11 only, Firefox <=30 (trac-15098, trac-14150) - // IE throws on elements created in popups - // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" - var view = elem.ownerDocument.defaultView; - - if ( !view || !view.opener ) { - view = window; - } - - return view.getComputedStyle( elem ); - }; - -var swap = function( elem, options, callback ) { - var ret, name, - old = {}; - - // Remember the old values, and insert the new ones - for ( name in options ) { - old[ name ] = elem.style[ name ]; - elem.style[ name ] = options[ name ]; - } - - ret = callback.call( elem ); - - // Revert the old values - for ( name in options ) { - elem.style[ name ] = old[ name ]; - } - - return ret; -}; - - -var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" ); - - - -( function() { - - // Executing both pixelPosition & boxSizingReliable tests require only one layout - // so they're executed at the same time to save the second computation. - function computeStyleTests() { - - // This is a singleton, we need to execute it only once - if ( !div ) { - return; - } - - container.style.cssText = "position:absolute;left:-11111px;width:60px;" + - "margin-top:1px;padding:0;border:0"; - div.style.cssText = - "position:relative;display:block;box-sizing:border-box;overflow:scroll;" + - "margin:auto;border:1px;padding:1px;" + - "width:60%;top:1%"; - documentElement.appendChild( container ).appendChild( div ); - - var divStyle = window.getComputedStyle( div ); - pixelPositionVal = divStyle.top !== "1%"; - - // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44 - reliableMarginLeftVal = roundPixelMeasures( divStyle.marginLeft ) === 12; - - // Support: Android 4.0 - 4.3 only, Safari <=9.1 - 10.1, iOS <=7.0 - 9.3 - // Some styles come back with percentage values, even though they shouldn't - div.style.right = "60%"; - pixelBoxStylesVal = roundPixelMeasures( divStyle.right ) === 36; - - // Support: IE 9 - 11 only - // Detect misreporting of content dimensions for box-sizing:border-box elements - boxSizingReliableVal = roundPixelMeasures( divStyle.width ) === 36; - - // Support: IE 9 only - // Detect overflow:scroll screwiness (gh-3699) - // Support: Chrome <=64 - // Don't get tricked when zoom affects offsetWidth (gh-4029) - div.style.position = "absolute"; - scrollboxSizeVal = roundPixelMeasures( div.offsetWidth / 3 ) === 12; - - documentElement.removeChild( container ); - - // Nullify the div so it wouldn't be stored in the memory and - // it will also be a sign that checks already performed - div = null; - } - - function roundPixelMeasures( measure ) { - return Math.round( parseFloat( measure ) ); - } - - var pixelPositionVal, boxSizingReliableVal, scrollboxSizeVal, pixelBoxStylesVal, - reliableTrDimensionsVal, reliableMarginLeftVal, - container = document.createElement( "div" ), - div = document.createElement( "div" ); - - // Finish early in limited (non-browser) environments - if ( !div.style ) { - return; - } - - // Support: IE <=9 - 11 only - // Style of cloned element affects source element cloned (trac-8908) - div.style.backgroundClip = "content-box"; - div.cloneNode( true ).style.backgroundClip = ""; - support.clearCloneStyle = div.style.backgroundClip === "content-box"; - - jQuery.extend( support, { - boxSizingReliable: function() { - computeStyleTests(); - return boxSizingReliableVal; - }, - pixelBoxStyles: function() { - computeStyleTests(); - return pixelBoxStylesVal; - }, - pixelPosition: function() { - computeStyleTests(); - return pixelPositionVal; - }, - reliableMarginLeft: function() { - computeStyleTests(); - return reliableMarginLeftVal; - }, - scrollboxSize: function() { - computeStyleTests(); - return scrollboxSizeVal; - }, - - // Support: IE 9 - 11+, Edge 15 - 18+ - // IE/Edge misreport `getComputedStyle` of table rows with width/height - // set in CSS while `offset*` properties report correct values. - // Behavior in IE 9 is more subtle than in newer versions & it passes - // some versions of this test; make sure not to make it pass there! - // - // Support: Firefox 70+ - // Only Firefox includes border widths - // in computed dimensions. (gh-4529) - reliableTrDimensions: function() { - var table, tr, trChild, trStyle; - if ( reliableTrDimensionsVal == null ) { - table = document.createElement( "table" ); - tr = document.createElement( "tr" ); - trChild = document.createElement( "div" ); - - table.style.cssText = "position:absolute;left:-11111px;border-collapse:separate"; - tr.style.cssText = "box-sizing:content-box;border:1px solid"; - - // Support: Chrome 86+ - // Height set through cssText does not get applied. - // Computed height then comes back as 0. - tr.style.height = "1px"; - trChild.style.height = "9px"; - - // Support: Android 8 Chrome 86+ - // In our bodyBackground.html iframe, - // display for all div elements is set to "inline", - // which causes a problem only in Android 8 Chrome 86. - // Ensuring the div is `display: block` - // gets around this issue. - trChild.style.display = "block"; - - documentElement - .appendChild( table ) - .appendChild( tr ) - .appendChild( trChild ); - - trStyle = window.getComputedStyle( tr ); - reliableTrDimensionsVal = ( parseInt( trStyle.height, 10 ) + - parseInt( trStyle.borderTopWidth, 10 ) + - parseInt( trStyle.borderBottomWidth, 10 ) ) === tr.offsetHeight; - - documentElement.removeChild( table ); - } - return reliableTrDimensionsVal; - } - } ); -} )(); - - -function curCSS( elem, name, computed ) { - var width, minWidth, maxWidth, ret, - isCustomProp = rcustomProp.test( name ), - - // Support: Firefox 51+ - // Retrieving style before computed somehow - // fixes an issue with getting wrong values - // on detached elements - style = elem.style; - - computed = computed || getStyles( elem ); - - // getPropertyValue is needed for: - // .css('filter') (IE 9 only, trac-12537) - // .css('--customProperty) (gh-3144) - if ( computed ) { - - // Support: IE <=9 - 11+ - // IE only supports `"float"` in `getPropertyValue`; in computed styles - // it's only available as `"cssFloat"`. We no longer modify properties - // sent to `.css()` apart from camelCasing, so we need to check both. - // Normally, this would create difference in behavior: if - // `getPropertyValue` returns an empty string, the value returned - // by `.css()` would be `undefined`. This is usually the case for - // disconnected elements. However, in IE even disconnected elements - // with no styles return `"none"` for `getPropertyValue( "float" )` - ret = computed.getPropertyValue( name ) || computed[ name ]; - - if ( isCustomProp && ret ) { - - // Support: Firefox 105+, Chrome <=105+ - // Spec requires trimming whitespace for custom properties (gh-4926). - // Firefox only trims leading whitespace. Chrome just collapses - // both leading & trailing whitespace to a single space. - // - // Fall back to `undefined` if empty string returned. - // This collapses a missing definition with property defined - // and set to an empty string but there's no standard API - // allowing us to differentiate them without a performance penalty - // and returning `undefined` aligns with older jQuery. - // - // rtrimCSS treats U+000D CARRIAGE RETURN and U+000C FORM FEED - // as whitespace while CSS does not, but this is not a problem - // because CSS preprocessing replaces them with U+000A LINE FEED - // (which *is* CSS whitespace) - // https://www.w3.org/TR/css-syntax-3/#input-preprocessing - ret = ret.replace( rtrimCSS, "$1" ) || undefined; - } - - if ( ret === "" && !isAttached( elem ) ) { - ret = jQuery.style( elem, name ); - } - - // A tribute to the "awesome hack by Dean Edwards" - // Android Browser returns percentage for some values, - // but width seems to be reliably pixels. - // This is against the CSSOM draft spec: - // https://drafts.csswg.org/cssom/#resolved-values - if ( !support.pixelBoxStyles() && rnumnonpx.test( ret ) && rboxStyle.test( name ) ) { - - // Remember the original values - width = style.width; - minWidth = style.minWidth; - maxWidth = style.maxWidth; - - // Put in the new values to get a computed value out - style.minWidth = style.maxWidth = style.width = ret; - ret = computed.width; - - // Revert the changed values - style.width = width; - style.minWidth = minWidth; - style.maxWidth = maxWidth; - } - } - - return ret !== undefined ? - - // Support: IE <=9 - 11 only - // IE returns zIndex value as an integer. - ret + "" : - ret; -} - - -function addGetHookIf( conditionFn, hookFn ) { - - // Define the hook, we'll check on the first run if it's really needed. - return { - get: function() { - if ( conditionFn() ) { - - // Hook not needed (or it's not possible to use it due - // to missing dependency), remove it. - delete this.get; - return; - } - - // Hook needed; redefine it so that the support test is not executed again. - return ( this.get = hookFn ).apply( this, arguments ); - } - }; -} - - -var cssPrefixes = [ "Webkit", "Moz", "ms" ], - emptyStyle = document.createElement( "div" ).style, - vendorProps = {}; - -// Return a vendor-prefixed property or undefined -function vendorPropName( name ) { - - // Check for vendor prefixed names - var capName = name[ 0 ].toUpperCase() + name.slice( 1 ), - i = cssPrefixes.length; - - while ( i-- ) { - name = cssPrefixes[ i ] + capName; - if ( name in emptyStyle ) { - return name; - } - } -} - -// Return a potentially-mapped jQuery.cssProps or vendor prefixed property -function finalPropName( name ) { - var final = jQuery.cssProps[ name ] || vendorProps[ name ]; - - if ( final ) { - return final; - } - if ( name in emptyStyle ) { - return name; - } - return vendorProps[ name ] = vendorPropName( name ) || name; -} - - -var - - // Swappable if display is none or starts with table - // except "table", "table-cell", or "table-caption" - // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display - rdisplayswap = /^(none|table(?!-c[ea]).+)/, - cssShow = { position: "absolute", visibility: "hidden", display: "block" }, - cssNormalTransform = { - letterSpacing: "0", - fontWeight: "400" - }; - -function setPositiveNumber( _elem, value, subtract ) { - - // Any relative (+/-) values have already been - // normalized at this point - var matches = rcssNum.exec( value ); - return matches ? - - // Guard against undefined "subtract", e.g., when used as in cssHooks - Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) : - value; -} - -function boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computedVal ) { - var i = dimension === "width" ? 1 : 0, - extra = 0, - delta = 0, - marginDelta = 0; - - // Adjustment may not be necessary - if ( box === ( isBorderBox ? "border" : "content" ) ) { - return 0; - } - - for ( ; i < 4; i += 2 ) { - - // Both box models exclude margin - // Count margin delta separately to only add it after scroll gutter adjustment. - // This is needed to make negative margins work with `outerHeight( true )` (gh-3982). - if ( box === "margin" ) { - marginDelta += jQuery.css( elem, box + cssExpand[ i ], true, styles ); - } - - // If we get here with a content-box, we're seeking "padding" or "border" or "margin" - if ( !isBorderBox ) { - - // Add padding - delta += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); - - // For "border" or "margin", add border - if ( box !== "padding" ) { - delta += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); - - // But still keep track of it otherwise - } else { - extra += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); - } - - // If we get here with a border-box (content + padding + border), we're seeking "content" or - // "padding" or "margin" - } else { - - // For "content", subtract padding - if ( box === "content" ) { - delta -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); - } - - // For "content" or "padding", subtract border - if ( box !== "margin" ) { - delta -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); - } - } - } - - // Account for positive content-box scroll gutter when requested by providing computedVal - if ( !isBorderBox && computedVal >= 0 ) { - - // offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border - // Assuming integer scroll gutter, subtract the rest and round down - delta += Math.max( 0, Math.ceil( - elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - - computedVal - - delta - - extra - - 0.5 - - // If offsetWidth/offsetHeight is unknown, then we can't determine content-box scroll gutter - // Use an explicit zero to avoid NaN (gh-3964) - ) ) || 0; - } - - return delta + marginDelta; -} - -function getWidthOrHeight( elem, dimension, extra ) { - - // Start with computed style - var styles = getStyles( elem ), - - // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-4322). - // Fake content-box until we know it's needed to know the true value. - boxSizingNeeded = !support.boxSizingReliable() || extra, - isBorderBox = boxSizingNeeded && - jQuery.css( elem, "boxSizing", false, styles ) === "border-box", - valueIsBorderBox = isBorderBox, - - val = curCSS( elem, dimension, styles ), - offsetProp = "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ); - - // Support: Firefox <=54 - // Return a confounding non-pixel value or feign ignorance, as appropriate. - if ( rnumnonpx.test( val ) ) { - if ( !extra ) { - return val; - } - val = "auto"; - } - - - // Support: IE 9 - 11 only - // Use offsetWidth/offsetHeight for when box sizing is unreliable. - // In those cases, the computed value can be trusted to be border-box. - if ( ( !support.boxSizingReliable() && isBorderBox || - - // Support: IE 10 - 11+, Edge 15 - 18+ - // IE/Edge misreport `getComputedStyle` of table rows with width/height - // set in CSS while `offset*` properties report correct values. - // Interestingly, in some cases IE 9 doesn't suffer from this issue. - !support.reliableTrDimensions() && nodeName( elem, "tr" ) || - - // Fall back to offsetWidth/offsetHeight when value is "auto" - // This happens for inline elements with no explicit setting (gh-3571) - val === "auto" || - - // Support: Android <=4.1 - 4.3 only - // Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602) - !parseFloat( val ) && jQuery.css( elem, "display", false, styles ) === "inline" ) && - - // Make sure the element is visible & connected - elem.getClientRects().length ) { - - isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; - - // Where available, offsetWidth/offsetHeight approximate border box dimensions. - // Where not available (e.g., SVG), assume unreliable box-sizing and interpret the - // retrieved value as a content box dimension. - valueIsBorderBox = offsetProp in elem; - if ( valueIsBorderBox ) { - val = elem[ offsetProp ]; - } - } - - // Normalize "" and auto - val = parseFloat( val ) || 0; - - // Adjust for the element's box model - return ( val + - boxModelAdjustment( - elem, - dimension, - extra || ( isBorderBox ? "border" : "content" ), - valueIsBorderBox, - styles, - - // Provide the current computed size to request scroll gutter calculation (gh-3589) - val - ) - ) + "px"; -} - -jQuery.extend( { - - // Add in style property hooks for overriding the default - // behavior of getting and setting a style property - cssHooks: { - opacity: { - get: function( elem, computed ) { - if ( computed ) { - - // We should always get a number back from opacity - var ret = curCSS( elem, "opacity" ); - return ret === "" ? "1" : ret; - } - } - } - }, - - // Don't automatically add "px" to these possibly-unitless properties - cssNumber: { - animationIterationCount: true, - aspectRatio: true, - borderImageSlice: true, - columnCount: true, - flexGrow: true, - flexShrink: true, - fontWeight: true, - gridArea: true, - gridColumn: true, - gridColumnEnd: true, - gridColumnStart: true, - gridRow: true, - gridRowEnd: true, - gridRowStart: true, - lineHeight: true, - opacity: true, - order: true, - orphans: true, - scale: true, - widows: true, - zIndex: true, - zoom: true, - - // SVG-related - fillOpacity: true, - floodOpacity: true, - stopOpacity: true, - strokeMiterlimit: true, - strokeOpacity: true - }, - - // Add in properties whose names you wish to fix before - // setting or getting the value - cssProps: {}, - - // Get and set the style property on a DOM Node - style: function( elem, name, value, extra ) { - - // Don't set styles on text and comment nodes - if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { - return; - } - - // Make sure that we're working with the right name - var ret, type, hooks, - origName = camelCase( name ), - isCustomProp = rcustomProp.test( name ), - style = elem.style; - - // Make sure that we're working with the right name. We don't - // want to query the value if it is a CSS custom property - // since they are user-defined. - if ( !isCustomProp ) { - name = finalPropName( origName ); - } - - // Gets hook for the prefixed version, then unprefixed version - hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; - - // Check if we're setting a value - if ( value !== undefined ) { - type = typeof value; - - // Convert "+=" or "-=" to relative numbers (trac-7345) - if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) { - value = adjustCSS( elem, name, ret ); - - // Fixes bug trac-9237 - type = "number"; - } - - // Make sure that null and NaN values aren't set (trac-7116) - if ( value == null || value !== value ) { - return; - } - - // If a number was passed in, add the unit (except for certain CSS properties) - // The isCustomProp check can be removed in jQuery 4.0 when we only auto-append - // "px" to a few hardcoded values. - if ( type === "number" && !isCustomProp ) { - value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" ); - } - - // background-* props affect original clone's values - if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) { - style[ name ] = "inherit"; - } - - // If a hook was provided, use that value, otherwise just set the specified value - if ( !hooks || !( "set" in hooks ) || - ( value = hooks.set( elem, value, extra ) ) !== undefined ) { - - if ( isCustomProp ) { - style.setProperty( name, value ); - } else { - style[ name ] = value; - } - } - - } else { - - // If a hook was provided get the non-computed value from there - if ( hooks && "get" in hooks && - ( ret = hooks.get( elem, false, extra ) ) !== undefined ) { - - return ret; - } - - // Otherwise just get the value from the style object - return style[ name ]; - } - }, - - css: function( elem, name, extra, styles ) { - var val, num, hooks, - origName = camelCase( name ), - isCustomProp = rcustomProp.test( name ); - - // Make sure that we're working with the right name. We don't - // want to modify the value if it is a CSS custom property - // since they are user-defined. - if ( !isCustomProp ) { - name = finalPropName( origName ); - } - - // Try prefixed name followed by the unprefixed name - hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; - - // If a hook was provided get the computed value from there - if ( hooks && "get" in hooks ) { - val = hooks.get( elem, true, extra ); - } - - // Otherwise, if a way to get the computed value exists, use that - if ( val === undefined ) { - val = curCSS( elem, name, styles ); - } - - // Convert "normal" to computed value - if ( val === "normal" && name in cssNormalTransform ) { - val = cssNormalTransform[ name ]; - } - - // Make numeric if forced or a qualifier was provided and val looks numeric - if ( extra === "" || extra ) { - num = parseFloat( val ); - return extra === true || isFinite( num ) ? num || 0 : val; - } - - return val; - } -} ); - -jQuery.each( [ "height", "width" ], function( _i, dimension ) { - jQuery.cssHooks[ dimension ] = { - get: function( elem, computed, extra ) { - if ( computed ) { - - // Certain elements can have dimension info if we invisibly show them - // but it must have a current display style that would benefit - return rdisplayswap.test( jQuery.css( elem, "display" ) ) && - - // Support: Safari 8+ - // Table columns in Safari have non-zero offsetWidth & zero - // getBoundingClientRect().width unless display is changed. - // Support: IE <=11 only - // Running getBoundingClientRect on a disconnected node - // in IE throws an error. - ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ? - swap( elem, cssShow, function() { - return getWidthOrHeight( elem, dimension, extra ); - } ) : - getWidthOrHeight( elem, dimension, extra ); - } - }, - - set: function( elem, value, extra ) { - var matches, - styles = getStyles( elem ), - - // Only read styles.position if the test has a chance to fail - // to avoid forcing a reflow. - scrollboxSizeBuggy = !support.scrollboxSize() && - styles.position === "absolute", - - // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-3991) - boxSizingNeeded = scrollboxSizeBuggy || extra, - isBorderBox = boxSizingNeeded && - jQuery.css( elem, "boxSizing", false, styles ) === "border-box", - subtract = extra ? - boxModelAdjustment( - elem, - dimension, - extra, - isBorderBox, - styles - ) : - 0; - - // Account for unreliable border-box dimensions by comparing offset* to computed and - // faking a content-box to get border and padding (gh-3699) - if ( isBorderBox && scrollboxSizeBuggy ) { - subtract -= Math.ceil( - elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - - parseFloat( styles[ dimension ] ) - - boxModelAdjustment( elem, dimension, "border", false, styles ) - - 0.5 - ); - } - - // Convert to pixels if value adjustment is needed - if ( subtract && ( matches = rcssNum.exec( value ) ) && - ( matches[ 3 ] || "px" ) !== "px" ) { - - elem.style[ dimension ] = value; - value = jQuery.css( elem, dimension ); - } - - return setPositiveNumber( elem, value, subtract ); - } - }; -} ); - -jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft, - function( elem, computed ) { - if ( computed ) { - return ( parseFloat( curCSS( elem, "marginLeft" ) ) || - elem.getBoundingClientRect().left - - swap( elem, { marginLeft: 0 }, function() { - return elem.getBoundingClientRect().left; - } ) - ) + "px"; - } - } -); - -// These hooks are used by animate to expand properties -jQuery.each( { - margin: "", - padding: "", - border: "Width" -}, function( prefix, suffix ) { - jQuery.cssHooks[ prefix + suffix ] = { - expand: function( value ) { - var i = 0, - expanded = {}, - - // Assumes a single number if not a string - parts = typeof value === "string" ? value.split( " " ) : [ value ]; - - for ( ; i < 4; i++ ) { - expanded[ prefix + cssExpand[ i ] + suffix ] = - parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; - } - - return expanded; - } - }; - - if ( prefix !== "margin" ) { - jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; - } -} ); - -jQuery.fn.extend( { - css: function( name, value ) { - return access( this, function( elem, name, value ) { - var styles, len, - map = {}, - i = 0; - - if ( Array.isArray( name ) ) { - styles = getStyles( elem ); - len = name.length; - - for ( ; i < len; i++ ) { - map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); - } - - return map; - } - - return value !== undefined ? - jQuery.style( elem, name, value ) : - jQuery.css( elem, name ); - }, name, value, arguments.length > 1 ); - } -} ); - - -function Tween( elem, options, prop, end, easing ) { - return new Tween.prototype.init( elem, options, prop, end, easing ); -} -jQuery.Tween = Tween; - -Tween.prototype = { - constructor: Tween, - init: function( elem, options, prop, end, easing, unit ) { - this.elem = elem; - this.prop = prop; - this.easing = easing || jQuery.easing._default; - this.options = options; - this.start = this.now = this.cur(); - this.end = end; - this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); - }, - cur: function() { - var hooks = Tween.propHooks[ this.prop ]; - - return hooks && hooks.get ? - hooks.get( this ) : - Tween.propHooks._default.get( this ); - }, - run: function( percent ) { - var eased, - hooks = Tween.propHooks[ this.prop ]; - - if ( this.options.duration ) { - this.pos = eased = jQuery.easing[ this.easing ]( - percent, this.options.duration * percent, 0, 1, this.options.duration - ); - } else { - this.pos = eased = percent; - } - this.now = ( this.end - this.start ) * eased + this.start; - - if ( this.options.step ) { - this.options.step.call( this.elem, this.now, this ); - } - - if ( hooks && hooks.set ) { - hooks.set( this ); - } else { - Tween.propHooks._default.set( this ); - } - return this; - } -}; - -Tween.prototype.init.prototype = Tween.prototype; - -Tween.propHooks = { - _default: { - get: function( tween ) { - var result; - - // Use a property on the element directly when it is not a DOM element, - // or when there is no matching style property that exists. - if ( tween.elem.nodeType !== 1 || - tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) { - return tween.elem[ tween.prop ]; - } - - // Passing an empty string as a 3rd parameter to .css will automatically - // attempt a parseFloat and fallback to a string if the parse fails. - // Simple values such as "10px" are parsed to Float; - // complex values such as "rotate(1rad)" are returned as-is. - result = jQuery.css( tween.elem, tween.prop, "" ); - - // Empty strings, null, undefined and "auto" are converted to 0. - return !result || result === "auto" ? 0 : result; - }, - set: function( tween ) { - - // Use step hook for back compat. - // Use cssHook if its there. - // Use .style if available and use plain properties where available. - if ( jQuery.fx.step[ tween.prop ] ) { - jQuery.fx.step[ tween.prop ]( tween ); - } else if ( tween.elem.nodeType === 1 && ( - jQuery.cssHooks[ tween.prop ] || - tween.elem.style[ finalPropName( tween.prop ) ] != null ) ) { - jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); - } else { - tween.elem[ tween.prop ] = tween.now; - } - } - } -}; - -// Support: IE <=9 only -// Panic based approach to setting things on disconnected nodes -Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { - set: function( tween ) { - if ( tween.elem.nodeType && tween.elem.parentNode ) { - tween.elem[ tween.prop ] = tween.now; - } - } -}; - -jQuery.easing = { - linear: function( p ) { - return p; - }, - swing: function( p ) { - return 0.5 - Math.cos( p * Math.PI ) / 2; - }, - _default: "swing" -}; - -jQuery.fx = Tween.prototype.init; - -// Back compat <1.8 extension point -jQuery.fx.step = {}; - - - - -var - fxNow, inProgress, - rfxtypes = /^(?:toggle|show|hide)$/, - rrun = /queueHooks$/; - -function schedule() { - if ( inProgress ) { - if ( document.hidden === false && window.requestAnimationFrame ) { - window.requestAnimationFrame( schedule ); - } else { - window.setTimeout( schedule, jQuery.fx.interval ); - } - - jQuery.fx.tick(); - } -} - -// Animations created synchronously will run synchronously -function createFxNow() { - window.setTimeout( function() { - fxNow = undefined; - } ); - return ( fxNow = Date.now() ); -} - -// Generate parameters to create a standard animation -function genFx( type, includeWidth ) { - var which, - i = 0, - attrs = { height: type }; - - // If we include width, step value is 1 to do all cssExpand values, - // otherwise step value is 2 to skip over Left and Right - includeWidth = includeWidth ? 1 : 0; - for ( ; i < 4; i += 2 - includeWidth ) { - which = cssExpand[ i ]; - attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; - } - - if ( includeWidth ) { - attrs.opacity = attrs.width = type; - } - - return attrs; -} - -function createTween( value, prop, animation ) { - var tween, - collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ), - index = 0, - length = collection.length; - for ( ; index < length; index++ ) { - if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) { - - // We're done with this property - return tween; - } - } -} - -function defaultPrefilter( elem, props, opts ) { - var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display, - isBox = "width" in props || "height" in props, - anim = this, - orig = {}, - style = elem.style, - hidden = elem.nodeType && isHiddenWithinTree( elem ), - dataShow = dataPriv.get( elem, "fxshow" ); - - // Queue-skipping animations hijack the fx hooks - if ( !opts.queue ) { - hooks = jQuery._queueHooks( elem, "fx" ); - if ( hooks.unqueued == null ) { - hooks.unqueued = 0; - oldfire = hooks.empty.fire; - hooks.empty.fire = function() { - if ( !hooks.unqueued ) { - oldfire(); - } - }; - } - hooks.unqueued++; - - anim.always( function() { - - // Ensure the complete handler is called before this completes - anim.always( function() { - hooks.unqueued--; - if ( !jQuery.queue( elem, "fx" ).length ) { - hooks.empty.fire(); - } - } ); - } ); - } - - // Detect show/hide animations - for ( prop in props ) { - value = props[ prop ]; - if ( rfxtypes.test( value ) ) { - delete props[ prop ]; - toggle = toggle || value === "toggle"; - if ( value === ( hidden ? "hide" : "show" ) ) { - - // Pretend to be hidden if this is a "show" and - // there is still data from a stopped show/hide - if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) { - hidden = true; - - // Ignore all other no-op show/hide data - } else { - continue; - } - } - orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop ); - } - } - - // Bail out if this is a no-op like .hide().hide() - propTween = !jQuery.isEmptyObject( props ); - if ( !propTween && jQuery.isEmptyObject( orig ) ) { - return; - } - - // Restrict "overflow" and "display" styles during box animations - if ( isBox && elem.nodeType === 1 ) { - - // Support: IE <=9 - 11, Edge 12 - 15 - // Record all 3 overflow attributes because IE does not infer the shorthand - // from identically-valued overflowX and overflowY and Edge just mirrors - // the overflowX value there. - opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; - - // Identify a display type, preferring old show/hide data over the CSS cascade - restoreDisplay = dataShow && dataShow.display; - if ( restoreDisplay == null ) { - restoreDisplay = dataPriv.get( elem, "display" ); - } - display = jQuery.css( elem, "display" ); - if ( display === "none" ) { - if ( restoreDisplay ) { - display = restoreDisplay; - } else { - - // Get nonempty value(s) by temporarily forcing visibility - showHide( [ elem ], true ); - restoreDisplay = elem.style.display || restoreDisplay; - display = jQuery.css( elem, "display" ); - showHide( [ elem ] ); - } - } - - // Animate inline elements as inline-block - if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) { - if ( jQuery.css( elem, "float" ) === "none" ) { - - // Restore the original display value at the end of pure show/hide animations - if ( !propTween ) { - anim.done( function() { - style.display = restoreDisplay; - } ); - if ( restoreDisplay == null ) { - display = style.display; - restoreDisplay = display === "none" ? "" : display; - } - } - style.display = "inline-block"; - } - } - } - - if ( opts.overflow ) { - style.overflow = "hidden"; - anim.always( function() { - style.overflow = opts.overflow[ 0 ]; - style.overflowX = opts.overflow[ 1 ]; - style.overflowY = opts.overflow[ 2 ]; - } ); - } - - // Implement show/hide animations - propTween = false; - for ( prop in orig ) { - - // General show/hide setup for this element animation - if ( !propTween ) { - if ( dataShow ) { - if ( "hidden" in dataShow ) { - hidden = dataShow.hidden; - } - } else { - dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } ); - } - - // Store hidden/visible for toggle so `.stop().toggle()` "reverses" - if ( toggle ) { - dataShow.hidden = !hidden; - } - - // Show elements before animating them - if ( hidden ) { - showHide( [ elem ], true ); - } - - /* eslint-disable no-loop-func */ - - anim.done( function() { - - /* eslint-enable no-loop-func */ - - // The final step of a "hide" animation is actually hiding the element - if ( !hidden ) { - showHide( [ elem ] ); - } - dataPriv.remove( elem, "fxshow" ); - for ( prop in orig ) { - jQuery.style( elem, prop, orig[ prop ] ); - } - } ); - } - - // Per-property setup - propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim ); - if ( !( prop in dataShow ) ) { - dataShow[ prop ] = propTween.start; - if ( hidden ) { - propTween.end = propTween.start; - propTween.start = 0; - } - } - } -} - -function propFilter( props, specialEasing ) { - var index, name, easing, value, hooks; - - // camelCase, specialEasing and expand cssHook pass - for ( index in props ) { - name = camelCase( index ); - easing = specialEasing[ name ]; - value = props[ index ]; - if ( Array.isArray( value ) ) { - easing = value[ 1 ]; - value = props[ index ] = value[ 0 ]; - } - - if ( index !== name ) { - props[ name ] = value; - delete props[ index ]; - } - - hooks = jQuery.cssHooks[ name ]; - if ( hooks && "expand" in hooks ) { - value = hooks.expand( value ); - delete props[ name ]; - - // Not quite $.extend, this won't overwrite existing keys. - // Reusing 'index' because we have the correct "name" - for ( index in value ) { - if ( !( index in props ) ) { - props[ index ] = value[ index ]; - specialEasing[ index ] = easing; - } - } - } else { - specialEasing[ name ] = easing; - } - } -} - -function Animation( elem, properties, options ) { - var result, - stopped, - index = 0, - length = Animation.prefilters.length, - deferred = jQuery.Deferred().always( function() { - - // Don't match elem in the :animated selector - delete tick.elem; - } ), - tick = function() { - if ( stopped ) { - return false; - } - var currentTime = fxNow || createFxNow(), - remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), - - // Support: Android 2.3 only - // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (trac-12497) - temp = remaining / animation.duration || 0, - percent = 1 - temp, - index = 0, - length = animation.tweens.length; - - for ( ; index < length; index++ ) { - animation.tweens[ index ].run( percent ); - } - - deferred.notifyWith( elem, [ animation, percent, remaining ] ); - - // If there's more to do, yield - if ( percent < 1 && length ) { - return remaining; - } - - // If this was an empty animation, synthesize a final progress notification - if ( !length ) { - deferred.notifyWith( elem, [ animation, 1, 0 ] ); - } - - // Resolve the animation and report its conclusion - deferred.resolveWith( elem, [ animation ] ); - return false; - }, - animation = deferred.promise( { - elem: elem, - props: jQuery.extend( {}, properties ), - opts: jQuery.extend( true, { - specialEasing: {}, - easing: jQuery.easing._default - }, options ), - originalProperties: properties, - originalOptions: options, - startTime: fxNow || createFxNow(), - duration: options.duration, - tweens: [], - createTween: function( prop, end ) { - var tween = jQuery.Tween( elem, animation.opts, prop, end, - animation.opts.specialEasing[ prop ] || animation.opts.easing ); - animation.tweens.push( tween ); - return tween; - }, - stop: function( gotoEnd ) { - var index = 0, - - // If we are going to the end, we want to run all the tweens - // otherwise we skip this part - length = gotoEnd ? animation.tweens.length : 0; - if ( stopped ) { - return this; - } - stopped = true; - for ( ; index < length; index++ ) { - animation.tweens[ index ].run( 1 ); - } - - // Resolve when we played the last frame; otherwise, reject - if ( gotoEnd ) { - deferred.notifyWith( elem, [ animation, 1, 0 ] ); - deferred.resolveWith( elem, [ animation, gotoEnd ] ); - } else { - deferred.rejectWith( elem, [ animation, gotoEnd ] ); - } - return this; - } - } ), - props = animation.props; - - propFilter( props, animation.opts.specialEasing ); - - for ( ; index < length; index++ ) { - result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts ); - if ( result ) { - if ( isFunction( result.stop ) ) { - jQuery._queueHooks( animation.elem, animation.opts.queue ).stop = - result.stop.bind( result ); - } - return result; - } - } - - jQuery.map( props, createTween, animation ); - - if ( isFunction( animation.opts.start ) ) { - animation.opts.start.call( elem, animation ); - } - - // Attach callbacks from options - animation - .progress( animation.opts.progress ) - .done( animation.opts.done, animation.opts.complete ) - .fail( animation.opts.fail ) - .always( animation.opts.always ); - - jQuery.fx.timer( - jQuery.extend( tick, { - elem: elem, - anim: animation, - queue: animation.opts.queue - } ) - ); - - return animation; -} - -jQuery.Animation = jQuery.extend( Animation, { - - tweeners: { - "*": [ function( prop, value ) { - var tween = this.createTween( prop, value ); - adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween ); - return tween; - } ] - }, - - tweener: function( props, callback ) { - if ( isFunction( props ) ) { - callback = props; - props = [ "*" ]; - } else { - props = props.match( rnothtmlwhite ); - } - - var prop, - index = 0, - length = props.length; - - for ( ; index < length; index++ ) { - prop = props[ index ]; - Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || []; - Animation.tweeners[ prop ].unshift( callback ); - } - }, - - prefilters: [ defaultPrefilter ], - - prefilter: function( callback, prepend ) { - if ( prepend ) { - Animation.prefilters.unshift( callback ); - } else { - Animation.prefilters.push( callback ); - } - } -} ); - -jQuery.speed = function( speed, easing, fn ) { - var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { - complete: fn || !fn && easing || - isFunction( speed ) && speed, - duration: speed, - easing: fn && easing || easing && !isFunction( easing ) && easing - }; - - // Go to the end state if fx are off - if ( jQuery.fx.off ) { - opt.duration = 0; - - } else { - if ( typeof opt.duration !== "number" ) { - if ( opt.duration in jQuery.fx.speeds ) { - opt.duration = jQuery.fx.speeds[ opt.duration ]; - - } else { - opt.duration = jQuery.fx.speeds._default; - } - } - } - - // Normalize opt.queue - true/undefined/null -> "fx" - if ( opt.queue == null || opt.queue === true ) { - opt.queue = "fx"; - } - - // Queueing - opt.old = opt.complete; - - opt.complete = function() { - if ( isFunction( opt.old ) ) { - opt.old.call( this ); - } - - if ( opt.queue ) { - jQuery.dequeue( this, opt.queue ); - } - }; - - return opt; -}; - -jQuery.fn.extend( { - fadeTo: function( speed, to, easing, callback ) { - - // Show any hidden elements after setting opacity to 0 - return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show() - - // Animate to the value specified - .end().animate( { opacity: to }, speed, easing, callback ); - }, - animate: function( prop, speed, easing, callback ) { - var empty = jQuery.isEmptyObject( prop ), - optall = jQuery.speed( speed, easing, callback ), - doAnimation = function() { - - // Operate on a copy of prop so per-property easing won't be lost - var anim = Animation( this, jQuery.extend( {}, prop ), optall ); - - // Empty animations, or finishing resolves immediately - if ( empty || dataPriv.get( this, "finish" ) ) { - anim.stop( true ); - } - }; - - doAnimation.finish = doAnimation; - - return empty || optall.queue === false ? - this.each( doAnimation ) : - this.queue( optall.queue, doAnimation ); - }, - stop: function( type, clearQueue, gotoEnd ) { - var stopQueue = function( hooks ) { - var stop = hooks.stop; - delete hooks.stop; - stop( gotoEnd ); - }; - - if ( typeof type !== "string" ) { - gotoEnd = clearQueue; - clearQueue = type; - type = undefined; - } - if ( clearQueue ) { - this.queue( type || "fx", [] ); - } - - return this.each( function() { - var dequeue = true, - index = type != null && type + "queueHooks", - timers = jQuery.timers, - data = dataPriv.get( this ); - - if ( index ) { - if ( data[ index ] && data[ index ].stop ) { - stopQueue( data[ index ] ); - } - } else { - for ( index in data ) { - if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { - stopQueue( data[ index ] ); - } - } - } - - for ( index = timers.length; index--; ) { - if ( timers[ index ].elem === this && - ( type == null || timers[ index ].queue === type ) ) { - - timers[ index ].anim.stop( gotoEnd ); - dequeue = false; - timers.splice( index, 1 ); - } - } - - // Start the next in the queue if the last step wasn't forced. - // Timers currently will call their complete callbacks, which - // will dequeue but only if they were gotoEnd. - if ( dequeue || !gotoEnd ) { - jQuery.dequeue( this, type ); - } - } ); - }, - finish: function( type ) { - if ( type !== false ) { - type = type || "fx"; - } - return this.each( function() { - var index, - data = dataPriv.get( this ), - queue = data[ type + "queue" ], - hooks = data[ type + "queueHooks" ], - timers = jQuery.timers, - length = queue ? queue.length : 0; - - // Enable finishing flag on private data - data.finish = true; - - // Empty the queue first - jQuery.queue( this, type, [] ); - - if ( hooks && hooks.stop ) { - hooks.stop.call( this, true ); - } - - // Look for any active animations, and finish them - for ( index = timers.length; index--; ) { - if ( timers[ index ].elem === this && timers[ index ].queue === type ) { - timers[ index ].anim.stop( true ); - timers.splice( index, 1 ); - } - } - - // Look for any animations in the old queue and finish them - for ( index = 0; index < length; index++ ) { - if ( queue[ index ] && queue[ index ].finish ) { - queue[ index ].finish.call( this ); - } - } - - // Turn off finishing flag - delete data.finish; - } ); - } -} ); - -jQuery.each( [ "toggle", "show", "hide" ], function( _i, name ) { - var cssFn = jQuery.fn[ name ]; - jQuery.fn[ name ] = function( speed, easing, callback ) { - return speed == null || typeof speed === "boolean" ? - cssFn.apply( this, arguments ) : - this.animate( genFx( name, true ), speed, easing, callback ); - }; -} ); - -// Generate shortcuts for custom animations -jQuery.each( { - slideDown: genFx( "show" ), - slideUp: genFx( "hide" ), - slideToggle: genFx( "toggle" ), - fadeIn: { opacity: "show" }, - fadeOut: { opacity: "hide" }, - fadeToggle: { opacity: "toggle" } -}, function( name, props ) { - jQuery.fn[ name ] = function( speed, easing, callback ) { - return this.animate( props, speed, easing, callback ); - }; -} ); - -jQuery.timers = []; -jQuery.fx.tick = function() { - var timer, - i = 0, - timers = jQuery.timers; - - fxNow = Date.now(); - - for ( ; i < timers.length; i++ ) { - timer = timers[ i ]; - - // Run the timer and safely remove it when done (allowing for external removal) - if ( !timer() && timers[ i ] === timer ) { - timers.splice( i--, 1 ); - } - } - - if ( !timers.length ) { - jQuery.fx.stop(); - } - fxNow = undefined; -}; - -jQuery.fx.timer = function( timer ) { - jQuery.timers.push( timer ); - jQuery.fx.start(); -}; - -jQuery.fx.interval = 13; -jQuery.fx.start = function() { - if ( inProgress ) { - return; - } - - inProgress = true; - schedule(); -}; - -jQuery.fx.stop = function() { - inProgress = null; -}; - -jQuery.fx.speeds = { - slow: 600, - fast: 200, - - // Default speed - _default: 400 -}; - - -// Based off of the plugin by Clint Helfers, with permission. -jQuery.fn.delay = function( time, type ) { - time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; - type = type || "fx"; - - return this.queue( type, function( next, hooks ) { - var timeout = window.setTimeout( next, time ); - hooks.stop = function() { - window.clearTimeout( timeout ); - }; - } ); -}; - - -( function() { - var input = document.createElement( "input" ), - select = document.createElement( "select" ), - opt = select.appendChild( document.createElement( "option" ) ); - - input.type = "checkbox"; - - // Support: Android <=4.3 only - // Default value for a checkbox should be "on" - support.checkOn = input.value !== ""; - - // Support: IE <=11 only - // Must access selectedIndex to make default options select - support.optSelected = opt.selected; - - // Support: IE <=11 only - // An input loses its value after becoming a radio - input = document.createElement( "input" ); - input.value = "t"; - input.type = "radio"; - support.radioValue = input.value === "t"; -} )(); - - -var boolHook, - attrHandle = jQuery.expr.attrHandle; - -jQuery.fn.extend( { - attr: function( name, value ) { - return access( this, jQuery.attr, name, value, arguments.length > 1 ); - }, - - removeAttr: function( name ) { - return this.each( function() { - jQuery.removeAttr( this, name ); - } ); - } -} ); - -jQuery.extend( { - attr: function( elem, name, value ) { - var ret, hooks, - nType = elem.nodeType; - - // Don't get/set attributes on text, comment and attribute nodes - if ( nType === 3 || nType === 8 || nType === 2 ) { - return; - } - - // Fallback to prop when attributes are not supported - if ( typeof elem.getAttribute === "undefined" ) { - return jQuery.prop( elem, name, value ); - } - - // Attribute hooks are determined by the lowercase version - // Grab necessary hook if one is defined - if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { - hooks = jQuery.attrHooks[ name.toLowerCase() ] || - ( jQuery.expr.match.bool.test( name ) ? boolHook : undefined ); - } - - if ( value !== undefined ) { - if ( value === null ) { - jQuery.removeAttr( elem, name ); - return; - } - - if ( hooks && "set" in hooks && - ( ret = hooks.set( elem, value, name ) ) !== undefined ) { - return ret; - } - - elem.setAttribute( name, value + "" ); - return value; - } - - if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { - return ret; - } - - ret = jQuery.find.attr( elem, name ); - - // Non-existent attributes return null, we normalize to undefined - return ret == null ? undefined : ret; - }, - - attrHooks: { - type: { - set: function( elem, value ) { - if ( !support.radioValue && value === "radio" && - nodeName( elem, "input" ) ) { - var val = elem.value; - elem.setAttribute( "type", value ); - if ( val ) { - elem.value = val; - } - return value; - } - } - } - }, - - removeAttr: function( elem, value ) { - var name, - i = 0, - - // Attribute names can contain non-HTML whitespace characters - // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 - attrNames = value && value.match( rnothtmlwhite ); - - if ( attrNames && elem.nodeType === 1 ) { - while ( ( name = attrNames[ i++ ] ) ) { - elem.removeAttribute( name ); - } - } - } -} ); - -// Hooks for boolean attributes -boolHook = { - set: function( elem, value, name ) { - if ( value === false ) { - - // Remove boolean attributes when set to false - jQuery.removeAttr( elem, name ); - } else { - elem.setAttribute( name, name ); - } - return name; - } -}; - -jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( _i, name ) { - var getter = attrHandle[ name ] || jQuery.find.attr; - - attrHandle[ name ] = function( elem, name, isXML ) { - var ret, handle, - lowercaseName = name.toLowerCase(); - - if ( !isXML ) { - - // Avoid an infinite loop by temporarily removing this function from the getter - handle = attrHandle[ lowercaseName ]; - attrHandle[ lowercaseName ] = ret; - ret = getter( elem, name, isXML ) != null ? - lowercaseName : - null; - attrHandle[ lowercaseName ] = handle; - } - return ret; - }; -} ); - - - - -var rfocusable = /^(?:input|select|textarea|button)$/i, - rclickable = /^(?:a|area)$/i; - -jQuery.fn.extend( { - prop: function( name, value ) { - return access( this, jQuery.prop, name, value, arguments.length > 1 ); - }, - - removeProp: function( name ) { - return this.each( function() { - delete this[ jQuery.propFix[ name ] || name ]; - } ); - } -} ); - -jQuery.extend( { - prop: function( elem, name, value ) { - var ret, hooks, - nType = elem.nodeType; - - // Don't get/set properties on text, comment and attribute nodes - if ( nType === 3 || nType === 8 || nType === 2 ) { - return; - } - - if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { - - // Fix name and attach hooks - name = jQuery.propFix[ name ] || name; - hooks = jQuery.propHooks[ name ]; - } - - if ( value !== undefined ) { - if ( hooks && "set" in hooks && - ( ret = hooks.set( elem, value, name ) ) !== undefined ) { - return ret; - } - - return ( elem[ name ] = value ); - } - - if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { - return ret; - } - - return elem[ name ]; - }, - - propHooks: { - tabIndex: { - get: function( elem ) { - - // Support: IE <=9 - 11 only - // elem.tabIndex doesn't always return the - // correct value when it hasn't been explicitly set - // Use proper attribute retrieval (trac-12072) - var tabindex = jQuery.find.attr( elem, "tabindex" ); - - if ( tabindex ) { - return parseInt( tabindex, 10 ); - } - - if ( - rfocusable.test( elem.nodeName ) || - rclickable.test( elem.nodeName ) && - elem.href - ) { - return 0; - } - - return -1; - } - } - }, - - propFix: { - "for": "htmlFor", - "class": "className" - } -} ); - -// Support: IE <=11 only -// Accessing the selectedIndex property -// forces the browser to respect setting selected -// on the option -// The getter ensures a default option is selected -// when in an optgroup -// eslint rule "no-unused-expressions" is disabled for this code -// since it considers such accessions noop -if ( !support.optSelected ) { - jQuery.propHooks.selected = { - get: function( elem ) { - - /* eslint no-unused-expressions: "off" */ - - var parent = elem.parentNode; - if ( parent && parent.parentNode ) { - parent.parentNode.selectedIndex; - } - return null; - }, - set: function( elem ) { - - /* eslint no-unused-expressions: "off" */ - - var parent = elem.parentNode; - if ( parent ) { - parent.selectedIndex; - - if ( parent.parentNode ) { - parent.parentNode.selectedIndex; - } - } - } - }; -} - -jQuery.each( [ - "tabIndex", - "readOnly", - "maxLength", - "cellSpacing", - "cellPadding", - "rowSpan", - "colSpan", - "useMap", - "frameBorder", - "contentEditable" -], function() { - jQuery.propFix[ this.toLowerCase() ] = this; -} ); - - - - - // Strip and collapse whitespace according to HTML spec - // https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace - function stripAndCollapse( value ) { - var tokens = value.match( rnothtmlwhite ) || []; - return tokens.join( " " ); - } - - -function getClass( elem ) { - return elem.getAttribute && elem.getAttribute( "class" ) || ""; -} - -function classesToArray( value ) { - if ( Array.isArray( value ) ) { - return value; - } - if ( typeof value === "string" ) { - return value.match( rnothtmlwhite ) || []; - } - return []; -} - -jQuery.fn.extend( { - addClass: function( value ) { - var classNames, cur, curValue, className, i, finalValue; - - if ( isFunction( value ) ) { - return this.each( function( j ) { - jQuery( this ).addClass( value.call( this, j, getClass( this ) ) ); - } ); - } - - classNames = classesToArray( value ); - - if ( classNames.length ) { - return this.each( function() { - curValue = getClass( this ); - cur = this.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); - - if ( cur ) { - for ( i = 0; i < classNames.length; i++ ) { - className = classNames[ i ]; - if ( cur.indexOf( " " + className + " " ) < 0 ) { - cur += className + " "; - } - } - - // Only assign if different to avoid unneeded rendering. - finalValue = stripAndCollapse( cur ); - if ( curValue !== finalValue ) { - this.setAttribute( "class", finalValue ); - } - } - } ); - } - - return this; - }, - - removeClass: function( value ) { - var classNames, cur, curValue, className, i, finalValue; - - if ( isFunction( value ) ) { - return this.each( function( j ) { - jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) ); - } ); - } - - if ( !arguments.length ) { - return this.attr( "class", "" ); - } - - classNames = classesToArray( value ); - - if ( classNames.length ) { - return this.each( function() { - curValue = getClass( this ); - - // This expression is here for better compressibility (see addClass) - cur = this.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); - - if ( cur ) { - for ( i = 0; i < classNames.length; i++ ) { - className = classNames[ i ]; - - // Remove *all* instances - while ( cur.indexOf( " " + className + " " ) > -1 ) { - cur = cur.replace( " " + className + " ", " " ); - } - } - - // Only assign if different to avoid unneeded rendering. - finalValue = stripAndCollapse( cur ); - if ( curValue !== finalValue ) { - this.setAttribute( "class", finalValue ); - } - } - } ); - } - - return this; - }, - - toggleClass: function( value, stateVal ) { - var classNames, className, i, self, - type = typeof value, - isValidValue = type === "string" || Array.isArray( value ); - - if ( isFunction( value ) ) { - return this.each( function( i ) { - jQuery( this ).toggleClass( - value.call( this, i, getClass( this ), stateVal ), - stateVal - ); - } ); - } - - if ( typeof stateVal === "boolean" && isValidValue ) { - return stateVal ? this.addClass( value ) : this.removeClass( value ); - } - - classNames = classesToArray( value ); - - return this.each( function() { - if ( isValidValue ) { - - // Toggle individual class names - self = jQuery( this ); - - for ( i = 0; i < classNames.length; i++ ) { - className = classNames[ i ]; - - // Check each className given, space separated list - if ( self.hasClass( className ) ) { - self.removeClass( className ); - } else { - self.addClass( className ); - } - } - - // Toggle whole class name - } else if ( value === undefined || type === "boolean" ) { - className = getClass( this ); - if ( className ) { - - // Store className if set - dataPriv.set( this, "__className__", className ); - } - - // If the element has a class name or if we're passed `false`, - // then remove the whole classname (if there was one, the above saved it). - // Otherwise bring back whatever was previously saved (if anything), - // falling back to the empty string if nothing was stored. - if ( this.setAttribute ) { - this.setAttribute( "class", - className || value === false ? - "" : - dataPriv.get( this, "__className__" ) || "" - ); - } - } - } ); - }, - - hasClass: function( selector ) { - var className, elem, - i = 0; - - className = " " + selector + " "; - while ( ( elem = this[ i++ ] ) ) { - if ( elem.nodeType === 1 && - ( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) { - return true; - } - } - - return false; - } -} ); - - - - -var rreturn = /\r/g; - -jQuery.fn.extend( { - val: function( value ) { - var hooks, ret, valueIsFunction, - elem = this[ 0 ]; - - if ( !arguments.length ) { - if ( elem ) { - hooks = jQuery.valHooks[ elem.type ] || - jQuery.valHooks[ elem.nodeName.toLowerCase() ]; - - if ( hooks && - "get" in hooks && - ( ret = hooks.get( elem, "value" ) ) !== undefined - ) { - return ret; - } - - ret = elem.value; - - // Handle most common string cases - if ( typeof ret === "string" ) { - return ret.replace( rreturn, "" ); - } - - // Handle cases where value is null/undef or number - return ret == null ? "" : ret; - } - - return; - } - - valueIsFunction = isFunction( value ); - - return this.each( function( i ) { - var val; - - if ( this.nodeType !== 1 ) { - return; - } - - if ( valueIsFunction ) { - val = value.call( this, i, jQuery( this ).val() ); - } else { - val = value; - } - - // Treat null/undefined as ""; convert numbers to string - if ( val == null ) { - val = ""; - - } else if ( typeof val === "number" ) { - val += ""; - - } else if ( Array.isArray( val ) ) { - val = jQuery.map( val, function( value ) { - return value == null ? "" : value + ""; - } ); - } - - hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; - - // If set returns undefined, fall back to normal setting - if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) { - this.value = val; - } - } ); - } -} ); - -jQuery.extend( { - valHooks: { - option: { - get: function( elem ) { - - var val = jQuery.find.attr( elem, "value" ); - return val != null ? - val : - - // Support: IE <=10 - 11 only - // option.text throws exceptions (trac-14686, trac-14858) - // Strip and collapse whitespace - // https://html.spec.whatwg.org/#strip-and-collapse-whitespace - stripAndCollapse( jQuery.text( elem ) ); - } - }, - select: { - get: function( elem ) { - var value, option, i, - options = elem.options, - index = elem.selectedIndex, - one = elem.type === "select-one", - values = one ? null : [], - max = one ? index + 1 : options.length; - - if ( index < 0 ) { - i = max; - - } else { - i = one ? index : 0; - } - - // Loop through all the selected options - for ( ; i < max; i++ ) { - option = options[ i ]; - - // Support: IE <=9 only - // IE8-9 doesn't update selected after form reset (trac-2551) - if ( ( option.selected || i === index ) && - - // Don't return options that are disabled or in a disabled optgroup - !option.disabled && - ( !option.parentNode.disabled || - !nodeName( option.parentNode, "optgroup" ) ) ) { - - // Get the specific value for the option - value = jQuery( option ).val(); - - // We don't need an array for one selects - if ( one ) { - return value; - } - - // Multi-Selects return an array - values.push( value ); - } - } - - return values; - }, - - set: function( elem, value ) { - var optionSet, option, - options = elem.options, - values = jQuery.makeArray( value ), - i = options.length; - - while ( i-- ) { - option = options[ i ]; - - /* eslint-disable no-cond-assign */ - - if ( option.selected = - jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1 - ) { - optionSet = true; - } - - /* eslint-enable no-cond-assign */ - } - - // Force browsers to behave consistently when non-matching value is set - if ( !optionSet ) { - elem.selectedIndex = -1; - } - return values; - } - } - } -} ); - -// Radios and checkboxes getter/setter -jQuery.each( [ "radio", "checkbox" ], function() { - jQuery.valHooks[ this ] = { - set: function( elem, value ) { - if ( Array.isArray( value ) ) { - return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 ); - } - } - }; - if ( !support.checkOn ) { - jQuery.valHooks[ this ].get = function( elem ) { - return elem.getAttribute( "value" ) === null ? "on" : elem.value; - }; - } -} ); - - - - -// Return jQuery for attributes-only inclusion -var location = window.location; - -var nonce = { guid: Date.now() }; - -var rquery = ( /\?/ ); - - - -// Cross-browser xml parsing -jQuery.parseXML = function( data ) { - var xml, parserErrorElem; - if ( !data || typeof data !== "string" ) { - return null; - } - - // Support: IE 9 - 11 only - // IE throws on parseFromString with invalid input. - try { - xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" ); - } catch ( e ) {} - - parserErrorElem = xml && xml.getElementsByTagName( "parsererror" )[ 0 ]; - if ( !xml || parserErrorElem ) { - jQuery.error( "Invalid XML: " + ( - parserErrorElem ? - jQuery.map( parserErrorElem.childNodes, function( el ) { - return el.textContent; - } ).join( "\n" ) : - data - ) ); - } - return xml; -}; - - -var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, - stopPropagationCallback = function( e ) { - e.stopPropagation(); - }; - -jQuery.extend( jQuery.event, { - - trigger: function( event, data, elem, onlyHandlers ) { - - var i, cur, tmp, bubbleType, ontype, handle, special, lastElement, - eventPath = [ elem || document ], - type = hasOwn.call( event, "type" ) ? event.type : event, - namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; - - cur = lastElement = tmp = elem = elem || document; - - // Don't do events on text and comment nodes - if ( elem.nodeType === 3 || elem.nodeType === 8 ) { - return; - } - - // focus/blur morphs to focusin/out; ensure we're not firing them right now - if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { - return; - } - - if ( type.indexOf( "." ) > -1 ) { - - // Namespaced trigger; create a regexp to match event type in handle() - namespaces = type.split( "." ); - type = namespaces.shift(); - namespaces.sort(); - } - ontype = type.indexOf( ":" ) < 0 && "on" + type; - - // Caller can pass in a jQuery.Event object, Object, or just an event type string - event = event[ jQuery.expando ] ? - event : - new jQuery.Event( type, typeof event === "object" && event ); - - // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) - event.isTrigger = onlyHandlers ? 2 : 3; - event.namespace = namespaces.join( "." ); - event.rnamespace = event.namespace ? - new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : - null; - - // Clean up the event in case it is being reused - event.result = undefined; - if ( !event.target ) { - event.target = elem; - } - - // Clone any incoming data and prepend the event, creating the handler arg list - data = data == null ? - [ event ] : - jQuery.makeArray( data, [ event ] ); - - // Allow special events to draw outside the lines - special = jQuery.event.special[ type ] || {}; - if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { - return; - } - - // Determine event propagation path in advance, per W3C events spec (trac-9951) - // Bubble up to document, then to window; watch for a global ownerDocument var (trac-9724) - if ( !onlyHandlers && !special.noBubble && !isWindow( elem ) ) { - - bubbleType = special.delegateType || type; - if ( !rfocusMorph.test( bubbleType + type ) ) { - cur = cur.parentNode; - } - for ( ; cur; cur = cur.parentNode ) { - eventPath.push( cur ); - tmp = cur; - } - - // Only add window if we got to document (e.g., not plain obj or detached DOM) - if ( tmp === ( elem.ownerDocument || document ) ) { - eventPath.push( tmp.defaultView || tmp.parentWindow || window ); - } - } - - // Fire handlers on the event path - i = 0; - while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { - lastElement = cur; - event.type = i > 1 ? - bubbleType : - special.bindType || type; - - // jQuery handler - handle = ( dataPriv.get( cur, "events" ) || Object.create( null ) )[ event.type ] && - dataPriv.get( cur, "handle" ); - if ( handle ) { - handle.apply( cur, data ); - } - - // Native handler - handle = ontype && cur[ ontype ]; - if ( handle && handle.apply && acceptData( cur ) ) { - event.result = handle.apply( cur, data ); - if ( event.result === false ) { - event.preventDefault(); - } - } - } - event.type = type; - - // If nobody prevented the default action, do it now - if ( !onlyHandlers && !event.isDefaultPrevented() ) { - - if ( ( !special._default || - special._default.apply( eventPath.pop(), data ) === false ) && - acceptData( elem ) ) { - - // Call a native DOM method on the target with the same name as the event. - // Don't do default actions on window, that's where global variables be (trac-6170) - if ( ontype && isFunction( elem[ type ] ) && !isWindow( elem ) ) { - - // Don't re-trigger an onFOO event when we call its FOO() method - tmp = elem[ ontype ]; - - if ( tmp ) { - elem[ ontype ] = null; - } - - // Prevent re-triggering of the same event, since we already bubbled it above - jQuery.event.triggered = type; - - if ( event.isPropagationStopped() ) { - lastElement.addEventListener( type, stopPropagationCallback ); - } - - elem[ type ](); - - if ( event.isPropagationStopped() ) { - lastElement.removeEventListener( type, stopPropagationCallback ); - } - - jQuery.event.triggered = undefined; - - if ( tmp ) { - elem[ ontype ] = tmp; - } - } - } - } - - return event.result; - }, - - // Piggyback on a donor event to simulate a different one - // Used only for `focus(in | out)` events - simulate: function( type, elem, event ) { - var e = jQuery.extend( - new jQuery.Event(), - event, - { - type: type, - isSimulated: true - } - ); - - jQuery.event.trigger( e, null, elem ); - } - -} ); - -jQuery.fn.extend( { - - trigger: function( type, data ) { - return this.each( function() { - jQuery.event.trigger( type, data, this ); - } ); - }, - triggerHandler: function( type, data ) { - var elem = this[ 0 ]; - if ( elem ) { - return jQuery.event.trigger( type, data, elem, true ); - } - } -} ); - - -var - rbracket = /\[\]$/, - rCRLF = /\r?\n/g, - rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, - rsubmittable = /^(?:input|select|textarea|keygen)/i; - -function buildParams( prefix, obj, traditional, add ) { - var name; - - if ( Array.isArray( obj ) ) { - - // Serialize array item. - jQuery.each( obj, function( i, v ) { - if ( traditional || rbracket.test( prefix ) ) { - - // Treat each array item as a scalar. - add( prefix, v ); - - } else { - - // Item is non-scalar (array or object), encode its numeric index. - buildParams( - prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]", - v, - traditional, - add - ); - } - } ); - - } else if ( !traditional && toType( obj ) === "object" ) { - - // Serialize object item. - for ( name in obj ) { - buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); - } - - } else { - - // Serialize scalar item. - add( prefix, obj ); - } -} - -// Serialize an array of form elements or a set of -// key/values into a query string -jQuery.param = function( a, traditional ) { - var prefix, - s = [], - add = function( key, valueOrFunction ) { - - // If value is a function, invoke it and use its return value - var value = isFunction( valueOrFunction ) ? - valueOrFunction() : - valueOrFunction; - - s[ s.length ] = encodeURIComponent( key ) + "=" + - encodeURIComponent( value == null ? "" : value ); - }; - - if ( a == null ) { - return ""; - } - - // If an array was passed in, assume that it is an array of form elements. - if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { - - // Serialize the form elements - jQuery.each( a, function() { - add( this.name, this.value ); - } ); - - } else { - - // If traditional, encode the "old" way (the way 1.3.2 or older - // did it), otherwise encode params recursively. - for ( prefix in a ) { - buildParams( prefix, a[ prefix ], traditional, add ); - } - } - - // Return the resulting serialization - return s.join( "&" ); -}; - -jQuery.fn.extend( { - serialize: function() { - return jQuery.param( this.serializeArray() ); - }, - serializeArray: function() { - return this.map( function() { - - // Can add propHook for "elements" to filter or add form elements - var elements = jQuery.prop( this, "elements" ); - return elements ? jQuery.makeArray( elements ) : this; - } ).filter( function() { - var type = this.type; - - // Use .is( ":disabled" ) so that fieldset[disabled] works - return this.name && !jQuery( this ).is( ":disabled" ) && - rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && - ( this.checked || !rcheckableType.test( type ) ); - } ).map( function( _i, elem ) { - var val = jQuery( this ).val(); - - if ( val == null ) { - return null; - } - - if ( Array.isArray( val ) ) { - return jQuery.map( val, function( val ) { - return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; - } ); - } - - return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; - } ).get(); - } -} ); - - -var - r20 = /%20/g, - rhash = /#.*$/, - rantiCache = /([?&])_=[^&]*/, - rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg, - - // trac-7653, trac-8125, trac-8152: local protocol detection - rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, - rnoContent = /^(?:GET|HEAD)$/, - rprotocol = /^\/\//, - - /* Prefilters - * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) - * 2) These are called: - * - BEFORE asking for a transport - * - AFTER param serialization (s.data is a string if s.processData is true) - * 3) key is the dataType - * 4) the catchall symbol "*" can be used - * 5) execution will start with transport dataType and THEN continue down to "*" if needed - */ - prefilters = {}, - - /* Transports bindings - * 1) key is the dataType - * 2) the catchall symbol "*" can be used - * 3) selection will start with transport dataType and THEN go to "*" if needed - */ - transports = {}, - - // Avoid comment-prolog char sequence (trac-10098); must appease lint and evade compression - allTypes = "*/".concat( "*" ), - - // Anchor tag for parsing the document origin - originAnchor = document.createElement( "a" ); - -originAnchor.href = location.href; - -// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport -function addToPrefiltersOrTransports( structure ) { - - // dataTypeExpression is optional and defaults to "*" - return function( dataTypeExpression, func ) { - - if ( typeof dataTypeExpression !== "string" ) { - func = dataTypeExpression; - dataTypeExpression = "*"; - } - - var dataType, - i = 0, - dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || []; - - if ( isFunction( func ) ) { - - // For each dataType in the dataTypeExpression - while ( ( dataType = dataTypes[ i++ ] ) ) { - - // Prepend if requested - if ( dataType[ 0 ] === "+" ) { - dataType = dataType.slice( 1 ) || "*"; - ( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func ); - - // Otherwise append - } else { - ( structure[ dataType ] = structure[ dataType ] || [] ).push( func ); - } - } - } - }; -} - -// Base inspection function for prefilters and transports -function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) { - - var inspected = {}, - seekingTransport = ( structure === transports ); - - function inspect( dataType ) { - var selected; - inspected[ dataType ] = true; - jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) { - var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR ); - if ( typeof dataTypeOrTransport === "string" && - !seekingTransport && !inspected[ dataTypeOrTransport ] ) { - - options.dataTypes.unshift( dataTypeOrTransport ); - inspect( dataTypeOrTransport ); - return false; - } else if ( seekingTransport ) { - return !( selected = dataTypeOrTransport ); - } - } ); - return selected; - } - - return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" ); -} - -// A special extend for ajax options -// that takes "flat" options (not to be deep extended) -// Fixes trac-9887 -function ajaxExtend( target, src ) { - var key, deep, - flatOptions = jQuery.ajaxSettings.flatOptions || {}; - - for ( key in src ) { - if ( src[ key ] !== undefined ) { - ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; - } - } - if ( deep ) { - jQuery.extend( true, target, deep ); - } - - return target; -} - -/* Handles responses to an ajax request: - * - finds the right dataType (mediates between content-type and expected dataType) - * - returns the corresponding response - */ -function ajaxHandleResponses( s, jqXHR, responses ) { - - var ct, type, finalDataType, firstDataType, - contents = s.contents, - dataTypes = s.dataTypes; - - // Remove auto dataType and get content-type in the process - while ( dataTypes[ 0 ] === "*" ) { - dataTypes.shift(); - if ( ct === undefined ) { - ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" ); - } - } - - // Check if we're dealing with a known content-type - if ( ct ) { - for ( type in contents ) { - if ( contents[ type ] && contents[ type ].test( ct ) ) { - dataTypes.unshift( type ); - break; - } - } - } - - // Check to see if we have a response for the expected dataType - if ( dataTypes[ 0 ] in responses ) { - finalDataType = dataTypes[ 0 ]; - } else { - - // Try convertible dataTypes - for ( type in responses ) { - if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) { - finalDataType = type; - break; - } - if ( !firstDataType ) { - firstDataType = type; - } - } - - // Or just use first one - finalDataType = finalDataType || firstDataType; - } - - // If we found a dataType - // We add the dataType to the list if needed - // and return the corresponding response - if ( finalDataType ) { - if ( finalDataType !== dataTypes[ 0 ] ) { - dataTypes.unshift( finalDataType ); - } - return responses[ finalDataType ]; - } -} - -/* Chain conversions given the request and the original response - * Also sets the responseXXX fields on the jqXHR instance - */ -function ajaxConvert( s, response, jqXHR, isSuccess ) { - var conv2, current, conv, tmp, prev, - converters = {}, - - // Work with a copy of dataTypes in case we need to modify it for conversion - dataTypes = s.dataTypes.slice(); - - // Create converters map with lowercased keys - if ( dataTypes[ 1 ] ) { - for ( conv in s.converters ) { - converters[ conv.toLowerCase() ] = s.converters[ conv ]; - } - } - - current = dataTypes.shift(); - - // Convert to each sequential dataType - while ( current ) { - - if ( s.responseFields[ current ] ) { - jqXHR[ s.responseFields[ current ] ] = response; - } - - // Apply the dataFilter if provided - if ( !prev && isSuccess && s.dataFilter ) { - response = s.dataFilter( response, s.dataType ); - } - - prev = current; - current = dataTypes.shift(); - - if ( current ) { - - // There's only work to do if current dataType is non-auto - if ( current === "*" ) { - - current = prev; - - // Convert response if prev dataType is non-auto and differs from current - } else if ( prev !== "*" && prev !== current ) { - - // Seek a direct converter - conv = converters[ prev + " " + current ] || converters[ "* " + current ]; - - // If none found, seek a pair - if ( !conv ) { - for ( conv2 in converters ) { - - // If conv2 outputs current - tmp = conv2.split( " " ); - if ( tmp[ 1 ] === current ) { - - // If prev can be converted to accepted input - conv = converters[ prev + " " + tmp[ 0 ] ] || - converters[ "* " + tmp[ 0 ] ]; - if ( conv ) { - - // Condense equivalence converters - if ( conv === true ) { - conv = converters[ conv2 ]; - - // Otherwise, insert the intermediate dataType - } else if ( converters[ conv2 ] !== true ) { - current = tmp[ 0 ]; - dataTypes.unshift( tmp[ 1 ] ); - } - break; - } - } - } - } - - // Apply converter (if not an equivalence) - if ( conv !== true ) { - - // Unless errors are allowed to bubble, catch and return them - if ( conv && s.throws ) { - response = conv( response ); - } else { - try { - response = conv( response ); - } catch ( e ) { - return { - state: "parsererror", - error: conv ? e : "No conversion from " + prev + " to " + current - }; - } - } - } - } - } - } - - return { state: "success", data: response }; -} - -jQuery.extend( { - - // Counter for holding the number of active queries - active: 0, - - // Last-Modified header cache for next request - lastModified: {}, - etag: {}, - - ajaxSettings: { - url: location.href, - type: "GET", - isLocal: rlocalProtocol.test( location.protocol ), - global: true, - processData: true, - async: true, - contentType: "application/x-www-form-urlencoded; charset=UTF-8", - - /* - timeout: 0, - data: null, - dataType: null, - username: null, - password: null, - cache: null, - throws: false, - traditional: false, - headers: {}, - */ - - accepts: { - "*": allTypes, - text: "text/plain", - html: "text/html", - xml: "application/xml, text/xml", - json: "application/json, text/javascript" - }, - - contents: { - xml: /\bxml\b/, - html: /\bhtml/, - json: /\bjson\b/ - }, - - responseFields: { - xml: "responseXML", - text: "responseText", - json: "responseJSON" - }, - - // Data converters - // Keys separate source (or catchall "*") and destination types with a single space - converters: { - - // Convert anything to text - "* text": String, - - // Text to html (true = no transformation) - "text html": true, - - // Evaluate text as a json expression - "text json": JSON.parse, - - // Parse text as xml - "text xml": jQuery.parseXML - }, - - // For options that shouldn't be deep extended: - // you can add your own custom options here if - // and when you create one that shouldn't be - // deep extended (see ajaxExtend) - flatOptions: { - url: true, - context: true - } - }, - - // Creates a full fledged settings object into target - // with both ajaxSettings and settings fields. - // If target is omitted, writes into ajaxSettings. - ajaxSetup: function( target, settings ) { - return settings ? - - // Building a settings object - ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) : - - // Extending ajaxSettings - ajaxExtend( jQuery.ajaxSettings, target ); - }, - - ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), - ajaxTransport: addToPrefiltersOrTransports( transports ), - - // Main method - ajax: function( url, options ) { - - // If url is an object, simulate pre-1.5 signature - if ( typeof url === "object" ) { - options = url; - url = undefined; - } - - // Force options to be an object - options = options || {}; - - var transport, - - // URL without anti-cache param - cacheURL, - - // Response headers - responseHeadersString, - responseHeaders, - - // timeout handle - timeoutTimer, - - // Url cleanup var - urlAnchor, - - // Request state (becomes false upon send and true upon completion) - completed, - - // To know if global events are to be dispatched - fireGlobals, - - // Loop variable - i, - - // uncached part of the url - uncached, - - // Create the final options object - s = jQuery.ajaxSetup( {}, options ), - - // Callbacks context - callbackContext = s.context || s, - - // Context for global events is callbackContext if it is a DOM node or jQuery collection - globalEventContext = s.context && - ( callbackContext.nodeType || callbackContext.jquery ) ? - jQuery( callbackContext ) : - jQuery.event, - - // Deferreds - deferred = jQuery.Deferred(), - completeDeferred = jQuery.Callbacks( "once memory" ), - - // Status-dependent callbacks - statusCode = s.statusCode || {}, - - // Headers (they are sent all at once) - requestHeaders = {}, - requestHeadersNames = {}, - - // Default abort message - strAbort = "canceled", - - // Fake xhr - jqXHR = { - readyState: 0, - - // Builds headers hashtable if needed - getResponseHeader: function( key ) { - var match; - if ( completed ) { - if ( !responseHeaders ) { - responseHeaders = {}; - while ( ( match = rheaders.exec( responseHeadersString ) ) ) { - responseHeaders[ match[ 1 ].toLowerCase() + " " ] = - ( responseHeaders[ match[ 1 ].toLowerCase() + " " ] || [] ) - .concat( match[ 2 ] ); - } - } - match = responseHeaders[ key.toLowerCase() + " " ]; - } - return match == null ? null : match.join( ", " ); - }, - - // Raw string - getAllResponseHeaders: function() { - return completed ? responseHeadersString : null; - }, - - // Caches the header - setRequestHeader: function( name, value ) { - if ( completed == null ) { - name = requestHeadersNames[ name.toLowerCase() ] = - requestHeadersNames[ name.toLowerCase() ] || name; - requestHeaders[ name ] = value; - } - return this; - }, - - // Overrides response content-type header - overrideMimeType: function( type ) { - if ( completed == null ) { - s.mimeType = type; - } - return this; - }, - - // Status-dependent callbacks - statusCode: function( map ) { - var code; - if ( map ) { - if ( completed ) { - - // Execute the appropriate callbacks - jqXHR.always( map[ jqXHR.status ] ); - } else { - - // Lazy-add the new callbacks in a way that preserves old ones - for ( code in map ) { - statusCode[ code ] = [ statusCode[ code ], map[ code ] ]; - } - } - } - return this; - }, - - // Cancel the request - abort: function( statusText ) { - var finalText = statusText || strAbort; - if ( transport ) { - transport.abort( finalText ); - } - done( 0, finalText ); - return this; - } - }; - - // Attach deferreds - deferred.promise( jqXHR ); - - // Add protocol if not provided (prefilters might expect it) - // Handle falsy url in the settings object (trac-10093: consistency with old signature) - // We also use the url parameter if available - s.url = ( ( url || s.url || location.href ) + "" ) - .replace( rprotocol, location.protocol + "//" ); - - // Alias method option to type as per ticket trac-12004 - s.type = options.method || options.type || s.method || s.type; - - // Extract dataTypes list - s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ]; - - // A cross-domain request is in order when the origin doesn't match the current origin. - if ( s.crossDomain == null ) { - urlAnchor = document.createElement( "a" ); - - // Support: IE <=8 - 11, Edge 12 - 15 - // IE throws exception on accessing the href property if url is malformed, - // e.g. http://example.com:80x/ - try { - urlAnchor.href = s.url; - - // Support: IE <=8 - 11 only - // Anchor's host property isn't correctly set when s.url is relative - urlAnchor.href = urlAnchor.href; - s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !== - urlAnchor.protocol + "//" + urlAnchor.host; - } catch ( e ) { - - // If there is an error parsing the URL, assume it is crossDomain, - // it can be rejected by the transport if it is invalid - s.crossDomain = true; - } - } - - // Convert data if not already a string - if ( s.data && s.processData && typeof s.data !== "string" ) { - s.data = jQuery.param( s.data, s.traditional ); - } - - // Apply prefilters - inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); - - // If request was aborted inside a prefilter, stop there - if ( completed ) { - return jqXHR; - } - - // We can fire global events as of now if asked to - // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (trac-15118) - fireGlobals = jQuery.event && s.global; - - // Watch for a new set of requests - if ( fireGlobals && jQuery.active++ === 0 ) { - jQuery.event.trigger( "ajaxStart" ); - } - - // Uppercase the type - s.type = s.type.toUpperCase(); - - // Determine if request has content - s.hasContent = !rnoContent.test( s.type ); - - // Save the URL in case we're toying with the If-Modified-Since - // and/or If-None-Match header later on - // Remove hash to simplify url manipulation - cacheURL = s.url.replace( rhash, "" ); - - // More options handling for requests with no content - if ( !s.hasContent ) { - - // Remember the hash so we can put it back - uncached = s.url.slice( cacheURL.length ); - - // If data is available and should be processed, append data to url - if ( s.data && ( s.processData || typeof s.data === "string" ) ) { - cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data; - - // trac-9682: remove data so that it's not used in an eventual retry - delete s.data; - } - - // Add or update anti-cache param if needed - if ( s.cache === false ) { - cacheURL = cacheURL.replace( rantiCache, "$1" ); - uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce.guid++ ) + - uncached; - } - - // Put hash and anti-cache on the URL that will be requested (gh-1732) - s.url = cacheURL + uncached; - - // Change '%20' to '+' if this is encoded form body content (gh-2658) - } else if ( s.data && s.processData && - ( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) { - s.data = s.data.replace( r20, "+" ); - } - - // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. - if ( s.ifModified ) { - if ( jQuery.lastModified[ cacheURL ] ) { - jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] ); - } - if ( jQuery.etag[ cacheURL ] ) { - jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] ); - } - } - - // Set the correct header, if data is being sent - if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { - jqXHR.setRequestHeader( "Content-Type", s.contentType ); - } - - // Set the Accepts header for the server, depending on the dataType - jqXHR.setRequestHeader( - "Accept", - s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ? - s.accepts[ s.dataTypes[ 0 ] ] + - ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : - s.accepts[ "*" ] - ); - - // Check for headers option - for ( i in s.headers ) { - jqXHR.setRequestHeader( i, s.headers[ i ] ); - } - - // Allow custom headers/mimetypes and early abort - if ( s.beforeSend && - ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) { - - // Abort if not done already and return - return jqXHR.abort(); - } - - // Aborting is no longer a cancellation - strAbort = "abort"; - - // Install callbacks on deferreds - completeDeferred.add( s.complete ); - jqXHR.done( s.success ); - jqXHR.fail( s.error ); - - // Get transport - transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); - - // If no transport, we auto-abort - if ( !transport ) { - done( -1, "No Transport" ); - } else { - jqXHR.readyState = 1; - - // Send global event - if ( fireGlobals ) { - globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); - } - - // If request was aborted inside ajaxSend, stop there - if ( completed ) { - return jqXHR; - } - - // Timeout - if ( s.async && s.timeout > 0 ) { - timeoutTimer = window.setTimeout( function() { - jqXHR.abort( "timeout" ); - }, s.timeout ); - } - - try { - completed = false; - transport.send( requestHeaders, done ); - } catch ( e ) { - - // Rethrow post-completion exceptions - if ( completed ) { - throw e; - } - - // Propagate others as results - done( -1, e ); - } - } - - // Callback for when everything is done - function done( status, nativeStatusText, responses, headers ) { - var isSuccess, success, error, response, modified, - statusText = nativeStatusText; - - // Ignore repeat invocations - if ( completed ) { - return; - } - - completed = true; - - // Clear timeout if it exists - if ( timeoutTimer ) { - window.clearTimeout( timeoutTimer ); - } - - // Dereference transport for early garbage collection - // (no matter how long the jqXHR object will be used) - transport = undefined; - - // Cache response headers - responseHeadersString = headers || ""; - - // Set readyState - jqXHR.readyState = status > 0 ? 4 : 0; - - // Determine if successful - isSuccess = status >= 200 && status < 300 || status === 304; - - // Get response data - if ( responses ) { - response = ajaxHandleResponses( s, jqXHR, responses ); - } - - // Use a noop converter for missing script but not if jsonp - if ( !isSuccess && - jQuery.inArray( "script", s.dataTypes ) > -1 && - jQuery.inArray( "json", s.dataTypes ) < 0 ) { - s.converters[ "text script" ] = function() {}; - } - - // Convert no matter what (that way responseXXX fields are always set) - response = ajaxConvert( s, response, jqXHR, isSuccess ); - - // If successful, handle type chaining - if ( isSuccess ) { - - // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. - if ( s.ifModified ) { - modified = jqXHR.getResponseHeader( "Last-Modified" ); - if ( modified ) { - jQuery.lastModified[ cacheURL ] = modified; - } - modified = jqXHR.getResponseHeader( "etag" ); - if ( modified ) { - jQuery.etag[ cacheURL ] = modified; - } - } - - // if no content - if ( status === 204 || s.type === "HEAD" ) { - statusText = "nocontent"; - - // if not modified - } else if ( status === 304 ) { - statusText = "notmodified"; - - // If we have data, let's convert it - } else { - statusText = response.state; - success = response.data; - error = response.error; - isSuccess = !error; - } - } else { - - // Extract error from statusText and normalize for non-aborts - error = statusText; - if ( status || !statusText ) { - statusText = "error"; - if ( status < 0 ) { - status = 0; - } - } - } - - // Set data for the fake xhr object - jqXHR.status = status; - jqXHR.statusText = ( nativeStatusText || statusText ) + ""; - - // Success/Error - if ( isSuccess ) { - deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); - } else { - deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); - } - - // Status-dependent callbacks - jqXHR.statusCode( statusCode ); - statusCode = undefined; - - if ( fireGlobals ) { - globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError", - [ jqXHR, s, isSuccess ? success : error ] ); - } - - // Complete - completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); - - if ( fireGlobals ) { - globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); - - // Handle the global AJAX counter - if ( !( --jQuery.active ) ) { - jQuery.event.trigger( "ajaxStop" ); - } - } - } - - return jqXHR; - }, - - getJSON: function( url, data, callback ) { - return jQuery.get( url, data, callback, "json" ); - }, - - getScript: function( url, callback ) { - return jQuery.get( url, undefined, callback, "script" ); - } -} ); - -jQuery.each( [ "get", "post" ], function( _i, method ) { - jQuery[ method ] = function( url, data, callback, type ) { - - // Shift arguments if data argument was omitted - if ( isFunction( data ) ) { - type = type || callback; - callback = data; - data = undefined; - } - - // The url can be an options object (which then must have .url) - return jQuery.ajax( jQuery.extend( { - url: url, - type: method, - dataType: type, - data: data, - success: callback - }, jQuery.isPlainObject( url ) && url ) ); - }; -} ); - -jQuery.ajaxPrefilter( function( s ) { - var i; - for ( i in s.headers ) { - if ( i.toLowerCase() === "content-type" ) { - s.contentType = s.headers[ i ] || ""; - } - } -} ); - - -jQuery._evalUrl = function( url, options, doc ) { - return jQuery.ajax( { - url: url, - - // Make this explicit, since user can override this through ajaxSetup (trac-11264) - type: "GET", - dataType: "script", - cache: true, - async: false, - global: false, - - // Only evaluate the response if it is successful (gh-4126) - // dataFilter is not invoked for failure responses, so using it instead - // of the default converter is kludgy but it works. - converters: { - "text script": function() {} - }, - dataFilter: function( response ) { - jQuery.globalEval( response, options, doc ); - } - } ); -}; - - -jQuery.fn.extend( { - wrapAll: function( html ) { - var wrap; - - if ( this[ 0 ] ) { - if ( isFunction( html ) ) { - html = html.call( this[ 0 ] ); - } - - // The elements to wrap the target around - wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true ); - - if ( this[ 0 ].parentNode ) { - wrap.insertBefore( this[ 0 ] ); - } - - wrap.map( function() { - var elem = this; - - while ( elem.firstElementChild ) { - elem = elem.firstElementChild; - } - - return elem; - } ).append( this ); - } - - return this; - }, - - wrapInner: function( html ) { - if ( isFunction( html ) ) { - return this.each( function( i ) { - jQuery( this ).wrapInner( html.call( this, i ) ); - } ); - } - - return this.each( function() { - var self = jQuery( this ), - contents = self.contents(); - - if ( contents.length ) { - contents.wrapAll( html ); - - } else { - self.append( html ); - } - } ); - }, - - wrap: function( html ) { - var htmlIsFunction = isFunction( html ); - - return this.each( function( i ) { - jQuery( this ).wrapAll( htmlIsFunction ? html.call( this, i ) : html ); - } ); - }, - - unwrap: function( selector ) { - this.parent( selector ).not( "body" ).each( function() { - jQuery( this ).replaceWith( this.childNodes ); - } ); - return this; - } -} ); - - -jQuery.expr.pseudos.hidden = function( elem ) { - return !jQuery.expr.pseudos.visible( elem ); -}; -jQuery.expr.pseudos.visible = function( elem ) { - return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ); -}; - - - - -jQuery.ajaxSettings.xhr = function() { - try { - return new window.XMLHttpRequest(); - } catch ( e ) {} -}; - -var xhrSuccessStatus = { - - // File protocol always yields status code 0, assume 200 - 0: 200, - - // Support: IE <=9 only - // trac-1450: sometimes IE returns 1223 when it should be 204 - 1223: 204 - }, - xhrSupported = jQuery.ajaxSettings.xhr(); - -support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported ); -support.ajax = xhrSupported = !!xhrSupported; - -jQuery.ajaxTransport( function( options ) { - var callback, errorCallback; - - // Cross domain only allowed if supported through XMLHttpRequest - if ( support.cors || xhrSupported && !options.crossDomain ) { - return { - send: function( headers, complete ) { - var i, - xhr = options.xhr(); - - xhr.open( - options.type, - options.url, - options.async, - options.username, - options.password - ); - - // Apply custom fields if provided - if ( options.xhrFields ) { - for ( i in options.xhrFields ) { - xhr[ i ] = options.xhrFields[ i ]; - } - } - - // Override mime type if needed - if ( options.mimeType && xhr.overrideMimeType ) { - xhr.overrideMimeType( options.mimeType ); - } - - // X-Requested-With header - // For cross-domain requests, seeing as conditions for a preflight are - // akin to a jigsaw puzzle, we simply never set it to be sure. - // (it can always be set on a per-request basis or even using ajaxSetup) - // For same-domain requests, won't change header if already provided. - if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) { - headers[ "X-Requested-With" ] = "XMLHttpRequest"; - } - - // Set headers - for ( i in headers ) { - xhr.setRequestHeader( i, headers[ i ] ); - } - - // Callback - callback = function( type ) { - return function() { - if ( callback ) { - callback = errorCallback = xhr.onload = - xhr.onerror = xhr.onabort = xhr.ontimeout = - xhr.onreadystatechange = null; - - if ( type === "abort" ) { - xhr.abort(); - } else if ( type === "error" ) { - - // Support: IE <=9 only - // On a manual native abort, IE9 throws - // errors on any property access that is not readyState - if ( typeof xhr.status !== "number" ) { - complete( 0, "error" ); - } else { - complete( - - // File: protocol always yields status 0; see trac-8605, trac-14207 - xhr.status, - xhr.statusText - ); - } - } else { - complete( - xhrSuccessStatus[ xhr.status ] || xhr.status, - xhr.statusText, - - // Support: IE <=9 only - // IE9 has no XHR2 but throws on binary (trac-11426) - // For XHR2 non-text, let the caller handle it (gh-2498) - ( xhr.responseType || "text" ) !== "text" || - typeof xhr.responseText !== "string" ? - { binary: xhr.response } : - { text: xhr.responseText }, - xhr.getAllResponseHeaders() - ); - } - } - }; - }; - - // Listen to events - xhr.onload = callback(); - errorCallback = xhr.onerror = xhr.ontimeout = callback( "error" ); - - // Support: IE 9 only - // Use onreadystatechange to replace onabort - // to handle uncaught aborts - if ( xhr.onabort !== undefined ) { - xhr.onabort = errorCallback; - } else { - xhr.onreadystatechange = function() { - - // Check readyState before timeout as it changes - if ( xhr.readyState === 4 ) { - - // Allow onerror to be called first, - // but that will not handle a native abort - // Also, save errorCallback to a variable - // as xhr.onerror cannot be accessed - window.setTimeout( function() { - if ( callback ) { - errorCallback(); - } - } ); - } - }; - } - - // Create the abort callback - callback = callback( "abort" ); - - try { - - // Do send the request (this may raise an exception) - xhr.send( options.hasContent && options.data || null ); - } catch ( e ) { - - // trac-14683: Only rethrow if this hasn't been notified as an error yet - if ( callback ) { - throw e; - } - } - }, - - abort: function() { - if ( callback ) { - callback(); - } - } - }; - } -} ); - - - - -// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432) -jQuery.ajaxPrefilter( function( s ) { - if ( s.crossDomain ) { - s.contents.script = false; - } -} ); - -// Install script dataType -jQuery.ajaxSetup( { - accepts: { - script: "text/javascript, application/javascript, " + - "application/ecmascript, application/x-ecmascript" - }, - contents: { - script: /\b(?:java|ecma)script\b/ - }, - converters: { - "text script": function( text ) { - jQuery.globalEval( text ); - return text; - } - } -} ); - -// Handle cache's special case and crossDomain -jQuery.ajaxPrefilter( "script", function( s ) { - if ( s.cache === undefined ) { - s.cache = false; - } - if ( s.crossDomain ) { - s.type = "GET"; - } -} ); - -// Bind script tag hack transport -jQuery.ajaxTransport( "script", function( s ) { - - // This transport only deals with cross domain or forced-by-attrs requests - if ( s.crossDomain || s.scriptAttrs ) { - var script, callback; - return { - send: function( _, complete ) { - script = jQuery( " - """, - """ - """, """ const pathtoroot = "./"; loadScripts(); @@ -437,6 +429,10 @@ public class TestSearch extends JavadocTester { holder="Search documentation (type /)" aria-label="Search in documentation" auto\ complete="off" spellcheck="false">"""); + checkOutput(fileName, false, + "jquery-ui.min.css", + "jquery-3.7.1.min.js", + "jquery-ui.min.js"); } void checkSingleIndex() { @@ -669,14 +665,15 @@ public class TestSearch extends JavadocTester { "AnotherClass.java:68: warning: invalid usage of tag {@index"); } - void checkJqueryAndImageFiles(boolean expectedOutput) { + void checkImageFiles(boolean expectedOutput) { checkFiles(expectedOutput, "script-files/search.js", - "script-files/jquery-3.7.1.min.js", - "script-files/jquery-ui.min.js", - "resource-files/jquery-ui.min.css", "resource-files/x.svg", "resource-files/glass.svg"); + checkFiles(false, + "script-files/jquery-3.7.1.min.js", + "script-files/jquery-ui.min.js", + "resource-files/jquery-ui.min.css"); } void checkSearchJS() { @@ -689,9 +686,7 @@ public class TestSearch extends JavadocTester { "function getURLPrefix(item, category) {", "url += item.l;"); - checkOutput("script-files/search-page.js", true, - "function renderResults(result) {", - "function selectTab(category) {"); + checkFiles(false, "script-files/search-page.js"); checkCssClasses("script-files/search.js", "resource-files/stylesheet.css"); } @@ -701,8 +696,8 @@ public class TestSearch extends JavadocTester { // are also defined as class selectors somewhere in the stylesheet file. String js = readOutputFile(jsFile); Set cssClasses = new TreeSet<>(); - addMatches(js, Pattern.compile("class=\\\\*\"([^\\\\\"]+)\\\\*\""), cssClasses); - addMatches(js, Pattern.compile("attr\\(\"class\", \"([^\"]+)\"\\)"), cssClasses); + addMatches(js, Pattern.compile("class=[\"']([-\\w]+)[\"']"), cssClasses); + addMatches(js, Pattern.compile("classList.add\\([\"']([-\\w]+)[\"']\\)"), cssClasses); // verify that the regex did find use of CSS class names checking("Checking CSS classes found"); if (cssClasses.isEmpty()) { diff --git a/test/langtools/jdk/javadoc/doclet/testStylesheet/TestStylesheet.java b/test/langtools/jdk/javadoc/doclet/testStylesheet/TestStylesheet.java index 012e9ce00de..a2c2a603212 100644 --- a/test/langtools/jdk/javadoc/doclet/testStylesheet/TestStylesheet.java +++ b/test/langtools/jdk/javadoc/doclet/testStylesheet/TestStylesheet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -132,6 +132,7 @@ public class TestStylesheet extends JavadocTester { min-height:12px; font-size:0; visibility:hidden; + cursor: pointer; }""", """ ::placeholder { diff --git a/test/langtools/jdk/javadoc/tool/api/basic/APITest.java b/test/langtools/jdk/javadoc/tool/api/basic/APITest.java index 71908f34e99..bd8d0cf7953 100644 --- a/test/langtools/jdk/javadoc/tool/api/basic/APITest.java +++ b/test/langtools/jdk/javadoc/tool/api/basic/APITest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ class APITest { "resource-files/copy.svg", "resource-files/down.svg", "resource-files/glass.svg", - "resource-files/jquery-ui.min.css", "resource-files/left.svg", "resource-files/link.svg", "resource-files/moon.svg", @@ -241,11 +240,8 @@ class APITest { "resource-files/fonts/DejaVuLGCSerif-Italic.woff2", "resource-files/fonts/DejaVuLGCSerif.woff", "resource-files/fonts/DejaVuLGCSerif.woff2", - "script-files/jquery-3.7.1.min.js", - "script-files/jquery-ui.min.js", "script-files/script.js", "script-files/search.js", - "script-files/search-page.js", "tag-search-index.js", "type-search-index.js" )); @@ -255,11 +251,8 @@ class APITest { !s.endsWith("-search-index.js") && !s.equals("index-all.html") && !s.equals("resource-files/glass.svg") - && !s.equals("resource-files/jquery-ui.min.css") && !s.equals("resource-files/x.svg") - && !s.startsWith("script-files/jquery-") && !s.equals("script-files/search.js") - && !s.equals("script-files/search-page.js") && !s.equals("search.html") && !s.equals("allclasses-index.html") && !s.equals("allpackages-index.html") From 0acc1d1e4fac4de6b48ed05ba0d83c1170bc4389 Mon Sep 17 00:00:00 2001 From: Quan Anh Mai Date: Mon, 13 Apr 2026 06:55:13 +0000 Subject: [PATCH 252/359] 8377163: C2: Iteration split must take into consideration sunk stores Reviewed-by: chagedorn, dfenacci --- src/hotspot/share/opto/loopTransform.cpp | 36 +++++- .../TestIterationSplitWithSunkStores.java | 112 ++++++++++++++++++ 2 files changed, 144 insertions(+), 4 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/loopopts/TestIterationSplitWithSunkStores.java diff --git a/src/hotspot/share/opto/loopTransform.cpp b/src/hotspot/share/opto/loopTransform.cpp index 80b17efb998..60a61b6bb4e 100644 --- a/src/hotspot/share/opto/loopTransform.cpp +++ b/src/hotspot/share/opto/loopTransform.cpp @@ -35,7 +35,9 @@ #include "opto/loopnode.hpp" #include "opto/movenode.hpp" #include "opto/mulnode.hpp" +#include "opto/node.hpp" #include "opto/opaquenode.hpp" +#include "opto/opcodes.hpp" #include "opto/phase.hpp" #include "opto/predicates.hpp" #include "opto/rootnode.hpp" @@ -1774,13 +1776,39 @@ Node *PhaseIdealLoop::insert_post_loop(IdealLoopTree* loop, Node_List& old_new, for (DUIterator i = main_head->outs(); main_head->has_out(i); i++) { Node* main_phi = main_head->out(i); if (main_phi->is_Phi() && main_phi->in(0) == main_head && main_phi->outcnt() > 0) { - Node* cur_phi = old_new[main_phi->_idx]; + Node* post_phi = old_new[main_phi->_idx]; + Node* loopback_input = main_phi->in(LoopNode::LoopBackControl); Node* fallnew = clone_up_backedge_goo(main_head->back_control(), post_head->init_control(), - main_phi->in(LoopNode::LoopBackControl), + loopback_input, visited, clones); - _igvn.hash_delete(cur_phi); - cur_phi->set_req(LoopNode::EntryControl, fallnew); + // Technically, the entry value of post_phi must be the loop back input of the corresponding + // Phi of the outer loop, not the Phi of the inner loop (i.e. main_phi). However, we have not + // constructed the Phis for the OuterStripMinedLoop yet, so the input must be inferred from + // the loop back input of main_phi. + // - If post_phi is a data Phi, then we can use the loop back input of main_phi. + // - If post_phi is a memory Phi, since Stores can be sunk below the inner loop, but still + // inside the outer loop, we have 2 cases: + // + If the loop back input of main_phi is on the backedge, then the entry input of + // post_phi is the clone of the node on the entry of post_head, similar to when post_phi + // is a data Phi. + // + If the loop back input of main_phi is not on the backedge, we need to find whether + // there is a sunk Store corresponding to post_phi, if there is any, the latest such + // store will be the entry input of post_phi. Fortunately, the safepoint at the exit of + // the outer loop captures all memory states, so we can use it as the entry input of + // post_phi. + // Another way to see it is that, the memory phi should capture the latest state at the + // post-loop entry. If loopback_input is cloned by clone_up_backedge_goo, it is pinned at + // the post-loop entry, and is surely the latest state. Otherwise, the latest memory state + // corresponding to post_phi is the memory state at the exit of the outer main-loop, which + // is captured by the safepoint there. + if (main_head->is_strip_mined() && fallnew == loopback_input && post_phi->is_memory_phi()) { + SafePointNode* main_safepoint = main_head->outer_safepoint(); + assert(main_safepoint != nullptr, "outer loop must have a safepoint"); + fallnew = main_safepoint->memory(); + } + _igvn.hash_delete(post_phi); + post_phi->set_req(LoopNode::EntryControl, fallnew); } } // Store nodes that were moved to the outer loop by PhaseIdealLoop::try_move_store_after_loop diff --git a/test/hotspot/jtreg/compiler/loopopts/TestIterationSplitWithSunkStores.java b/test/hotspot/jtreg/compiler/loopopts/TestIterationSplitWithSunkStores.java new file mode 100644 index 00000000000..7138f22beec --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/TestIterationSplitWithSunkStores.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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; + +import java.util.Objects; +import jdk.internal.misc.Unsafe; + +/* + * @test + * @bug 8377163 + * @summary Iteration splitting a counted loop with sunk stores should connect the memory phi of + * the post loop to the sunk store in the main loop, not the store at the loop back input + * of the corresponding phi of the main loop. + * @modules java.base/jdk.internal.misc + * @run main ${test.main.class} + * @run main/othervm -Xbatch -XX:-TieredCompilation ${test.main.class} + */ +public class TestIterationSplitWithSunkStores { + private static final Unsafe U = Unsafe.getUnsafe(); + + public static void main(String[] args) { + test1(); + + int[] array = new int[1000]; + MyInteger v = new MyInteger(0); + for (int i = 0; i < 100; i++) { + test2(array, v, v, v, v); + } + } + + private static void test1() { + int[] dst = new int[5]; + for (long i = 0L; i < 20_000; i++) { + test1(dst, 1); + for (int j = 1; j < 5; j++) { + if (dst[j] != j) { + throw new RuntimeException("Bad copy"); + } + } + } + } + + private static void test1(int[] dst, int dstPos) { + int[] src = new int[4]; + src[0] = new MyInteger(1).v(); + src[1] = 2; + src[2] = 3; + src[3] = 4; + System.arraycopy(src, 0, dst, dstPos, 4); + } + + private static void test2(int[] array, MyInteger v1, MyInteger v2, MyInteger v3, MyInteger v4) { + Objects.requireNonNull(array); + Objects.requireNonNull(v1); + Objects.requireNonNull(v2); + Objects.requireNonNull(v3); + Objects.requireNonNull(v4); + + // Using Unsafe to access the array so that the stores can be sunk without loop + // predication. This is because store sinking is only attempted during the first and the + // last loop opt passes, and we need it to occur before iteration splitting. + for (int i = 0; i < array.length; i++) { + long elemOffset = Unsafe.ARRAY_INT_BASE_OFFSET + (long) i * Unsafe.ARRAY_INT_INDEX_SCALE; + int e = U.getInt(array, elemOffset); + U.putInt(array, elemOffset, e + 1); + + // These 4 stores can all be sunk, but depending on the order in which they are + // visited, it is most likely that only some of them are actually sunk + v1.v = e + 1; + v2.v = e + 2; + v3.v = e + 3; + v4.v = e + 4; + } + } + + static class MyInteger { + public int v; + + public MyInteger(int v) { + for (int i = 0; i < 32; i++) { + if (i < 10) { + this.v = v; + } + } + this.v = v; + } + + public int v() { + return v; + } + } +} From 78a6aa9c7a907fe3375cd20e45bb293b5d15732e Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Mon, 13 Apr 2026 07:13:23 +0000 Subject: [PATCH 253/359] 8381937: Make exceptions in Java_sun_security_mscapi_CKeyPairGenerator generateCKeyPair more specific Reviewed-by: mdoerr, lucy --- .../windows/native/libsunmscapi/security.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/jdk.crypto.mscapi/windows/native/libsunmscapi/security.cpp b/src/jdk.crypto.mscapi/windows/native/libsunmscapi/security.cpp index ff011dca889..5c84b929ef1 100644 --- a/src/jdk.crypto.mscapi/windows/native/libsunmscapi/security.cpp +++ b/src/jdk.crypto.mscapi/windows/native/libsunmscapi/security.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1375,7 +1375,7 @@ JNIEXPORT jobject JNICALL Java_sun_security_mscapi_CKeyPairGenerator_00024RSA_ge PROV_RSA_FULL, CRYPT_NEWKEYSET) == FALSE) { - ThrowException(env, KEY_EXCEPTION, GetLastError()); + ThrowExceptionWithMessageAndErrcode(env, KEY_EXCEPTION, "CryptAcquireContext failure", GetLastError()); __leave; } } @@ -1387,7 +1387,7 @@ JNIEXPORT jobject JNICALL Java_sun_security_mscapi_CKeyPairGenerator_00024RSA_ge dwFlags, &hKeyPair) == FALSE) { - ThrowException(env, KEY_EXCEPTION, GetLastError()); + ThrowExceptionWithMessageAndErrcode(env, KEY_EXCEPTION, "CryptGenKey failure", GetLastError()); __leave; } From 909d4e758c045a0d8cea52f6a1333839f7d6c43e Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Mon, 13 Apr 2026 07:20:16 +0000 Subject: [PATCH 254/359] 8378838: Fix issues with "dead" code elimination and serviceability agent in libjvm.so on Linux Reviewed-by: lucy, erikj --- make/autoconf/flags-cflags.m4 | 5 +---- make/autoconf/flags-ldflags.m4 | 13 ++++++------- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/make/autoconf/flags-cflags.m4 b/make/autoconf/flags-cflags.m4 index ab9cd8be19b..423654cd50a 100644 --- a/make/autoconf/flags-cflags.m4 +++ b/make/autoconf/flags-cflags.m4 @@ -544,12 +544,9 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_HELPER], TOOLCHAIN_CFLAGS_JVM="$TOOLCHAIN_CFLAGS_JVM -fstack-protector" TOOLCHAIN_CFLAGS_JDK="-fvisibility=hidden -pipe -fstack-protector" # reduce lib size on linux in link step, this needs also special compile flags - # do this on s390x also for libjvm (where serviceability agent is not supported) if test "x$ENABLE_LINKTIME_GC" = xtrue; then TOOLCHAIN_CFLAGS_JDK="$TOOLCHAIN_CFLAGS_JDK -ffunction-sections -fdata-sections" - if test "x$OPENJDK_TARGET_CPU" = xs390x && test "x$DEBUG_LEVEL" == xrelease; then - TOOLCHAIN_CFLAGS_JVM="$TOOLCHAIN_CFLAGS_JVM -ffunction-sections -fdata-sections" - fi + TOOLCHAIN_CFLAGS_JVM="$TOOLCHAIN_CFLAGS_JVM -ffunction-sections -fdata-sections" fi # technically NOT for CXX (but since this gives *worse* performance, use # no-strict-aliasing everywhere!) diff --git a/make/autoconf/flags-ldflags.m4 b/make/autoconf/flags-ldflags.m4 index 7782735be25..ff10828731e 100644 --- a/make/autoconf/flags-ldflags.m4 +++ b/make/autoconf/flags-ldflags.m4 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2026, Oracle and/or its affiliates. All rights reserved. # 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,16 +53,15 @@ AC_DEFUN([FLAGS_SETUP_LDFLAGS_HELPER], # add --icf=all (Identical Code Folding — merges identical functions) BASIC_LDFLAGS="-Wl,-z,defs -Wl,-z,relro -Wl,-z,now -Wl,--no-as-needed -Wl,--exclude-libs,ALL" + BASIC_LDFLAGS_JVM_ONLY="" # Linux : remove unused code+data in link step if test "x$ENABLE_LINKTIME_GC" = xtrue; then - if test "x$OPENJDK_TARGET_CPU" = xs390x; then - BASIC_LDFLAGS="$BASIC_LDFLAGS -Wl,--gc-sections" - else - BASIC_LDFLAGS_JDK_ONLY="$BASIC_LDFLAGS_JDK_ONLY -Wl,--gc-sections" - fi + # keep vtables : -Wl,--undefined-glob=_ZTV* (but this seems not to work with gold ld) + # so keep at least the Metadata vtable that is used in the serviceability agent + BASIC_LDFLAGS_JVM_ONLY="$BASIC_LDFLAGS_JVM_ONLY -Wl,--gc-sections -Wl,--undefined=_ZTV8Metadata" + BASIC_LDFLAGS_JDK_ONLY="$BASIC_LDFLAGS_JDK_ONLY -Wl,--gc-sections" fi - BASIC_LDFLAGS_JVM_ONLY="" LDFLAGS_LTO="-flto=auto -fuse-linker-plugin -fno-strict-aliasing $DEBUG_PREFIX_CFLAGS" LDFLAGS_CXX_PARTIAL_LINKING="$MACHINE_FLAG -r" From efe7fd8683d1185a48b7000b132fd97241040ba8 Mon Sep 17 00:00:00 2001 From: Leo Korinth Date: Mon, 13 Apr 2026 08:14:47 +0000 Subject: [PATCH 255/359] 8380163: Fix implicit conversion in macroAssembler_aarch64.hpp Reviewed-by: aph, fyang --- .../cpu/aarch64/macroAssembler_aarch64.cpp | 37 ++++++++++++++++--- .../cpu/aarch64/macroAssembler_aarch64.hpp | 21 +++-------- 2 files changed, 37 insertions(+), 21 deletions(-) diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp index 7fa2e8086ad..7bec0a3c0ca 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp @@ -55,6 +55,7 @@ #include "runtime/sharedRuntime.hpp" #include "runtime/stubRoutines.hpp" #include "utilities/globalDefinitions.hpp" +#include "utilities/integerCast.hpp" #include "utilities/powerOfTwo.hpp" #ifdef COMPILER1 #include "c1/c1_LIRAssembler.hpp" @@ -2916,7 +2917,11 @@ void MacroAssembler::increment(Address dst, int value) // Push lots of registers in the bit set supplied. Don't push sp. // Return the number of words pushed -int MacroAssembler::push(unsigned int bitset, Register stack) { +int MacroAssembler::push(RegSet regset, Register stack) { + if (regset.bits() == 0) { + return 0; + } + auto bitset = integer_cast(regset.bits()); int words_pushed = 0; // Scan bitset to accumulate register pairs @@ -2946,7 +2951,11 @@ int MacroAssembler::push(unsigned int bitset, Register stack) { return count; } -int MacroAssembler::pop(unsigned int bitset, Register stack) { +int MacroAssembler::pop(RegSet regset, Register stack) { + if (regset.bits() == 0) { + return 0; + } + auto bitset = integer_cast(regset.bits()); int words_pushed = 0; // Scan bitset to accumulate register pairs @@ -2978,7 +2987,11 @@ int MacroAssembler::pop(unsigned int bitset, Register stack) { // Push lots of registers in the bit set supplied. Don't push sp. // Return the number of dwords pushed -int MacroAssembler::push_fp(unsigned int bitset, Register stack, FpPushPopMode mode) { +int MacroAssembler::push_fp(FloatRegSet regset, Register stack, FpPushPopMode mode) { + if (regset.bits() == 0) { + return 0; + } + auto bitset = integer_cast(regset.bits()); int words_pushed = 0; bool use_sve = false; int sve_vector_size_in_bytes = 0; @@ -3091,7 +3104,11 @@ int MacroAssembler::push_fp(unsigned int bitset, Register stack, FpPushPopMode m } // Return the number of dwords popped -int MacroAssembler::pop_fp(unsigned int bitset, Register stack, FpPushPopMode mode) { +int MacroAssembler::pop_fp(FloatRegSet regset, Register stack, FpPushPopMode mode) { + if (regset.bits() == 0) { + return 0; + } + auto bitset = integer_cast(regset.bits()); int words_pushed = 0; bool use_sve = false; int sve_vector_size_in_bytes = 0; @@ -3201,7 +3218,11 @@ int MacroAssembler::pop_fp(unsigned int bitset, Register stack, FpPushPopMode mo } // Return the number of dwords pushed -int MacroAssembler::push_p(unsigned int bitset, Register stack) { +int MacroAssembler::push_p(PRegSet regset, Register stack) { + if (regset.bits() == 0) { + return 0; + } + auto bitset = integer_cast(regset.bits()); bool use_sve = false; int sve_predicate_size_in_slots = 0; @@ -3238,7 +3259,11 @@ int MacroAssembler::push_p(unsigned int bitset, Register stack) { } // Return the number of dwords popped -int MacroAssembler::pop_p(unsigned int bitset, Register stack) { +int MacroAssembler::pop_p(PRegSet regset, Register stack) { + if (regset.bits() == 0) { + return 0; + } + auto bitset = integer_cast(regset.bits()); bool use_sve = false; int sve_predicate_size_in_slots = 0; diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp index 994fbe3c80f..dfba2dcff46 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp @@ -499,29 +499,20 @@ private: void mov_immediate64(Register dst, uint64_t imm64); void mov_immediate32(Register dst, uint32_t imm32); - int push(unsigned int bitset, Register stack); - int pop(unsigned int bitset, Register stack); - - int push_fp(unsigned int bitset, Register stack, FpPushPopMode mode); - int pop_fp(unsigned int bitset, Register stack, FpPushPopMode mode); - - int push_p(unsigned int bitset, Register stack); - int pop_p(unsigned int bitset, Register stack); - void mov(Register dst, Address a); public: - void push(RegSet regs, Register stack) { if (regs.bits()) push(regs.bits(), stack); } - void pop(RegSet regs, Register stack) { if (regs.bits()) pop(regs.bits(), stack); } + int push(RegSet regset, Register stack); + int pop(RegSet regset, Register stack); - void push_fp(FloatRegSet regs, Register stack, FpPushPopMode mode = PushPopFull) { if (regs.bits()) push_fp(regs.bits(), stack, mode); } - void pop_fp(FloatRegSet regs, Register stack, FpPushPopMode mode = PushPopFull) { if (regs.bits()) pop_fp(regs.bits(), stack, mode); } + int push_fp(FloatRegSet regset, Register stack, FpPushPopMode mode = PushPopFull); + int pop_fp(FloatRegSet regset, Register stack, FpPushPopMode mode = PushPopFull); static RegSet call_clobbered_gp_registers(); - void push_p(PRegSet regs, Register stack) { if (regs.bits()) push_p(regs.bits(), stack); } - void pop_p(PRegSet regs, Register stack) { if (regs.bits()) pop_p(regs.bits(), stack); } + int push_p(PRegSet regset, Register stack); + int pop_p(PRegSet regset, Register stack); // Push and pop everything that might be clobbered by a native // runtime call except rscratch1 and rscratch2. (They are always From e8c77d16c41b9e4569c888f87e97fa48a24f1498 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20Sikstr=C3=B6m?= Date: Mon, 13 Apr 2026 08:44:51 +0000 Subject: [PATCH 256/359] 8381900: Test vmTestbase/nsk/jvmti/scenarios/allocation/AP03/ap03t001 does not handle frequent GC gracefully Reviewed-by: aboldtch, sspitsyn --- .../scenarios/allocation/AP03/ap03t001/ap03t001.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/allocation/AP03/ap03t001/ap03t001.cpp b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/allocation/AP03/ap03t001/ap03t001.cpp index e50e1ff537b..0e5ff69fe6c 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/allocation/AP03/ap03t001/ap03t001.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/allocation/AP03/ap03t001/ap03t001.cpp @@ -42,6 +42,7 @@ static jvmtiCapabilities caps; static volatile int obj_free = 0; static volatile long obj_count = 0; +static volatile bool check_object_free = true; static jlong timeout = 0; static int user_data = 0; @@ -50,6 +51,9 @@ static const jlong DEBUGEE_CLASS_TAG = (jlong)1024; void JNICALL ObjectFree(jvmtiEnv *jvmti_env, jlong tag) { + if (!check_object_free) { + return; + } NSK_COMPLAIN1("Received unexpected ObjectFree event for an object with tag %ld\n\n", (long)tag); nsk_jvmti_setFailStatus(); obj_free++; @@ -190,6 +194,11 @@ agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) { } else { NSK_DISPLAY1("Number of objects IterateOverObjectsReachableFromObject has found: %d\n\n", obj_count); } + + // Ignore late ObjectFree notifications after the resurrected object has + // been validated. At this point the test has already proven that the + // tagged object survived finalization and is reachable through the catcher. + check_object_free = false; } while (0); NSK_DISPLAY0("Let debugee to finish\n"); From fa612824239ac1f997dd0d526995bd13e5c1bdd1 Mon Sep 17 00:00:00 2001 From: Dingli Zhang Date: Mon, 13 Apr 2026 09:06:37 +0000 Subject: [PATCH 257/359] 8381926: Fix implicit conversion in macroAssembler_riscv.hpp Reviewed-by: fyang, wenanjian --- .../cpu/riscv/macroAssembler_riscv.cpp | 43 ++++++++++++++----- .../cpu/riscv/macroAssembler_riscv.hpp | 25 +++++------ 2 files changed, 43 insertions(+), 25 deletions(-) diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index a2b7970f9f6..0e32c602d95 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -49,6 +49,7 @@ #include "runtime/sharedRuntime.hpp" #include "runtime/stubRoutines.hpp" #include "utilities/globalDefinitions.hpp" +#include "utilities/integerCast.hpp" #include "utilities/powerOfTwo.hpp" #ifdef COMPILER2 #include "opto/compile.hpp" @@ -1947,14 +1948,12 @@ void MacroAssembler::restore_cpu_control_state_after_jni(Register tmp) { } } -void MacroAssembler::push_reg(Register Rs) -{ +void MacroAssembler::push_reg(Register Rs) { subi(esp, esp, wordSize); sd(Rs, Address(esp, 0)); } -void MacroAssembler::pop_reg(Register Rd) -{ +void MacroAssembler::pop_reg(Register Rd) { ld(Rd, Address(esp, 0)); addi(esp, esp, wordSize); } @@ -1973,7 +1972,11 @@ int MacroAssembler::bitset_to_regs(unsigned int bitset, unsigned char* regs) { // Push integer registers in the bitset supplied. Don't push sp. // Return the number of words pushed -int MacroAssembler::push_reg(unsigned int bitset, Register stack) { +int MacroAssembler::push_reg(RegSet regset, Register stack) { + if (regset.bits() == 0) { + return 0; + } + auto bitset = integer_cast(regset.bits()); DEBUG_ONLY(int words_pushed = 0;) unsigned char regs[32]; int count = bitset_to_regs(bitset, regs); @@ -1993,7 +1996,11 @@ int MacroAssembler::push_reg(unsigned int bitset, Register stack) { return count; } -int MacroAssembler::pop_reg(unsigned int bitset, Register stack) { +int MacroAssembler::pop_reg(RegSet regset, Register stack) { + if (regset.bits() == 0) { + return 0; + } + auto bitset = integer_cast(regset.bits()); DEBUG_ONLY(int words_popped = 0;) unsigned char regs[32]; int count = bitset_to_regs(bitset, regs); @@ -2015,7 +2022,11 @@ int MacroAssembler::pop_reg(unsigned int bitset, Register stack) { // Push floating-point registers in the bitset supplied. // Return the number of words pushed -int MacroAssembler::push_fp(unsigned int bitset, Register stack) { +int MacroAssembler::push_fp(FloatRegSet regset, Register stack) { + if (regset.bits() == 0) { + return 0; + } + auto bitset = integer_cast(regset.bits()); DEBUG_ONLY(int words_pushed = 0;) unsigned char regs[32]; int count = bitset_to_regs(bitset, regs); @@ -2035,7 +2046,11 @@ int MacroAssembler::push_fp(unsigned int bitset, Register stack) { return count; } -int MacroAssembler::pop_fp(unsigned int bitset, Register stack) { +int MacroAssembler::pop_fp(FloatRegSet regset, Register stack) { + if (regset.bits() == 0) { + return 0; + } + auto bitset = integer_cast(regset.bits()); DEBUG_ONLY(int words_popped = 0;) unsigned char regs[32]; int count = bitset_to_regs(bitset, regs); @@ -2721,7 +2736,11 @@ void MacroAssembler::kernel_crc32(Register crc, Register buf, Register len, #ifdef COMPILER2 // Push vector registers in the bitset supplied. // Return the number of words pushed -int MacroAssembler::push_v(unsigned int bitset, Register stack) { +int MacroAssembler::push_v(VectorRegSet regset, Register stack) { + if (regset.bits() == 0) { + return 0; + } + auto bitset = integer_cast(regset.bits()); int vector_size_in_bytes = Matcher::scalable_vector_reg_size(T_BYTE); // Scan bitset to accumulate register pairs @@ -2736,7 +2755,11 @@ int MacroAssembler::push_v(unsigned int bitset, Register stack) { return count * vector_size_in_bytes / wordSize; } -int MacroAssembler::pop_v(unsigned int bitset, Register stack) { +int MacroAssembler::pop_v(VectorRegSet regset, Register stack) { + if (regset.bits() == 0) { + return 0; + } + auto bitset = integer_cast(regset.bits()); int vector_size_in_bytes = Matcher::scalable_vector_reg_size(T_BYTE); // Scan bitset to accumulate register pairs diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp index a51a6aea468..4cc55e7ae23 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp @@ -818,15 +818,6 @@ class MacroAssembler: public Assembler { void double_bgt(FloatRegister Rs1, FloatRegister Rs2, Label &l, bool is_far = false, bool is_unordered = false); private: - int push_reg(unsigned int bitset, Register stack); - int pop_reg(unsigned int bitset, Register stack); - int push_fp(unsigned int bitset, Register stack); - int pop_fp(unsigned int bitset, Register stack); -#ifdef COMPILER2 - int push_v(unsigned int bitset, Register stack); - int pop_v(unsigned int bitset, Register stack); -#endif // COMPILER2 - // The signed 20-bit upper imm can materialize at most negative 0xF...F80000000, two G. // The following signed 12-bit imm can at max subtract 0x800, two K, from that previously loaded two G. bool is_valid_32bit_offset(int64_t x) { @@ -844,15 +835,19 @@ private: } public: + // Stack push and pop individual 64 bit registers void push_reg(Register Rs); void pop_reg(Register Rd); - void push_reg(RegSet regs, Register stack) { if (regs.bits()) push_reg(regs.bits(), stack); } - void pop_reg(RegSet regs, Register stack) { if (regs.bits()) pop_reg(regs.bits(), stack); } - void push_fp(FloatRegSet regs, Register stack) { if (regs.bits()) push_fp(regs.bits(), stack); } - void pop_fp(FloatRegSet regs, Register stack) { if (regs.bits()) pop_fp(regs.bits(), stack); } + + int push_reg(RegSet regset, Register stack); + int pop_reg(RegSet regset, Register stack); + + int push_fp(FloatRegSet regset, Register stack); + int pop_fp(FloatRegSet regset, Register stack); + #ifdef COMPILER2 - void push_v(VectorRegSet regs, Register stack) { if (regs.bits()) push_v(regs.bits(), stack); } - void pop_v(VectorRegSet regs, Register stack) { if (regs.bits()) pop_v(regs.bits(), stack); } + int push_v(VectorRegSet regset, Register stack); + int pop_v(VectorRegSet regset, Register stack); #endif // COMPILER2 // Push and pop everything that might be clobbered by a native From d605b5709a43f87a01a650fcd8aed2fb6d2d3f8a Mon Sep 17 00:00:00 2001 From: Dusan Balek Date: Mon, 13 Apr 2026 09:08:45 +0000 Subject: [PATCH 258/359] 8179187: Misleading compilation error on annotated fully-qualified classname Reviewed-by: jlahoda, vromero --- .../share/classes/com/sun/tools/javac/comp/Attr.java | 12 ++++++++---- .../failures/CantAnnotatePackages.java | 2 +- .../failures/CantAnnotatePackages.out | 6 +++--- .../failures/CantAnnotateScoping.java | 2 +- .../typeAnnotations/failures/CantAnnotateScoping.out | 9 +++++---- 5 files changed, 18 insertions(+), 13 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java index 444530c7266..89ae68e85ba 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java @@ -5270,11 +5270,15 @@ public class Attr extends JCTree.Visitor { public void visitAnnotatedType(JCAnnotatedType tree) { attribAnnotationTypes(tree.annotations, env); - Type underlyingType = attribType(tree.underlyingType, env); - Type annotatedType = underlyingType.preannotatedType(); + Type underlyingType = attribTree(tree.underlyingType, env, resultInfo); + if (underlyingType.getTag() == PACKAGE) { + result = tree.type = underlyingType; + } else { + Type annotatedType = underlyingType.preannotatedType(); - annotate.annotateTypeSecondStage(tree, tree.annotations, annotatedType); - result = tree.type = annotatedType; + annotate.annotateTypeSecondStage(tree, tree.annotations, annotatedType); + result = tree.type = annotatedType; + } } public void visitErroneous(JCErroneous tree) { diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotatePackages.java b/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotatePackages.java index d35351b6f40..5031a74bc5a 100644 --- a/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotatePackages.java +++ b/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotatePackages.java @@ -1,6 +1,6 @@ /* * @test /nodynamiccopyright/ - * @bug 8026564 8043226 8334055 + * @bug 8026564 8043226 8334055 8179187 * @summary The parts of a fully-qualified type can't be annotated. * @author Werner Dietl * @compile/fail/ref=CantAnnotatePackages.out -XDrawDiagnostics CantAnnotatePackages.java diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotatePackages.out b/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotatePackages.out index b91d65828b9..6e2b9cb93b0 100644 --- a/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotatePackages.out +++ b/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotatePackages.out @@ -1,5 +1,5 @@ -CantAnnotatePackages.java:16:14: compiler.err.cant.resolve.location: kindname.class, java, , , (compiler.misc.location: kindname.class, CantAnnotatePackages, null) -CantAnnotatePackages.java:17:9: compiler.err.cant.resolve.location: kindname.class, lang, , , (compiler.misc.location: kindname.package, java, null) -CantAnnotatePackages.java:18:14: compiler.err.cant.resolve.location: kindname.class, lang, , , (compiler.misc.location: kindname.package, java, null) CantAnnotatePackages.java:14:18: compiler.err.type.annotation.inadmissible: (compiler.misc.type.annotation.1: @TA), java.lang, @TA java.lang.Object +CantAnnotatePackages.java:16:14: compiler.err.type.annotation.inadmissible: (compiler.misc.type.annotation.1: @TA), java.lang, @TA java.lang.Object +CantAnnotatePackages.java:17:9: compiler.err.type.annotation.inadmissible: (compiler.misc.type.annotation.1: @TA), java.lang, @TA java.lang.Object +CantAnnotatePackages.java:18:14: compiler.err.type.annotation.inadmissible: (compiler.misc.type.annotation.1: @TA), java.lang, @TA java.lang.Object 4 errors diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotateScoping.java b/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotateScoping.java index 4bdd791909c..427c1fef3a8 100644 --- a/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotateScoping.java +++ b/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotateScoping.java @@ -1,6 +1,6 @@ /* * @test /nodynamiccopyright/ - * @bug 8006733 8006775 8043226 8334055 + * @bug 8006733 8006775 8043226 8334055 8179187 * @summary Ensure behavior for nested types is correct. * @author Werner Dietl * @compile/fail/ref=CantAnnotateScoping.out -XDrawDiagnostics CantAnnotateScoping.java diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotateScoping.out b/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotateScoping.out index ade5333a446..2ae736ad315 100644 --- a/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotateScoping.out +++ b/test/langtools/tools/javac/annotations/typeAnnotations/failures/CantAnnotateScoping.out @@ -1,12 +1,13 @@ -CantAnnotateScoping.java:63:9: compiler.err.cant.resolve.location: kindname.class, lang, , , (compiler.misc.location: kindname.package, java, null) -CantAnnotateScoping.java:68:9: compiler.err.cant.resolve.location: kindname.class, XXX, , , (compiler.misc.location: kindname.package, java, null) -CantAnnotateScoping.java:71:9: compiler.err.cant.resolve.location: kindname.class, lang, , , (compiler.misc.location: kindname.package, java, null) +CantAnnotateScoping.java:68:18: compiler.err.doesnt.exist: java.XXX CantAnnotateScoping.java:38:14: compiler.err.type.annotation.inadmissible: (compiler.misc.type.annotation.1: @TA), Test.Outer, @TA Test.Outer.SInner CantAnnotateScoping.java:51:18: compiler.err.type.annotation.inadmissible: (compiler.misc.type.annotation.1: @TA), java.lang, @TA java.lang.Object CantAnnotateScoping.java:60:37: compiler.err.type.annotation.inadmissible: (compiler.misc.type.annotation: @TA,@TA2), java.lang, @DTA @TA @TA2 java.lang.Object CantAnnotateScoping.java:40:14: compiler.err.type.annotation.inadmissible: (compiler.misc.type.annotation.1: @TA), Test.Outer, @TA Test.Outer.SInner +CantAnnotateScoping.java:63:11: compiler.err.annotation.type.not.applicable.to.type: DA +CantAnnotateScoping.java:68:11: compiler.err.annotation.type.not.applicable.to.type: DA +CantAnnotateScoping.java:71:9: compiler.err.type.annotation.inadmissible: (compiler.misc.type.annotation.1: @TA), java.lang, @TA java.lang.Object CantAnnotateScoping.java:44:34: compiler.err.type.annotation.inadmissible: (compiler.misc.type.annotation: @TA,@TA2), Test.Outer, @TA @TA2 Test.Outer.SInner CantAnnotateScoping.java:44:25: compiler.err.annotation.type.not.applicable.to.type: DA CantAnnotateScoping.java:48:38: compiler.err.type.annotation.inadmissible: (compiler.misc.type.annotation.1: @TA), Test.Outer, @TA Test.Outer.SInner CantAnnotateScoping.java:48:34: compiler.err.annotation.type.not.applicable.to.type: DA -11 errors +12 errors From a76e38c7eb135dcd613a29fa63ab4761d5d81d19 Mon Sep 17 00:00:00 2001 From: Daniel Fuchs Date: Mon, 13 Apr 2026 09:24:41 +0000 Subject: [PATCH 259/359] 8381359: Refactor java/net/DatagramSocket TestNG tests to use JUnit Reviewed-by: vyazici --- .../net/DatagramSocket/ConnectPortZero.java | 85 ++++++++--------- .../java/net/DatagramSocket/Constructor.java | 10 +- .../net/DatagramSocket/DatagramTimeout.java | 90 +++++++++--------- .../OldDatagramSocketImplTest.java | 64 ++++++------- .../java/net/DatagramSocket/SendCheck.java | 93 +++++++++---------- .../java/net/DatagramSocket/SendPortZero.java | 46 ++++----- .../DatagramSocket/SendReceiveMaxSize.java | 57 ++++++------ .../SetGetReceiveBufferSize.java | 35 +++---- .../DatagramSocket/SetGetSendBufferSize.java | 41 ++++---- .../DatagramSocket/SupportedOptionsCheck.java | 8 +- 10 files changed, 262 insertions(+), 267 deletions(-) diff --git a/test/jdk/java/net/DatagramSocket/ConnectPortZero.java b/test/jdk/java/net/DatagramSocket/ConnectPortZero.java index 7f61d146bc0..342dae4c02b 100644 --- a/test/jdk/java/net/DatagramSocket/ConnectPortZero.java +++ b/test/jdk/java/net/DatagramSocket/ConnectPortZero.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * 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,11 +21,6 @@ * questions. */ -import org.testng.annotations.AfterTest; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - import java.io.IOException; import java.io.UncheckedIOException; import java.net.DatagramSocket; @@ -34,62 +29,64 @@ import java.net.InetSocketAddress; import java.net.MulticastSocket; import java.net.SocketException; import java.nio.channels.DatagramChannel; +import java.util.List; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertThrows; -import static org.testng.Assert.expectThrows; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; /* * @test * @bug 8240533 * @summary Check that DatagramSocket, MulticastSocket and DatagramSocketAdaptor * throw expected Exception when connecting to port 0 - * @run testng/othervm ConnectPortZero + * @run junit/othervm ${test.main.class} */ public class ConnectPortZero { - private InetAddress loopbackAddr, wildcardAddr; - private DatagramSocket datagramSocket, datagramSocketAdaptor; - private MulticastSocket multicastSocket; - + private static InetAddress loopbackAddr, wildcardAddr; private static final Class SE = SocketException.class; private static final Class UCIOE = UncheckedIOException.class; - @BeforeTest - public void setUp() throws IOException { + @BeforeAll + public static void setUp() throws IOException { loopbackAddr = InetAddress.getLoopbackAddress(); wildcardAddr = new InetSocketAddress(0).getAddress(); - - datagramSocket = new DatagramSocket(); - multicastSocket = new MulticastSocket(); - datagramSocketAdaptor = DatagramChannel.open().socket(); } - @DataProvider(name = "data") - public Object[][] variants() { - return new Object[][]{ - { datagramSocket, loopbackAddr }, - { datagramSocketAdaptor, loopbackAddr }, - { multicastSocket, loopbackAddr }, - { datagramSocket, wildcardAddr }, - { datagramSocketAdaptor, wildcardAddr }, - { multicastSocket, wildcardAddr } - }; + public static List testCases() throws IOException { + // Note that Closeable arguments passed to a ParameterizedTest are automatically + // closed by JUnit. We do not want to rely on this, but we do need to + // create a new set of sockets for each invocation of this method, so that + // the next test method invoked doesn't get a closed socket. + return List.of( + Arguments.of(new DatagramSocket(), loopbackAddr), + Arguments.of(DatagramChannel.open().socket(), loopbackAddr), + Arguments.of(new MulticastSocket(), loopbackAddr), + Arguments.of(new DatagramSocket(), wildcardAddr), + Arguments.of(DatagramChannel.open().socket(), wildcardAddr), + Arguments.of(new MulticastSocket(), wildcardAddr) + ); } - @Test(dataProvider = "data") - public void testConnect(DatagramSocket ds, InetAddress addr) { - Throwable t = expectThrows(UCIOE, () -> ds.connect(addr, 0)); - assertEquals(t.getCause().getClass(), SE); - - assertThrows(SE, () -> ds - .connect(new InetSocketAddress(addr, 0))); - } - - @AfterTest - public void tearDown() { - datagramSocket.close(); - multicastSocket.close(); - datagramSocketAdaptor.close(); + @ParameterizedTest + @MethodSource("testCases") + public void testConnect(DatagramSocket socket, InetAddress addr) { + try (var ds = socket) { + assertFalse(ds.isConnected()); + assertFalse(ds.isClosed()); + Throwable t = assertThrows(UCIOE, () -> ds.connect(addr, 0)); + assertSame(SE, t.getCause().getClass()); + assertFalse(ds.isConnected()); + assertFalse(ds.isClosed()); + assertThrows(SE, () -> ds + .connect(new InetSocketAddress(addr, 0))); + assertFalse(ds.isConnected()); + assertFalse(ds.isClosed()); + } } } diff --git a/test/jdk/java/net/DatagramSocket/Constructor.java b/test/jdk/java/net/DatagramSocket/Constructor.java index 6fecf8dc732..6e5cd944297 100644 --- a/test/jdk/java/net/DatagramSocket/Constructor.java +++ b/test/jdk/java/net/DatagramSocket/Constructor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * 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,18 +24,18 @@ /* @test * @bug 8243507 8243999 * @summary Checks to ensure that DatagramSocket constructors behave as expected - * @run testng Constructor + * @run junit ${test.main.class} */ -import org.testng.annotations.Test; import java.io.IOException; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.SocketAddress; -import static org.testng.Assert.assertThrows; -import static org.testng.Assert.assertTrue; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; public class Constructor { private static final InetAddress LOOPBACK = InetAddress.getLoopbackAddress(); diff --git a/test/jdk/java/net/DatagramSocket/DatagramTimeout.java b/test/jdk/java/net/DatagramSocket/DatagramTimeout.java index 4d979f9dc8d..a8d35a64dc8 100644 --- a/test/jdk/java/net/DatagramSocket/DatagramTimeout.java +++ b/test/jdk/java/net/DatagramSocket/DatagramTimeout.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2026, Oracle and/or its affiliates. All rights reserved. * 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,23 +26,24 @@ * @bug 4163126 8222829 * @summary Test to see if timeout hangs. Also checks that * negative timeout value fails as expected. - * @run testng DatagramTimeout + * @run junit ${test.main.class} */ +import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.MulticastSocket; import java.net.SocketException; import java.net.SocketTimeoutException; import java.nio.channels.DatagramChannel; +import java.util.List; -import org.testng.annotations.AfterTest; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertThrows; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; public class DatagramTimeout { private static final Class IAE = @@ -51,49 +52,46 @@ public class DatagramTimeout { SocketTimeoutException.class; private static final Class SE = SocketException.class; - private DatagramSocket datagramSocket, multicastSocket, - datagramSocketAdaptor; - - @BeforeTest - public void setUp() throws Exception { - datagramSocket = new DatagramSocket(); - multicastSocket = new MulticastSocket(); - datagramSocketAdaptor = DatagramChannel.open().socket(); + public static List sockets() throws IOException { + // Note that Closeable arguments passed to a ParameterizedTest are automatically + // closed by JUnit. We do not want to rely on this, but we do need to + // create a new set of sockets for each invocation of this method, so that + // the next test method invoked doesn't get a closed socket. + return List.of( + new DatagramSocket(), + new MulticastSocket(), + DatagramChannel.open().socket()); } - @DataProvider(name = "data") - public Object[][] variants() { - return new Object[][]{ - { datagramSocket }, - { datagramSocketAdaptor }, - { multicastSocket }, - }; + @ParameterizedTest + @MethodSource("sockets") + public void testSetNegTimeout(DatagramSocket socket) { + try (var ds = socket) { + assertFalse(ds.isClosed()); + assertThrows(IAE, () -> ds.setSoTimeout(-1)); + } } - @Test(dataProvider = "data") - public void testSetNegTimeout(DatagramSocket ds) { - assertThrows(IAE, () -> ds.setSoTimeout(-1)); + @ParameterizedTest + @MethodSource("sockets") + public void testSetTimeout(DatagramSocket socket) throws Exception { + try (var ds = socket) { + assertFalse(ds.isClosed()); + byte[] buffer = new byte[50]; + DatagramPacket pkt = new DatagramPacket(buffer, buffer.length); + ds.setSoTimeout(2); + assertThrows(STE, () -> ds.receive(pkt)); + } } - @Test(dataProvider = "data") - public void testSetTimeout(DatagramSocket ds) throws Exception { - byte[] buffer = new byte[50]; - DatagramPacket pkt = new DatagramPacket(buffer, buffer.length); - ds.setSoTimeout(2); - assertThrows(STE, () -> ds.receive(pkt)); - } - - @Test(dataProvider = "data") - public void testGetTimeout(DatagramSocket ds) throws Exception { - ds.setSoTimeout(10); - assertEquals(10, ds.getSoTimeout()); - } - - @AfterTest - public void tearDown() { - datagramSocket.close(); - multicastSocket.close(); - datagramSocketAdaptor.close(); + @ParameterizedTest + @MethodSource("sockets") + public void testGetTimeout(DatagramSocket socket) throws Exception { + try (var ds = socket) { + assertFalse(ds.isClosed()); + ds.setSoTimeout(10); + assertEquals(10, ds.getSoTimeout()); + } } @Test diff --git a/test/jdk/java/net/DatagramSocket/OldDatagramSocketImplTest.java b/test/jdk/java/net/DatagramSocket/OldDatagramSocketImplTest.java index 7f8eea874ec..1d3c39ffd71 100644 --- a/test/jdk/java/net/DatagramSocket/OldDatagramSocketImplTest.java +++ b/test/jdk/java/net/DatagramSocket/OldDatagramSocketImplTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * 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,15 +25,24 @@ * @test * @bug 8260428 * @summary Drop support for pre JDK 1.4 DatagramSocketImpl implementations - * @run testng/othervm OldDatagramSocketImplTest + * @run junit/othervm ${test.main.class} */ -import org.testng.annotations.Test; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.DatagramSocketImpl; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.NetworkInterface; +import java.net.SocketAddress; +import java.net.SocketException; -import java.net.*; -import java.io.*; - -import static org.testng.Assert.assertEquals; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; public class OldDatagramSocketImplTest { InetAddress LOOPBACK = InetAddress.getLoopbackAddress(); @@ -41,22 +50,18 @@ public class OldDatagramSocketImplTest { @Test public void testOldImplConnect() { try (var ds = new DatagramSocket(new OldDatagramSocketImpl()) {}) { - ds.connect(new InetSocketAddress(LOOPBACK, 6667)); - throw new RuntimeException("ERROR: test failed"); - } catch (SocketException ex) { - assertEquals(ex.getMessage(), "connect not implemented"); - System.out.println("PASSED: default implementation of connect has thrown as expected"); + SocketException ex = assertThrows(SocketException.class, + () -> ds.connect(new InetSocketAddress(LOOPBACK, 6667))); + assertEquals("connect not implemented", ex.getMessage()); } } @Test public void testOldImplConnectTwoArgs() { try (var ds = new DatagramSocket(new OldDatagramSocketImpl()) {}) { - ds.connect(LOOPBACK, 6667); - throw new RuntimeException("ERROR: test failed"); - } catch (UncheckedIOException ex) { - assertEquals(ex.getMessage(), "connect failed"); - System.out.println("PASSED: default implementation of connect has thrown as expected"); + UncheckedIOException ex = assertThrows(UncheckedIOException.class, + () -> ds.connect(LOOPBACK, 6667)); + assertEquals("connect failed", ex.getMessage()); } } @@ -64,36 +69,27 @@ public class OldDatagramSocketImplTest { public void testOldImplDisconnect() { try (var ds = new DatagramSocket(new OldDatagramSocketImplWithValidConnect()) { }){ ds.connect(LOOPBACK, 6667); - ds.disconnect(); - throw new RuntimeException("ERROR: test failed"); - } catch (UncheckedIOException ex) { + UncheckedIOException ex = assertThrows(UncheckedIOException.class, () -> ds.disconnect()); var innerException = ex.getCause(); - assertEquals(innerException.getClass(), SocketException.class); - assertEquals(innerException.getMessage(), "disconnect not implemented"); - System.out.println("PASSED: default implementation of disconnect has thrown as expected"); + assertSame(SocketException.class, innerException.getClass()); + assertEquals("disconnect not implemented", innerException.getMessage()); } } @Test public void testOldImplPublic() { try (var ds = new PublicOldDatagramSocketImpl()) { - ds.connect(LOOPBACK, 0); - throw new RuntimeException("ERROR: test failed"); - } catch (SocketException ex) { - assertEquals(ex.getMessage(), "connect not implemented"); - System.out.println("PASSED: default implementation of disconnect has thrown as expected"); + SocketException ex = assertThrows(SocketException.class, () -> ds.connect(LOOPBACK, 0)); + assertEquals("connect not implemented", ex.getMessage()); } } @Test public void testOldImplPublicDisconnect() { try (var ds = new PublicOldDatagramSocketImplWithValidConnect()) { - ds.disconnect(); - throw new RuntimeException("ERROR: test failed"); - } catch (UncheckedIOException ex) { + UncheckedIOException ex = assertThrows(UncheckedIOException.class, () -> ds.disconnect()); var innerException = ex.getCause(); - assertEquals(innerException.getClass(), SocketException.class); - assertEquals(innerException.getMessage(), "disconnect not implemented"); - System.out.println("PASSED: default implementation of disconnect has thrown as expected"); + assertSame(SocketException.class, innerException.getClass()); + assertEquals("disconnect not implemented", innerException.getMessage()); } } diff --git a/test/jdk/java/net/DatagramSocket/SendCheck.java b/test/jdk/java/net/DatagramSocket/SendCheck.java index 482eadb3cf9..5cefb0fd0e6 100644 --- a/test/jdk/java/net/DatagramSocket/SendCheck.java +++ b/test/jdk/java/net/DatagramSocket/SendCheck.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * 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,12 +33,14 @@ import java.nio.channels.DatagramChannel; import java.util.ArrayList; import java.util.List; -import org.testng.annotations.AfterTest; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.Test; -import org.testng.annotations.DataProvider; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; -import static org.testng.Assert.expectThrows; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertThrows; /* * @test @@ -47,28 +49,24 @@ import static org.testng.Assert.expectThrows; * DatagramSocketAdaptor and DatagramChannel all * throw expected Exception when passed a DatagramPacket * with invalid details - * @run testng SendCheck + * @run junit ${test.main.class} */ public class SendCheck { - private InetAddress loopbackAddr, wildcardAddr; + private static InetAddress loopbackAddr, wildcardAddr; static final Class IOE = IOException.class; static final Class SE = SocketException.class; static final byte[] buf = {0, 1, 2}; static DatagramSocket socket; - @BeforeTest - public void setUp() { - try { - socket = new DatagramSocket(); - } catch (Exception e) { - throw new ExceptionInInitializerError(e); - } + @BeforeAll + public static void setUp() throws Exception { + socket = new DatagramSocket(); } - @AfterTest - public void closeDown() { + @AfterAll + public static void closeDown() { socket.close(); } @@ -92,7 +90,7 @@ public class SendCheck { if (address == null) { description = ":" + port; } else if (port < 0) { - description = packet.getAddress().toString() + ":" + port; + description = packet.getAddress() + ":" + port; } else { description = packet.getSocketAddress().toString(); } @@ -100,8 +98,7 @@ public class SendCheck { } } - @DataProvider(name = "packets") - Object[][] providerIO() throws IOException { + static List providerIO() throws IOException { loopbackAddr = InetAddress.getLoopbackAddress(); wildcardAddr = new InetSocketAddress(0).getAddress(); @@ -124,44 +121,46 @@ public class SendCheck { List Packets = List.of(Packet.of(pkt1), Packet.of(pkt2)); - List senders = List.of( - Sender.of(new DatagramSocket(null)), - Sender.of(new MulticastSocket(null)), - Sender.of(DatagramChannel.open()), - Sender.of(DatagramChannel.open().socket()) - ); - - List testcases = new ArrayList<>(); + List testcases = new ArrayList<>(); for (var packet : Packets) { + // Note that Closeable arguments passed to a ParameterizedTest are automatically + // closed by JUnit. We do not want to rely on this, but we do need to + // create a new set of sockets for each invocation of this method, so that + // the next test method invoked doesn't get a closed socket. + List senders = List.of( + Sender.of(new DatagramSocket(null)), + Sender.of(new MulticastSocket(null)), + Sender.of(DatagramChannel.open()), + Sender.of(DatagramChannel.open().socket()) + ); addTestCaseFor(testcases, senders, packet); } - return testcases.toArray(new Object[0][0]); + return testcases; } - static void addTestCaseFor(List testcases, + static void addTestCaseFor(List testcases, List senders, Packet p) { for (var s : senders) { - Object[] testcase = new Object[]{s, p, s.expectedException()}; - testcases.add(testcase); + testcases.add(Arguments.of(s, p, s.expectedException())); } } - @Test(dataProvider = "packets") - public static void sendCheck(Sender sender, - Packet packet, - Class exception) { - DatagramPacket pkt = packet.packet; - if (exception != null) { - Throwable t = expectThrows(exception, () -> sender.send(pkt)); - System.out.printf("%s got expected exception %s%n", - packet.toString(), t); - } else { - try { - sender.send(pkt); - } catch (IOException e) { - throw new AssertionError("Unexpected exception for " - + sender + " / " + packet, e); + @ParameterizedTest + @MethodSource("providerIO") + public void sendCheck(Sender socket, + Packet packet, + Class exception) + throws IOException + { + try (var sender = socket) { + DatagramPacket pkt = packet.packet; + if (exception != null) { + Throwable t = assertThrows(exception, () -> sender.send(pkt)); + System.out.printf("%s got expected exception %s%n", packet, t); + } else { + assertDoesNotThrow(() -> sender.send(pkt), + "Unexpected exception for " + sender + " / " + packet); } } } diff --git a/test/jdk/java/net/DatagramSocket/SendPortZero.java b/test/jdk/java/net/DatagramSocket/SendPortZero.java index 03c78c3e54d..149424232ee 100644 --- a/test/jdk/java/net/DatagramSocket/SendPortZero.java +++ b/test/jdk/java/net/DatagramSocket/SendPortZero.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * 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,39 +21,40 @@ * questions. */ -import org.testng.annotations.AfterTest; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetSocketAddress; import java.net.InetAddress; -import java.net.MulticastSocket; import java.net.SocketException; import java.nio.channels.DatagramChannel; -import static org.testng.Assert.assertThrows; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; /* * @test * @bug 8236105 8240533 * @summary Check that DatagramSocket throws expected * Exception when sending a DatagramPacket with port 0 - * @run testng/othervm SendPortZero + * @run junit/othervm ${test.main.class} */ public class SendPortZero { - private InetAddress loopbackAddr, wildcardAddr; - private DatagramSocket datagramSocket, datagramSocketAdaptor; - private DatagramPacket loopbackZeroPkt, wildcardZeroPkt, wildcardValidPkt; + private static InetAddress loopbackAddr, wildcardAddr; + private static DatagramSocket datagramSocket, datagramSocketAdaptor; + private static DatagramPacket loopbackZeroPkt, wildcardZeroPkt, wildcardValidPkt; private static final Class SE = SocketException.class; - @BeforeTest - public void setUp() throws IOException { + @BeforeAll + public static void setUp() throws IOException { datagramSocket = new DatagramSocket(); datagramSocketAdaptor = DatagramChannel.open().socket(); @@ -81,8 +82,13 @@ public class SendPortZero { wildcardValidPkt.setPort(datagramSocket.getLocalPort()); } - @DataProvider(name = "data") - public Object[][] variants() { + @AfterAll + public static void tearDown() { + datagramSocket.close(); + datagramSocketAdaptor.close(); + } + + public static Object[][] testCases() { return new Object[][]{ { datagramSocket, loopbackZeroPkt }, { datagramSocket, wildcardZeroPkt }, @@ -96,14 +102,10 @@ public class SendPortZero { }; } - @Test(dataProvider = "data") + @ParameterizedTest(autoCloseArguments = false) // closed in tearDown + @MethodSource("testCases") public void testSend(DatagramSocket ds, DatagramPacket pkt) { + assertFalse(ds.isClosed()); assertThrows(SE, () -> ds.send(pkt)); } - - @AfterTest - public void tearDown() { - datagramSocket.close(); - datagramSocketAdaptor.close(); - } } diff --git a/test/jdk/java/net/DatagramSocket/SendReceiveMaxSize.java b/test/jdk/java/net/DatagramSocket/SendReceiveMaxSize.java index 36eae0b5c32..d85817337f4 100644 --- a/test/jdk/java/net/DatagramSocket/SendReceiveMaxSize.java +++ b/test/jdk/java/net/DatagramSocket/SendReceiveMaxSize.java @@ -33,7 +33,7 @@ * limit. * @library /test/lib * @build jdk.test.lib.net.IPSupport - * @run testng/othervm SendReceiveMaxSize + * @run junit/othervm ${test.main.class} */ /* * @test id=preferIPv4Stack @@ -42,7 +42,7 @@ * maximum size on macOS, using an IPv4 only socket. * @library /test/lib * @build jdk.test.lib.net.IPSupport - * @run testng/othervm -Djava.net.preferIPv4Stack=true SendReceiveMaxSize + * @run junit/othervm -Djava.net.preferIPv4Stack=true ${test.main.class} */ /* * @test id=preferIPv6Addresses @@ -52,7 +52,7 @@ * IPv6 addresses. * @library /test/lib * @build jdk.test.lib.net.IPSupport - * @run testng/othervm -Djava.net.preferIPv6Addresses=true SendReceiveMaxSize + * @run junit/othervm -Djava.net.preferIPv6Addresses=true ${test.main.class} */ /* * @test id=preferLoopback @@ -62,7 +62,7 @@ * interface. * @library /test/lib * @build jdk.test.lib.net.IPSupport - * @run testng/othervm -Dtest.preferLoopback=true SendReceiveMaxSize + * @run junit/othervm -Dtest.preferLoopback=true ${test.main.class} */ /* * @test id=preferIPv6Loopback @@ -72,7 +72,7 @@ * interface. * @library /test/lib * @build jdk.test.lib.net.IPSupport - * @run testng/othervm -Dtest.preferLoopback=true -Djava.net.preferIPv6Addresses=true SendReceiveMaxSize + * @run junit/othervm -Dtest.preferLoopback=true -Djava.net.preferIPv6Addresses=true ${test.main.class} */ /* * @test id=preferIPv4Loopback @@ -82,16 +82,12 @@ * loopback interface * @library /test/lib * @build jdk.test.lib.net.IPSupport - * @run testng/othervm -Dtest.preferLoopback=true -Djava.net.preferIPv4Stack=true SendReceiveMaxSize + * @run junit/othervm -Dtest.preferLoopback=true -Djava.net.preferIPv4Stack=true ${test.main.class} */ import jdk.test.lib.RandomFactory; import jdk.test.lib.Platform; import jdk.test.lib.net.IPSupport; -import org.testng.SkipException; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import java.io.IOException; import java.net.DatagramPacket; @@ -101,21 +97,27 @@ import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.MulticastSocket; import java.nio.channels.DatagramChannel; -import java.util.Optional; import java.util.Random; import static java.net.StandardSocketOptions.SO_RCVBUF; import static jdk.test.lib.net.IPSupport.diagnoseConfigurationIssue; -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.expectThrows; + +import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; public class SendReceiveMaxSize { private final static boolean PREFER_LOOPBACK = Boolean.getBoolean("test.preferLoopback"); - private int BUF_LIMIT; - private InetAddress HOST_ADDR; + private static int BUF_LIMIT; + private static InetAddress HOST_ADDR; private final static int IPV4_SNDBUF = IPSupport.getMaxUDPSendBufSizeIPv4(); private final static int IPV6_SNDBUF = IPSupport.getMaxUDPSendBufSizeIPv6(); private final static Class IOE = IOException.class; @@ -126,20 +128,16 @@ public class SendReceiveMaxSize { } static DatagramSocketSupplier supplier(DatagramSocketSupplier supplier) { return supplier; } - @BeforeTest - public void setUp() throws IOException { - Optional configurationIssue = diagnoseConfigurationIssue(); - configurationIssue.map(SkipException::new).ifPresent(x -> { - throw x; - }); - + @BeforeAll + public static void setUp() throws IOException { + // skip test if the configuration is not operational + diagnoseConfigurationIssue().ifPresent(Assumptions::abort); HOST_ADDR = PREFER_LOOPBACK ? InetAddress.getLoopbackAddress() : InetAddress.getLocalHost(); BUF_LIMIT = (HOST_ADDR instanceof Inet6Address) ? IPV6_SNDBUF : IPV4_SNDBUF; System.out.printf("Host address: %s, Buffer limit: %d%n", HOST_ADDR, BUF_LIMIT); } - @DataProvider - public Object[][] invariants() { + public static Object[][] testCases() { var ds = supplier(() -> new DatagramSocket()); var ms = supplier(() -> new MulticastSocket()); var dsa = supplier(() -> DatagramChannel.open().socket()); @@ -156,7 +154,8 @@ public class SendReceiveMaxSize { }; } - @Test(dataProvider = "invariants") + @ParameterizedTest + @MethodSource("testCases") public void testSendReceiveMaxSize(String name, int capacity, DatagramSocketSupplier supplier, Class exception) throws IOException { @@ -177,7 +176,7 @@ public class SendReceiveMaxSize { var sendPkt = new DatagramPacket(testData, capacity, addr); if (exception != null) { - Exception ex = expectThrows(IOE, () -> sender.send(sendPkt)); + Exception ex = assertThrows(exception, () -> sender.send(sendPkt)); System.out.println(name + " got expected exception: " + ex); } else { sender.send(sendPkt); @@ -185,8 +184,8 @@ public class SendReceiveMaxSize { receiver.receive(receivePkt); // check packet data has been fragmented and re-assembled correctly at receiver - assertEquals(receivePkt.getLength(), capacity); - assertEquals(receivePkt.getData(), testData); + assertEquals(capacity, receivePkt.getLength()); + assertArrayEquals(testData, receivePkt.getData()); } } } diff --git a/test/jdk/java/net/DatagramSocket/SetGetReceiveBufferSize.java b/test/jdk/java/net/DatagramSocket/SetGetReceiveBufferSize.java index 67c890cd2e2..96fa4d68d2e 100644 --- a/test/jdk/java/net/DatagramSocket/SetGetReceiveBufferSize.java +++ b/test/jdk/java/net/DatagramSocket/SetGetReceiveBufferSize.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2026, Oracle and/or its affiliates. All rights reserved. * 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,21 +25,20 @@ * @test * @bug 4173717 8243488 * @summary Check that setReceiveBufferSize and getReceiveBufferSize work as expected - * @run testng SetGetReceiveBufferSize - * @run testng/othervm -Djava.net.preferIPv4Stack=true SetGetReceiveBufferSize + * @run junit ${test.main.class} + * @run junit/othervm -Djava.net.preferIPv4Stack=true ${test.main.class} */ -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - import java.io.IOException; import java.net.DatagramSocket; import java.net.MulticastSocket; import java.net.SocketException; import java.nio.channels.DatagramChannel; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.expectThrows; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; public class SetGetReceiveBufferSize { static final Class SE = SocketException.class; @@ -51,8 +50,7 @@ public class SetGetReceiveBufferSize { } static DatagramSocketSupplier supplier(DatagramSocketSupplier supplier) { return supplier; } - @DataProvider - public Object[][] invariants() { + public static Object[][] suppliers() { return new Object[][]{ {"DatagramSocket", supplier(() -> new DatagramSocket())}, {"MulticastSocket", supplier(() -> new MulticastSocket())}, @@ -60,39 +58,42 @@ public class SetGetReceiveBufferSize { }; } - @Test(dataProvider = "invariants") + @ParameterizedTest + @MethodSource("suppliers") public void testSetInvalidBufferSize(String name, DatagramSocketSupplier supplier) throws IOException { var invalidArgs = new int[]{ -1, 0 }; try (var socket = supplier.open()) { for (int i : invalidArgs) { - Exception ex = expectThrows(IAE, () -> socket.setReceiveBufferSize(i)); + Exception ex = assertThrows(IAE, () -> socket.setReceiveBufferSize(i)); System.out.println(name + " got expected exception: " + ex); } } } - @Test(dataProvider = "invariants") + @ParameterizedTest + @MethodSource("suppliers") public void testSetAndGetBufferSize(String name, DatagramSocketSupplier supplier) throws IOException { var validArgs = new int[]{ 1234, 2345, 3456 }; try (var socket = supplier.open()) { for (int i : validArgs) { socket.setReceiveBufferSize(i); - assertEquals(socket.getReceiveBufferSize(), i, name); + assertEquals(i, socket.getReceiveBufferSize(), name); } } } - @Test(dataProvider = "invariants") + @ParameterizedTest + @MethodSource("suppliers") public void testSetGetAfterClose(String name, DatagramSocketSupplier supplier) throws IOException { var socket = supplier.open(); socket.close(); - Exception setException = expectThrows(SE, () -> socket.setReceiveBufferSize(2345)); + Exception setException = assertThrows(SE, () -> socket.setReceiveBufferSize(2345)); System.out.println(name + " got expected exception: " + setException); - Exception getException = expectThrows(SE, () -> socket.getReceiveBufferSize()); + Exception getException = assertThrows(SE, () -> socket.getReceiveBufferSize()); System.out.println(name + " got expected exception: " + getException); } } diff --git a/test/jdk/java/net/DatagramSocket/SetGetSendBufferSize.java b/test/jdk/java/net/DatagramSocket/SetGetSendBufferSize.java index 0f6f9af4c60..07ae4bfad59 100644 --- a/test/jdk/java/net/DatagramSocket/SetGetSendBufferSize.java +++ b/test/jdk/java/net/DatagramSocket/SetGetSendBufferSize.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,14 +27,12 @@ * @library /test/lib * @build jdk.test.lib.Platform * @summary Check that setSendBufferSize and getSendBufferSize work as expected - * @run testng SetGetSendBufferSize - * @run testng/othervm -Djava.net.preferIPv4Stack=true SetGetSendBufferSize + * @run junit ${test.main.class} + * @run junit/othervm -Djava.net.preferIPv4Stack=true ${test.main.class} */ import jdk.test.lib.Platform; import jdk.test.lib.net.IPSupport; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import java.io.IOException; import java.net.DatagramSocket; @@ -42,9 +40,11 @@ import java.net.MulticastSocket; import java.net.SocketException; import java.nio.channels.DatagramChannel; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.expectThrows; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; public class SetGetSendBufferSize { static final Class SE = SocketException.class; @@ -55,8 +55,7 @@ public class SetGetSendBufferSize { } static DatagramSocketSupplier supplier(DatagramSocketSupplier supplier) { return supplier; } - @DataProvider - public Object[][] invariants() { + public static Object[][] suppliers() { return new Object[][]{ {"DatagramSocket", supplier(() -> new DatagramSocket())}, {"MulticastSocket", supplier(() -> new MulticastSocket())}, @@ -64,51 +63,55 @@ public class SetGetSendBufferSize { }; } - @Test(dataProvider = "invariants") + @ParameterizedTest + @MethodSource("suppliers") public void testSetInvalidBufferSize(String name, DatagramSocketSupplier supplier) throws IOException { var invalidArgs = new int[]{ -1, 0 }; try (var socket = supplier.open()) { for (int i : invalidArgs) { - Exception ex = expectThrows(IAE, () -> socket.setSendBufferSize(i)); + Exception ex = assertThrows(IAE, () -> socket.setSendBufferSize(i)); System.out.println(name + " got expected exception: " + ex); } } } - @Test(dataProvider = "invariants") + @ParameterizedTest + @MethodSource("suppliers") public void testSetAndGetBufferSize(String name, DatagramSocketSupplier supplier) throws IOException { var validArgs = new int[]{ 2345, 3456 }; try (var socket = supplier.open()) { for (int i : validArgs) { socket.setSendBufferSize(i); - assertEquals(socket.getSendBufferSize(), i, name); + assertEquals(i, socket.getSendBufferSize(), name); } } } - @Test(dataProvider = "invariants") + @ParameterizedTest + @MethodSource("suppliers") public void testInitialSendBufferSize(String name, DatagramSocketSupplier supplier) throws IOException { if (Platform.isOSX()) { try (var socket = supplier.open()){ assertTrue(socket.getSendBufferSize() >= 65507, name); if (IPSupport.hasIPv6() && !IPSupport.preferIPv4Stack()) { - assertEquals(socket.getSendBufferSize(), 65527, name); + assertEquals(65527, socket.getSendBufferSize(), name); } } } } - @Test(dataProvider = "invariants") + @ParameterizedTest + @MethodSource("suppliers") public void testSetGetAfterClose(String name, DatagramSocketSupplier supplier) throws IOException { var socket = supplier.open(); socket.close(); - Exception setException = expectThrows(SE, () -> socket.setSendBufferSize(2345)); + Exception setException = assertThrows(SE, () -> socket.setSendBufferSize(2345)); System.out.println(name + " got expected exception: " + setException); - Exception getException = expectThrows(SE, () -> socket.getSendBufferSize()); + Exception getException = assertThrows(SE, () -> socket.getSendBufferSize()); System.out.println(name + " got expected exception: " + getException); } } diff --git a/test/jdk/java/net/DatagramSocket/SupportedOptionsCheck.java b/test/jdk/java/net/DatagramSocket/SupportedOptionsCheck.java index 9ad381be73c..0186e3e4d46 100644 --- a/test/jdk/java/net/DatagramSocket/SupportedOptionsCheck.java +++ b/test/jdk/java/net/DatagramSocket/SupportedOptionsCheck.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,17 +27,17 @@ * @library /test/lib * @summary checks that the DatagramSocket supportedOptions set contains all * MulticastSocket socket options - * @run testng SupportedOptionsCheck + * @run junit ${test.main.class} */ import jdk.test.lib.Platform; -import org.testng.annotations.Test; import java.net.DatagramSocket; import java.net.StandardSocketOptions; import java.util.Set; -import static org.testng.Assert.assertTrue; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertTrue; public class SupportedOptionsCheck { From ac74e6f9433f1e0ad177e579bde7f2338189d6c6 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Mon, 13 Apr 2026 10:56:38 +0000 Subject: [PATCH 260/359] 8382055: G1: Remove unused unused args in mark_evac_failure_object Reviewed-by: tschatzl --- src/hotspot/share/gc/g1/g1CollectedHeap.cpp | 2 +- src/hotspot/share/gc/g1/g1CollectedHeap.hpp | 2 +- src/hotspot/share/gc/g1/g1ParScanThreadState.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index fe286793ae7..2709e6b3008 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -3219,7 +3219,7 @@ void G1CollectedHeap::retire_gc_alloc_region(G1HeapRegion* alloc_region, G1HeapRegionPrinter::retire(alloc_region); } -void G1CollectedHeap::mark_evac_failure_object(uint worker_id, const oop obj, size_t obj_size) const { +void G1CollectedHeap::mark_evac_failure_object(const oop obj) const { assert(!_cm->is_marked_in_bitmap(obj), "must be"); _cm->raw_mark_in_bitmap(obj); diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp index b5cb9167d92..3a47453819e 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp @@ -1275,7 +1275,7 @@ public: inline bool is_obj_dead_full(const oop obj) const; // Mark the live object that failed evacuation in the bitmap. - void mark_evac_failure_object(uint worker_id, oop obj, size_t obj_size) const; + void mark_evac_failure_object(oop obj) const; G1ConcurrentMark* concurrent_mark() const { return _cm; } diff --git a/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp b/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp index cb857dc6eab..2b0e6ce9cf4 100644 --- a/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp +++ b/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp @@ -650,7 +650,7 @@ oop G1ParScanThreadState::handle_evacuation_failure_par(oop old, markWord m, Kla // Mark the failing object in the marking bitmap and later use the bitmap to handle // evacuation failure recovery. - _g1h->mark_evac_failure_object(_worker_id, old, word_sz); + _g1h->mark_evac_failure_object(old); _evacuation_failed_info.register_copy_failure(word_sz); From 03b46a308ce944b515939db613f5250a5b84b844 Mon Sep 17 00:00:00 2001 From: Daniel Fuchs Date: Mon, 13 Apr 2026 12:44:27 +0000 Subject: [PATCH 261/359] 8381767: Refactor various java/net/*[URL/Http]*/ TestNG tests to use JUnit Reviewed-by: vyazici, myankelevich --- .../whitebox/MaxAgeExpiresDriver.java | 6 +- .../java.base/java/net/MaxAgeExpires.java | 42 ++++---- .../HttpURLConnectionHeadersOrder.java | 54 ++++++----- .../HttpURLProxySelectionTest.java | 55 +++++------ .../HttpURLConnection/Response1xxTest.java | 39 ++++---- .../JarURLConnection/TestDefaultBehavior.java | 95 ++++++++++--------- .../definePackage/SplitPackage.java | 29 +++--- .../net/URLConnection/RequestProperties.java | 48 +++++----- .../URLConnection/SetDefaultUseCaches.java | 31 +++--- .../URLConnectionHeadersOrder.java | 19 ++-- .../jdk/java/net/URLDecoder/EncodingTest.java | 44 +++++---- .../jdk/java/net/URLEncoder/EncodingTest.java | 25 ++--- .../net/URLPermission/EmptyAuthorityTest.java | 26 ++--- .../URLPermission/InvalidCharacterTest.java | 19 ++-- .../URLStreamHandler/TestDefaultBehavior.java | 25 ++--- 15 files changed, 297 insertions(+), 260 deletions(-) diff --git a/test/jdk/java/net/HttpCookie/whitebox/MaxAgeExpiresDriver.java b/test/jdk/java/net/HttpCookie/whitebox/MaxAgeExpiresDriver.java index 7f535fa0c23..c3cc3eddc68 100644 --- a/test/jdk/java/net/HttpCookie/whitebox/MaxAgeExpiresDriver.java +++ b/test/jdk/java/net/HttpCookie/whitebox/MaxAgeExpiresDriver.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * 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,5 @@ * @test * @bug 8351983 * @summary HttpCookie Parser Incorrectly Handles Cookies with Expires Attribute - * @run testng java.base/java.net.MaxAgeExpires + * @run junit java.base/java.net.MaxAgeExpires */ -public class MaxAgeExpiresDriver { -} \ No newline at end of file diff --git a/test/jdk/java/net/HttpCookie/whitebox/java.base/java/net/MaxAgeExpires.java b/test/jdk/java/net/HttpCookie/whitebox/java.base/java/net/MaxAgeExpires.java index 5c4f8f66b3d..6704a290836 100644 --- a/test/jdk/java/net/HttpCookie/whitebox/java.base/java/net/MaxAgeExpires.java +++ b/test/jdk/java/net/HttpCookie/whitebox/java.base/java/net/MaxAgeExpires.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,12 +23,16 @@ package java.net; -import java.time.*; +import java.time.Instant; +import java.time.ZoneId; +import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; -import java.util.*; -import org.testng.Assert; -import org.testng.annotations.Test; -import org.testng.annotations.DataProvider; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import static org.junit.jupiter.api.Assertions.assertEquals; public class MaxAgeExpires { @@ -54,8 +58,7 @@ public class MaxAgeExpires { return zdt.toInstant().getEpochSecond() * 1000; // always exact seconds } - @DataProvider(name = "testData") - public Object[][] testData() { + public static Object[][] testData() { return new Object[][] { // Date string in past. But checking based on current time. {-1L, -1L, -1L, DT1, 0, true}, @@ -79,10 +82,11 @@ public class MaxAgeExpires { {zdtToMillis(zdt1), zdtToMillis(zdt2), -1L, DT3,120, false} }; - }; + } - @Test(dataProvider = "testData") + @ParameterizedTest + @MethodSource("testData") public void test1(long creationInstant, // if -1, then current time is used long expiryCheckInstant, // if -1 then current time is used long maxAge, // if -1, then not included in String @@ -99,7 +103,7 @@ public class MaxAgeExpires { sb.append("; max-age=" + Long.toString(maxAge)); String s = sb.toString(); - System.out.println(s); + System.err.println(s); HttpCookie cookie; if (creationInstant == -1) cookie = HttpCookie.parse(s).get(0); @@ -107,8 +111,8 @@ public class MaxAgeExpires { cookie = HttpCookie.parse(s, false, creationInstant).get(0); if (expectedAge != -1 && cookie.getMaxAge() != expectedAge) { - System.out.println("getMaxAge returned " + cookie.getMaxAge()); - System.out.println("expectedAge was " + expectedAge); + System.err.println("getMaxAge returned " + cookie.getMaxAge()); + System.err.println("expectedAge was " + expectedAge); throw new RuntimeException("Test failed: wrong age"); } @@ -117,9 +121,9 @@ public class MaxAgeExpires { : cookie.hasExpired(expiryCheckInstant); if (expired != hasExpired) { - System.out.println("cookie.hasExpired() returned " + expired); - System.out.println("hasExpired was " + hasExpired); - System.out.println("getMaxAge() returned " + cookie.getMaxAge()); + System.err.println("cookie.hasExpired() returned " + expired); + System.err.println("hasExpired was " + hasExpired); + System.err.println("getMaxAge() returned " + cookie.getMaxAge()); throw new RuntimeException("Test failed: wrong hasExpired"); } } @@ -128,10 +132,10 @@ public class MaxAgeExpires { public void test2() { // Miscellaneous tests that setMaxAge() overrides whatever was set already HttpCookie cookie = HttpCookie.parse("Set-Cookie: name=value; max-age=100").get(0); - Assert.assertEquals(cookie.getMaxAge(), 100); + assertEquals(100, cookie.getMaxAge()); cookie.setMaxAge(200); - Assert.assertEquals(cookie.getMaxAge(), 200); + assertEquals(200, cookie.getMaxAge()); cookie.setMaxAge(-2); - Assert.assertEquals(cookie.getMaxAge(), -2); + assertEquals(-2, cookie.getMaxAge()); } } diff --git a/test/jdk/java/net/HttpURLConnection/HttpURLConnectionHeadersOrder.java b/test/jdk/java/net/HttpURLConnection/HttpURLConnectionHeadersOrder.java index a44eef9c3f5..9a490ce18e7 100644 --- a/test/jdk/java/net/HttpURLConnection/HttpURLConnectionHeadersOrder.java +++ b/test/jdk/java/net/HttpURLConnection/HttpURLConnectionHeadersOrder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * 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,30 +21,36 @@ * questions. */ -/** +/* * @test * @bug 8133686 * @summary Ensuring that multiple header values for a given field-name are returned in * the order they were added for HttpURLConnection.getRequestProperties * and HttpURLConnection.getHeaderFields * @library /test/lib - * @run testng HttpURLConnectionHeadersOrder + * @run junit ${test.main.class} */ import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpHandler; import com.sun.net.httpserver.HttpServer; import jdk.test.lib.net.URIBuilder; -import org.testng.Assert; -import org.testng.annotations.AfterTest; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.Test; import java.io.IOException; -import java.net.*; +import java.net.HttpURLConnection; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.URL; import java.util.Arrays; import java.util.List; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + public class HttpURLConnectionHeadersOrder { private static final String LOCAL_TEST_ENDPOINT = "/headertest"; private static final String ERROR_MESSAGE_TEMPLATE = "Expected Request Properties = %s, Actual Request Properties = %s"; @@ -53,8 +59,8 @@ public class HttpURLConnectionHeadersOrder { private static URL serverUrl; - @BeforeTest - public void beforeTest() throws Exception { + @BeforeAll + public static void beforeTest() throws Exception { SimpleHandler handler = new SimpleHandler(); server = createSimpleHttpServer(handler); serverUrl = URIBuilder.newBuilder() @@ -65,8 +71,8 @@ public class HttpURLConnectionHeadersOrder { .toURL(); } - @AfterTest - public void afterTest() { + @AfterAll + public static void afterTest() { if (server != null) server.stop(0); } @@ -77,9 +83,9 @@ public class HttpURLConnectionHeadersOrder { * - request to a "dummy" server with additional * - custom request properties * - * @throws Exception + * @throws Exception if failed */ - @Test (priority = 1) + @Test public void testRequestPropertiesOrder() throws Exception { final var conn = (HttpURLConnection) serverUrl.openConnection(); @@ -93,8 +99,9 @@ public class HttpURLConnectionHeadersOrder { var customRequestProps = requestProperties.get("test_req_prop"); conn.disconnect(); - Assert.assertNotNull(customRequestProps); - Assert.assertEquals(customRequestProps, EXPECTED_HEADER_VALUES, String.format(ERROR_MESSAGE_TEMPLATE, EXPECTED_HEADER_VALUES.toString(), customRequestProps.toString())); + assertNotNull(customRequestProps); + assertEquals(EXPECTED_HEADER_VALUES, customRequestProps, + "Unexpected value for request header \"test_req_prop\""); } /** @@ -105,7 +112,7 @@ public class HttpURLConnectionHeadersOrder { * * @throws Exception */ - @Test (priority = 2) + @Test public void testServerSideRequestHeadersOrder() throws Exception { final var conn = (HttpURLConnection) serverUrl.openConnection(); conn.addRequestProperty("test_server_handling", "a"); @@ -114,17 +121,19 @@ public class HttpURLConnectionHeadersOrder { int statusCode = conn.getResponseCode(); conn.disconnect(); - Assert.assertEquals(statusCode, 999, "The insertion-order was not preserved on the server-side response headers handling"); + assertEquals(999, statusCode, + "The insertion-order was not preserved on the server-side response headers handling"); } - @Test (priority = 3) + @Test public void testClientSideResponseHeadersOrder() throws Exception { final var conn = (HttpURLConnection) serverUrl.openConnection(); conn.setRequestMethod("GET"); var actualCustomResponseHeaders = conn.getHeaderFields().get("Test_response"); - Assert.assertNotNull(actualCustomResponseHeaders, "Error in reading custom response headers"); - Assert.assertEquals(EXPECTED_HEADER_VALUES, actualCustomResponseHeaders, String.format(ERROR_MESSAGE_TEMPLATE, EXPECTED_HEADER_VALUES.toString(), actualCustomResponseHeaders.toString())); + assertNotNull(actualCustomResponseHeaders, "Error in reading custom response headers"); + assertEquals(EXPECTED_HEADER_VALUES, actualCustomResponseHeaders, + "Unexpected value for response header field \"Test_response\""); } private static HttpServer createSimpleHttpServer(SimpleHandler handler) throws IOException { @@ -153,7 +162,8 @@ public class HttpURLConnectionHeadersOrder { } if (!actualTestRequestHeaders.equals(EXPECTED_HEADER_VALUES)) { - System.out.println("Error: " + String.format(ERROR_MESSAGE_TEMPLATE, EXPECTED_HEADER_VALUES.toString(), actualTestRequestHeaders.toString())); + System.out.printf("Error for \"test_server_handling\" " + + String.format(ERROR_MESSAGE_TEMPLATE, EXPECTED_HEADER_VALUES, actualTestRequestHeaders)); return -1; } return 999; diff --git a/test/jdk/java/net/HttpURLConnection/HttpURLProxySelectionTest.java b/test/jdk/java/net/HttpURLConnection/HttpURLProxySelectionTest.java index a6f2fbc1ae6..be922608c80 100644 --- a/test/jdk/java/net/HttpURLConnection/HttpURLProxySelectionTest.java +++ b/test/jdk/java/net/HttpURLConnection/HttpURLProxySelectionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,10 +25,6 @@ import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpHandler; import com.sun.net.httpserver.HttpServer; import jdk.test.lib.net.URIBuilder; -import org.testng.Assert; -import org.testng.annotations.AfterTest; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.Test; import sun.net.spi.DefaultProxySelector; import java.io.IOException; @@ -42,35 +38,43 @@ import java.net.URISyntaxException; import java.net.URL; import java.util.List; -/** +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/* * @test * @bug 6563286 6797318 8177648 8230220 * @summary Tests that sun.net.www.protocol.http.HttpURLConnection when dealing with * sun.net.spi.DefaultProxySelector#select() handles any IllegalArgumentException * correctly * @library /test/lib - * @run testng HttpURLProxySelectionTest + * @run junit ${test.main.class} * @modules java.base/sun.net.spi:+open */ public class HttpURLProxySelectionTest { private static final String WEB_APP_CONTEXT = "/httpurlproxytest"; - private HttpServer server; - private SimpleHandler handler; - private ProxySelector previousDefault; - private CustomProxySelector ourProxySelector = new CustomProxySelector(); + private static HttpServer server; + private static SimpleHandler handler; + private static ProxySelector previousDefault; + private static final CustomProxySelector ourProxySelector = new CustomProxySelector(); - @BeforeTest - public void beforeTest() throws Exception { + @BeforeAll + public static void beforeTest() throws Exception { previousDefault = ProxySelector.getDefault(); ProxySelector.setDefault(ourProxySelector); handler = new SimpleHandler(); server = createServer(handler); } - @AfterTest - public void afterTest() { + @AfterAll + public static void afterTest() { try { if (server != null) { final int delaySeconds = 0; @@ -86,7 +90,7 @@ public class HttpURLProxySelectionTest { * - Server receives request and sends a 301 redirect to an URI which doesn't have a "host" * - Redirect is expected to fail with IOException (caused by IllegalArgumentException from DefaultProxySelector) * - * @throws Exception + * @throws Exception if failed */ @Test public void test() throws Exception { @@ -98,19 +102,16 @@ public class HttpURLProxySelectionTest { .toURL(); System.out.println("Sending request to " + targetURL); final HttpURLConnection conn = (HttpURLConnection) targetURL.openConnection(); - try { - conn.getResponseCode(); - Assert.fail("Request to " + targetURL + " was expected to fail during redirect"); - } catch (IOException ioe) { - // expected because of the redirect to an invalid URL, for which a proxy can't be selected + // expected because of the redirect to an invalid URL, for which a proxy can't be selected + IOException ioe = assertThrows(IOException.class, conn::getResponseCode, + "Request to " + targetURL + " was expected to fail during redirect"); - // make sure the it was indeed a redirect - Assert.assertTrue(handler.redirectSent, "Server was expected to send a redirect, but didn't"); - Assert.assertTrue(ourProxySelector.selectorUsedForRedirect, "Proxy selector wasn't used for redirect"); + // make sure the IOException was indeed a redirect + assertTrue(handler.redirectSent, "Server was expected to send a redirect, but didn't"); + assertTrue(ourProxySelector.selectorUsedForRedirect, "Proxy selector wasn't used for redirect"); - // make sure the IOException was caused by an IllegalArgumentException - Assert.assertTrue(ioe.getCause() instanceof IllegalArgumentException, "Unexpected cause in the IOException"); - } + // make sure the IOException was caused by an IllegalArgumentException + assertInstanceOf(IllegalArgumentException.class, ioe.getCause(), "Unexpected cause in the IOException"); } diff --git a/test/jdk/java/net/HttpURLConnection/Response1xxTest.java b/test/jdk/java/net/HttpURLConnection/Response1xxTest.java index 2be9772ed29..bdda7821bf8 100644 --- a/test/jdk/java/net/HttpURLConnection/Response1xxTest.java +++ b/test/jdk/java/net/HttpURLConnection/Response1xxTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved. * 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,28 +33,31 @@ import java.net.URI; import java.nio.charset.StandardCharsets; import jdk.test.lib.net.URIBuilder; -import org.testng.Assert; -import org.testng.annotations.AfterClass; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.Test; -/** +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +/* * @test * @bug 8170305 * @summary Tests behaviour of HttpURLConnection when server responds with 1xx interim response status codes * @library /test/lib - * @run testng Response1xxTest + * @run junit ${test.main.class} */ public class Response1xxTest { private static final String EXPECTED_RSP_BODY = "Hello World"; - private ServerSocket serverSocket; - private Http11Server server; - private String requestURIBase; + private static ServerSocket serverSocket; + private static Http11Server server; + private static String requestURIBase; - @BeforeClass - public void setup() throws Exception { + @BeforeAll + public static void setup() throws Exception { serverSocket = new ServerSocket(0, 0, InetAddress.getLoopbackAddress()); server = new Http11Server(serverSocket); new Thread(server).start(); @@ -62,8 +65,8 @@ public class Response1xxTest { .port(serverSocket.getLocalPort()).build().toString(); } - @AfterClass - public void teardown() throws Exception { + @AfterAll + public static void teardown() throws Exception { if (server != null) { server.stop = true; System.out.println("(HTTP 1.1) Server stop requested"); @@ -166,7 +169,7 @@ public class Response1xxTest { static String readRequestLine(final Socket sock) throws IOException { final InputStream is = sock.getInputStream(); - final StringBuilder sb = new StringBuilder(""); + final StringBuilder sb = new StringBuilder(); byte[] buf = new byte[1024]; while (!sb.toString().endsWith("\r\n\r\n")) { final int numRead = is.read(buf); @@ -203,13 +206,13 @@ public class Response1xxTest { System.out.println("Issuing request to " + requestURI); final HttpURLConnection urlConnection = (HttpURLConnection) requestURI.toURL().openConnection(); final int responseCode = urlConnection.getResponseCode(); - Assert.assertEquals(responseCode, 200, "Unexpected response code"); + assertEquals(200, responseCode, "Unexpected response code"); final String body; try (final InputStream is = urlConnection.getInputStream()) { final byte[] bytes = is.readAllBytes(); body = new String(bytes, StandardCharsets.UTF_8); } - Assert.assertEquals(body, EXPECTED_RSP_BODY, "Unexpected response body"); + assertEquals(EXPECTED_RSP_BODY, body, "Unexpected response body"); } } @@ -223,6 +226,6 @@ public class Response1xxTest { System.out.println("Issuing request to " + requestURI); final HttpURLConnection urlConnection = (HttpURLConnection) requestURI.toURL().openConnection(); // we expect the request to fail because the server unexpectedly sends a 101 response - Assert.assertThrows(ProtocolException.class, () -> urlConnection.getResponseCode()); + assertThrows(ProtocolException.class, urlConnection::getResponseCode); } } diff --git a/test/jdk/java/net/JarURLConnection/TestDefaultBehavior.java b/test/jdk/java/net/JarURLConnection/TestDefaultBehavior.java index 69b6c588af8..6a0173ac692 100644 --- a/test/jdk/java/net/JarURLConnection/TestDefaultBehavior.java +++ b/test/jdk/java/net/JarURLConnection/TestDefaultBehavior.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * 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 8225037 * @library /test/lib * @summary Basic test for java.net.JarURLConnection default behavior - * @run testng/othervm TestDefaultBehavior + * @run junit/othervm ${test.main.class} */ import java.io.IOException; @@ -39,10 +39,13 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.jar.JarFile; import jdk.test.lib.util.JarUtils; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.Test; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertNotNull; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; public class TestDefaultBehavior { @@ -50,8 +53,8 @@ public class TestDefaultBehavior { // 1. jar without a manifest // 2. jar with a manifest // 3. jar with manifest that includes an entry attribute - @BeforeTest - public void setup() throws Exception { + @BeforeAll + public static void setup() throws Exception { URLConnection.setDefaultUseCaches("jar", false); URLConnection.setDefaultUseCaches("file", false); @@ -76,14 +79,14 @@ public class TestDefaultBehavior { URL jarFileURL = URI.create("jar:" + fileURI + "!/").toURL(); JarURLConnection jarURLConnection = new CustomJarURLConnection(jarFileURL); - assertEquals(jarURLConnection.getAttributes(), null); - assertEquals(jarURLConnection.getCertificates(), null); - assertEquals(jarURLConnection.getEntryName(), null); - assertEquals(jarURLConnection.getJarEntry(), null); + assertNull(jarURLConnection.getAttributes()); + assertNull(jarURLConnection.getCertificates()); + assertNull(jarURLConnection.getEntryName()); + assertNull(jarURLConnection.getJarEntry()); assertNotNull(jarURLConnection.getJarFile()); - assertEquals(jarURLConnection.getJarFileURL(), fileURI.toURL()); - assertEquals(jarURLConnection.getMainAttributes(), null); - assertEquals(jarURLConnection.getManifest(), null); + assertEquals(fileURI.toURL(), jarURLConnection.getJarFileURL()); + assertNull(jarURLConnection.getMainAttributes()); + assertNull(jarURLConnection.getManifest()); } @Test @@ -92,14 +95,14 @@ public class TestDefaultBehavior { URL jarFileURL = URI.create("jar:" + fileURI + "!/foo.txt").toURL(); JarURLConnection jarURLConnection = new CustomJarURLConnection(jarFileURL); - assertEquals(jarURLConnection.getAttributes(), null); - assertEquals(jarURLConnection.getCertificates(), null); - assertEquals(jarURLConnection.getEntryName(), "foo.txt"); - assertEquals(jarURLConnection.getJarEntry().getName(), "foo.txt"); + assertNull(jarURLConnection.getAttributes()); + assertNull(jarURLConnection.getCertificates()); + assertEquals("foo.txt", jarURLConnection.getEntryName()); + assertEquals("foo.txt", jarURLConnection.getJarEntry().getName()); assertNotNull(jarURLConnection.getJarFile()); - assertEquals(jarURLConnection.getJarFileURL(), fileURI.toURL()); - assertEquals(jarURLConnection.getMainAttributes(), null); - assertEquals(jarURLConnection.getManifest(), null); + assertEquals(fileURI.toURL(), jarURLConnection.getJarFileURL()); + assertNull(jarURLConnection.getMainAttributes()); + assertNull(jarURLConnection.getManifest()); } @Test @@ -108,13 +111,13 @@ public class TestDefaultBehavior { URL jarFileURL = URI.create("jar:" + fileURI + "!/").toURL(); JarURLConnection jarURLConnection = new CustomJarURLConnection(jarFileURL); - assertEquals(jarURLConnection.getAttributes(), null); - assertEquals(jarURLConnection.getCertificates(), null); - assertEquals(jarURLConnection.getEntryName(), null); - assertEquals(jarURLConnection.getJarEntry(), null); + assertNull(jarURLConnection.getAttributes()); + assertNull(jarURLConnection.getCertificates()); + assertNull(jarURLConnection.getEntryName()); + assertNull(jarURLConnection.getJarEntry()); assertNotNull(jarURLConnection.getJarFile()); - assertEquals(jarURLConnection.getJarFileURL(), fileURI.toURL()); - assertEquals(jarURLConnection.getMainAttributes().getValue("Manifest-Version"), "5.5"); + assertEquals(fileURI.toURL(), jarURLConnection.getJarFileURL()); + assertEquals("5.5", jarURLConnection.getMainAttributes().getValue("Manifest-Version")); assertNotNull(jarURLConnection.getManifest()); } @@ -124,13 +127,13 @@ public class TestDefaultBehavior { URL jarFileURL = URI.create("jar:" + fileURI + "!/foo.txt").toURL(); JarURLConnection jarURLConnection = new CustomJarURLConnection(jarFileURL); - assertEquals(jarURLConnection.getAttributes(), null); - assertEquals(jarURLConnection.getCertificates(), null); - assertEquals(jarURLConnection.getEntryName(), "foo.txt"); - assertEquals(jarURLConnection.getJarEntry().getName(), "foo.txt"); + assertNull(jarURLConnection.getAttributes()); + assertNull(jarURLConnection.getCertificates()); + assertEquals("foo.txt", jarURLConnection.getEntryName()); + assertEquals("foo.txt", jarURLConnection.getJarEntry().getName()); assertNotNull(jarURLConnection.getJarFile()); - assertEquals(jarURLConnection.getJarFileURL(), fileURI.toURL()); - assertEquals(jarURLConnection.getMainAttributes().getValue("Manifest-Version"), "5.5"); + assertEquals(fileURI.toURL(), jarURLConnection.getJarFileURL()); + assertEquals("5.5", jarURLConnection.getMainAttributes().getValue("Manifest-Version")); assertNotNull(jarURLConnection.getManifest()); } @@ -140,13 +143,13 @@ public class TestDefaultBehavior { URL jarFileURL = URI.create("jar:" + fileURI + "!/").toURL(); JarURLConnection jarURLConnection = new CustomJarURLConnection(jarFileURL); - assertEquals(jarURLConnection.getAttributes(), null); - assertEquals(jarURLConnection.getCertificates(), null); - assertEquals(jarURLConnection.getEntryName(), null); - assertEquals(jarURLConnection.getJarEntry(), null); + assertNull(jarURLConnection.getAttributes()); + assertNull(jarURLConnection.getCertificates()); + assertNull(jarURLConnection.getEntryName()); + assertNull(jarURLConnection.getJarEntry()); assertNotNull(jarURLConnection.getJarFile()); - assertEquals(jarURLConnection.getJarFileURL(), fileURI.toURL()); - assertEquals(jarURLConnection.getMainAttributes().getValue("Manifest-Version"), "7.7"); + assertEquals(fileURI.toURL(), jarURLConnection.getJarFileURL()); + assertEquals("7.7", jarURLConnection.getMainAttributes().getValue("Manifest-Version")); assertNotNull(jarURLConnection.getManifest()); } @@ -156,13 +159,13 @@ public class TestDefaultBehavior { URL jarFileURL = URI.create("jar:" + fileURI + "!/foo.txt").toURL(); JarURLConnection jarURLConnection = new CustomJarURLConnection(jarFileURL); - assertEquals(jarURLConnection.getAttributes().getValue("Greeting"), "true"); - assertEquals(jarURLConnection.getCertificates(), null); - assertEquals(jarURLConnection.getEntryName(), "foo.txt"); - assertEquals(jarURLConnection.getJarEntry().getName(), "foo.txt"); + assertEquals("true", jarURLConnection.getAttributes().getValue("Greeting")); + assertNull(jarURLConnection.getCertificates()); + assertEquals("foo.txt", jarURLConnection.getEntryName()); + assertEquals("foo.txt", jarURLConnection.getJarEntry().getName()); assertNotNull(jarURLConnection.getJarFile()); - assertEquals(jarURLConnection.getJarFileURL(), fileURI.toURL()); - assertEquals(jarURLConnection.getMainAttributes().getValue("Manifest-Version"), "7.7"); + assertEquals(fileURI.toURL(), jarURLConnection.getJarFileURL()); + assertEquals("7.7", jarURLConnection.getMainAttributes().getValue("Manifest-Version")); assertNotNull(jarURLConnection.getManifest()); } diff --git a/test/jdk/java/net/URLClassLoader/definePackage/SplitPackage.java b/test/jdk/java/net/URLClassLoader/definePackage/SplitPackage.java index e8698dddf6b..47e32b39a4b 100644 --- a/test/jdk/java/net/URLClassLoader/definePackage/SplitPackage.java +++ b/test/jdk/java/net/URLClassLoader/definePackage/SplitPackage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,7 @@ * @library /test/lib * @build jdk.test.lib.compiler.CompilerUtils * @modules jdk.compiler - * @run testng SplitPackage + * @run junit ${test.main.class} */ import java.net.URL; @@ -40,17 +40,21 @@ import java.nio.file.StandardCopyOption; import java.util.jar.Manifest; import jdk.test.lib.compiler.CompilerUtils; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.Test; -import static org.testng.Assert.*; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotSame; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; public class SplitPackage { private static final Path SRC_DIR = Paths.get(System.getProperty("test.src", ".")); private static final Path FOO_DIR = Paths.get("foo"); private static final Path BAR_DIR = Paths.get("bar"); - @BeforeTest - private void setup() throws Exception { + @BeforeAll + public static void setup() throws Exception { Files.createDirectory(BAR_DIR); Path pkgDir = Paths.get("p"); @@ -80,14 +84,11 @@ public class SplitPackage { Package pForFoo = loader1.getDefinedPackage("p"); Package pForBar = loader2.getDefinedPackage("p"); - assertEquals(pForFoo.getName(), pForBar.getName()); - assertTrue(pForFoo != pForBar); + assertEquals(pForBar.getName(), pForFoo.getName()); + assertNotSame(pForBar, pForFoo); - try { - loader2.defineSplitPackage("p"); - } catch (IllegalArgumentException e) { - - } + assertThrows(IllegalArgumentException.class, + () -> loader2.defineSplitPackage("p")); } static class Loader extends URLClassLoader { diff --git a/test/jdk/java/net/URLConnection/RequestProperties.java b/test/jdk/java/net/URLConnection/RequestProperties.java index d052f1aeaf2..84206d89868 100644 --- a/test/jdk/java/net/URLConnection/RequestProperties.java +++ b/test/jdk/java/net/URLConnection/RequestProperties.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * 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,17 +21,14 @@ * questions. */ -/** +/* * @test * @bug 4485208 8252767 * @summary Validate various request property methods on java.net.URLConnection * throw NullPointerException and IllegalStateException when expected - * @run testng RequestProperties + * @run junit ${test.main.class} */ -import org.testng.Assert; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import java.io.IOException; import java.net.URL; @@ -40,13 +37,19 @@ import java.nio.file.Path; import java.util.ArrayList; import java.util.List; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + public class RequestProperties { private static final Class NPE = NullPointerException.class; private static final Class ISE = IllegalStateException.class; - @DataProvider(name = "urls") - private Object[][] urls() { + private static List urls() { final List urls = new ArrayList<>(); urls.add("http://foo.com/bar/"); urls.add("jar:http://foo.com/bar.html!/foo/bar"); @@ -54,11 +57,7 @@ public class RequestProperties { if (hasFtp()) { urls.add("ftp://foo:bar@foobar.com/etc/passwd"); } - final Object[][] data = new Object[urls.size()][1]; - for (int i = 0; i < urls.size(); i++) { - data[i][0] = urls.get(i); - } - return data; + return List.copyOf(urls); } @@ -66,10 +65,11 @@ public class RequestProperties { * Test that {@link java.net.URLConnection#setRequestProperty(String, String)} throws * a {@link NullPointerException} when passed null key */ - @Test(dataProvider = "urls") + @ParameterizedTest + @MethodSource("urls") public void testSetRequestPropertyNullPointerException(final String url) throws Exception { final URLConnection conn = new URL(url).openConnection(); - Assert.assertThrows(NPE, () -> conn.setRequestProperty(null, "bar")); + assertThrows(NPE, () -> conn.setRequestProperty(null, "bar")); // expected to pass conn.setRequestProperty("key", null); } @@ -78,10 +78,11 @@ public class RequestProperties { * Test that {@link java.net.URLConnection#addRequestProperty(String, String)} throws * a {@link NullPointerException} when passed null key */ - @Test(dataProvider = "urls") + @ParameterizedTest + @MethodSource("urls") public void testAddRequestPropertyNullPointerException(final String url) throws Exception { final URLConnection conn = new URL(url).openConnection(); - Assert.assertThrows(NPE, () -> conn.addRequestProperty(null, "hello")); + assertThrows(NPE, () -> conn.addRequestProperty(null, "hello")); // expected to pass conn.addRequestProperty("key", null); } @@ -90,10 +91,11 @@ public class RequestProperties { * Test that {@link java.net.URLConnection#getRequestProperty(String)} returns * null when the passed key is null */ - @Test(dataProvider = "urls") + @ParameterizedTest + @MethodSource("urls") public void testGetRequestPropertyReturnsNull(final String url) throws Exception { final URLConnection conn = new URL(url).openConnection(); - Assert.assertNull(conn.getRequestProperty(null), + assertNull(conn.getRequestProperty(null), "getRequestProperty was expected to return null for null key"); } @@ -105,7 +107,7 @@ public class RequestProperties { public void testSetRequestPropertyIllegalStateException() throws Exception { final URLConnection conn = createAndConnectURLConnection(); try { - Assert.assertThrows(ISE, () -> conn.setRequestProperty("foo", "bar")); + assertThrows(ISE, () -> conn.setRequestProperty("foo", "bar")); } finally { safeClose(conn); } @@ -119,7 +121,7 @@ public class RequestProperties { public void testAddRequestPropertyIllegalStateException() throws Exception { final URLConnection conn = createAndConnectURLConnection(); try { - Assert.assertThrows(ISE, () -> conn.addRequestProperty("foo", "bar")); + assertThrows(ISE, () -> conn.addRequestProperty("foo", "bar")); } finally { safeClose(conn); } @@ -133,7 +135,7 @@ public class RequestProperties { public void testGetRequestPropertyIllegalStateException() throws Exception { final URLConnection conn = createAndConnectURLConnection(); try { - Assert.assertThrows(ISE, () -> conn.getRequestProperty("hello")); + assertThrows(ISE, () -> conn.getRequestProperty("hello")); } finally { safeClose(conn); } @@ -147,7 +149,7 @@ public class RequestProperties { public void testGetRequestPropertiesIllegalStateException() throws Exception { final URLConnection conn = createAndConnectURLConnection(); try { - Assert.assertThrows(ISE, () -> conn.getRequestProperties()); + assertThrows(ISE, () -> conn.getRequestProperties()); } finally { safeClose(conn); } diff --git a/test/jdk/java/net/URLConnection/SetDefaultUseCaches.java b/test/jdk/java/net/URLConnection/SetDefaultUseCaches.java index 73c822ac2c9..224e5217d33 100644 --- a/test/jdk/java/net/URLConnection/SetDefaultUseCaches.java +++ b/test/jdk/java/net/URLConnection/SetDefaultUseCaches.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * 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,15 +24,18 @@ /* @test * @bug 8163449 8175261 * @summary Allow per protocol setting for URLConnection defaultUseCaches - * @run testng/othervm SetDefaultUseCaches + * @run junit/othervm ${test.main.class} */ import java.io.IOException; import java.io.UncheckedIOException; import java.net.URL; import java.net.URLConnection; -import org.testng.annotations.Test; -import static org.testng.Assert.*; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; public class SetDefaultUseCaches { @@ -85,28 +88,28 @@ public class SetDefaultUseCaches { void checkJAR(boolean defaultValue) throws IOException { URLConnection.setDefaultUseCaches("JAR", defaultValue); - assertEquals(URLConnection.getDefaultUseCaches("JAr"), defaultValue); + assertEquals(defaultValue, URLConnection.getDefaultUseCaches("JAr")); URLConnection jarFileURLConn = jarFileURL.openConnection(); URLConnection jarHttpURLConn = jarHttpURL.openConnection(); - assertEquals(jarFileURLConn.getUseCaches(), defaultValue); - assertEquals(jarHttpURLConn.getUseCaches(), defaultValue); + assertEquals(defaultValue, jarFileURLConn.getUseCaches()); + assertEquals(defaultValue, jarHttpURLConn.getUseCaches()); jarFileURLConn.setUseCaches(!defaultValue); jarHttpURLConn.setUseCaches(!defaultValue); - assertEquals(jarFileURLConn.getUseCaches(), !defaultValue); - assertEquals(jarHttpURLConn.getUseCaches(), !defaultValue); + assertEquals(!defaultValue, jarFileURLConn.getUseCaches()); + assertEquals(!defaultValue, jarHttpURLConn.getUseCaches()); URLConnection.setDefaultUseCaches("JaR", !defaultValue); // case-insensitive - assertEquals(URLConnection.getDefaultUseCaches("jAR"), !defaultValue); + assertEquals(!defaultValue, URLConnection.getDefaultUseCaches("jAR")); jarFileURLConn = jarFileURL.openConnection(); jarHttpURLConn = jarHttpURL.openConnection(); - assertEquals(jarFileURLConn.getUseCaches(), !defaultValue); - assertEquals(jarHttpURLConn.getUseCaches(), !defaultValue); + assertEquals(!defaultValue, jarFileURLConn.getUseCaches()); + assertEquals(!defaultValue, jarHttpURLConn.getUseCaches()); jarFileURLConn.setUseCaches(defaultValue); jarHttpURLConn.setUseCaches(defaultValue); - assertEquals(jarFileURLConn.getUseCaches(), defaultValue); - assertEquals(jarHttpURLConn.getUseCaches(), defaultValue); + assertEquals(defaultValue, jarFileURLConn.getUseCaches()); + assertEquals(defaultValue, jarHttpURLConn.getUseCaches()); } static URL uncheckURL(String url) { diff --git a/test/jdk/java/net/URLConnection/URLConnectionHeadersOrder.java b/test/jdk/java/net/URLConnection/URLConnectionHeadersOrder.java index 6f16c79f520..5f680a04283 100644 --- a/test/jdk/java/net/URLConnection/URLConnectionHeadersOrder.java +++ b/test/jdk/java/net/URLConnection/URLConnectionHeadersOrder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * 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,19 +21,17 @@ * questions. */ -/** +/* * @test * @bug 8133686 * @summary Ensuring that multiple header values for a given field-name are returned in * the order they were added for HttpURLConnection.getRequestProperties * and HttpURLConnection.getHeaderFields * @library /test/lib - * @run testng URLConnectionHeadersOrder + * @run junit ${test.main.class} */ import jdk.test.lib.net.URIBuilder; -import org.testng.Assert; -import org.testng.annotations.Test; import java.io.IOException; import java.net.InetAddress; @@ -41,6 +39,11 @@ import java.net.URL; import java.net.URLConnection; import java.util.Arrays; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + public class URLConnectionHeadersOrder { @Test public void testRequestPropertiesOrder() throws Exception { @@ -58,10 +61,10 @@ public class URLConnectionHeadersOrder { var expectedRequestProps = Arrays.asList("a", "b", "c"); var actualRequestProps = conn.getRequestProperties().get("test"); - Assert.assertNotNull(actualRequestProps); + assertNotNull(actualRequestProps); - String errorMessageTemplate = "Expected Request Properties = %s, Actual Request Properties = %s"; - Assert.assertEquals(actualRequestProps, expectedRequestProps, String.format(errorMessageTemplate, expectedRequestProps.toString(), actualRequestProps.toString())); + assertEquals(expectedRequestProps, actualRequestProps, + "Unexpected value for request header \"test\""); } } diff --git a/test/jdk/java/net/URLDecoder/EncodingTest.java b/test/jdk/java/net/URLDecoder/EncodingTest.java index b01be15a446..c49720545ed 100644 --- a/test/jdk/java/net/URLDecoder/EncodingTest.java +++ b/test/jdk/java/net/URLDecoder/EncodingTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * 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,16 +24,20 @@ import java.net.URLDecoder; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; -import org.testng.Assert; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; -/** +import org.junit.jupiter.api.function.Executable; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +/* * @test * @bug 8183743 * @summary Test to verify the new overload method with Charset functions the * same as the existing method that takes a charset name. - * @run testng EncodingTest + * @run junit ${test.main.class} */ public class EncodingTest { public static enum ParameterType { @@ -41,16 +45,14 @@ public class EncodingTest { CHARSET } - @DataProvider(name = "illegalArgument") - public Object[][] getParameters() { + public static Object[][] getParameters() { return new Object[][]{ {ParameterType.STRING}, {ParameterType.CHARSET} }; } - @DataProvider(name = "decode") - public Object[][] getDecodeParameters() { + public static Object[][] getDecodeParameters() { return new Object[][]{ {"The string \u00FC@foo-bar"}, // the string from javadoc example @@ -82,17 +84,16 @@ public class EncodingTest { * @param type the type of the argument, e.g a String charset name or * charset */ - @Test(dataProvider = "illegalArgument", expectedExceptions = IllegalArgumentException.class) + @ParameterizedTest + @MethodSource("getParameters") public void testIllegalArgument(ParameterType type) throws Exception { String encoded = URLEncoder.encode("http://www.xyz.com/find?key=\u0100\u0101", StandardCharsets.UTF_8.name()); String illegal = "%" + encoded; - String returned; - if (type == ParameterType.STRING) { - returned = URLDecoder.decode(illegal, StandardCharsets.UTF_8.name()); - } else { - returned = URLDecoder.decode(illegal, StandardCharsets.UTF_8); - } + Executable decoded = type == ParameterType.STRING + ? () -> URLDecoder.decode(illegal, StandardCharsets.UTF_8.name()) + : () -> URLDecoder.decode(illegal, StandardCharsets.UTF_8); + assertThrows(IllegalArgumentException.class, decoded); } /** @@ -101,17 +102,18 @@ public class EncodingTest { * * @param s the string to be encoded and then decoded with both existing * and the overload methods. - * @throws Exception + * @throws Exception if failed */ - @Test(dataProvider = "decode") + @ParameterizedTest + @MethodSource("getDecodeParameters") public void decode(String s) throws Exception { String encoded = URLEncoder.encode(s, StandardCharsets.UTF_8.name()); String returned1 = URLDecoder.decode(encoded, StandardCharsets.UTF_8.name()); String returned2 = URLDecoder.decode(encoded, StandardCharsets.UTF_8); - Assert.assertEquals(returned1, returned2); + assertEquals(returned2, returned1); } - String charactersRange(char c1, char c2) { + private static String charactersRange(char c1, char c2) { StringBuilder sb = new StringBuilder(c2 - c1); for (char c = c1; c < c2; c++) { sb.append(c); diff --git a/test/jdk/java/net/URLEncoder/EncodingTest.java b/test/jdk/java/net/URLEncoder/EncodingTest.java index f1b4f3ce3e9..f992fb4e8ee 100644 --- a/test/jdk/java/net/URLEncoder/EncodingTest.java +++ b/test/jdk/java/net/URLEncoder/EncodingTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * 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,16 +24,17 @@ import java.net.URLDecoder; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; -import org.testng.Assert; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; -/** +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import static org.junit.jupiter.api.Assertions.assertEquals; + +/* * @test * @bug 8183743 * @summary Test to verify the new overload method with Charset functions the same * as the existing method that takes a charset name. - * @run testng EncodingTest + * @run junit ${test.main.class} */ public class EncodingTest { public static enum ParameterType { @@ -41,8 +42,7 @@ public class EncodingTest { CHARSET } - @DataProvider(name = "encode") - public Object[][] getDecodeParameters() { + public static Object[][] getDecodeParameters() { return new Object[][]{ {"The string \u00FC@foo-bar"}, // the string from javadoc example @@ -74,19 +74,20 @@ public class EncodingTest { * @param s the string to be encoded * @throws Exception if the test fails */ - @Test(dataProvider = "encode") + @ParameterizedTest + @MethodSource("getDecodeParameters") public void encode(String s) throws Exception { String encoded1 = URLEncoder.encode(s, StandardCharsets.UTF_8.name()); String encoded2 = URLEncoder.encode(s, StandardCharsets.UTF_8); - Assert.assertEquals(encoded1, encoded2); + assertEquals(encoded2, encoded1); // cross check String returned1 = URLDecoder.decode(encoded1, StandardCharsets.UTF_8.name()); String returned2 = URLDecoder.decode(encoded2, StandardCharsets.UTF_8); - Assert.assertEquals(returned1, returned2); + assertEquals(returned2, returned1); } - String charactersRange(char c1, char c2) { + private static String charactersRange(char c1, char c2) { StringBuilder sb = new StringBuilder(c2 - c1); for (char c = c1; c < c2; c++) { sb.append(c); diff --git a/test/jdk/java/net/URLPermission/EmptyAuthorityTest.java b/test/jdk/java/net/URLPermission/EmptyAuthorityTest.java index 06dd21b71ea..9dce36dbb27 100644 --- a/test/jdk/java/net/URLPermission/EmptyAuthorityTest.java +++ b/test/jdk/java/net/URLPermission/EmptyAuthorityTest.java @@ -1,5 +1,5 @@ /* -* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. +* Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,18 +25,19 @@ * @test * @bug 8367049 * @summary URLPermission must reject empty/missing host authority with IAE (no SIOOBE) -* @run testng EmptyAuthorityTest +* @run junit ${test.main.class} */ import java.net.URLPermission; -import org.testng.Assert; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import static org.junit.jupiter.api.Assertions.assertThrows; public class EmptyAuthorityTest { - @DataProvider(name = "badUrls") - public Object[][] badUrls() { + public static Object[][] badUrls() { return new Object[][]{ { "http:///path" }, // empty authority { "https:///x" }, // empty authority @@ -46,8 +47,7 @@ public class EmptyAuthorityTest { }; } - @DataProvider(name = "goodUrls") - public Object[][] goodUrls() { + public static Object[][] goodUrls() { return new Object[][]{ { "http://example.com/x" }, { "http://example.com:80/x" }, @@ -56,12 +56,14 @@ public class EmptyAuthorityTest { }; } - @Test(dataProvider = "badUrls") + @ParameterizedTest + @MethodSource("badUrls") public void rejectsEmptyOrMalformedAuthority(String url) { - Assert.expectThrows(IllegalArgumentException.class, () -> new URLPermission(url)); + assertThrows(IllegalArgumentException.class, () -> new URLPermission(url)); } - @Test(dataProvider = "goodUrls") + @ParameterizedTest + @MethodSource("goodUrls") public void acceptsValidAuthorities(String url) { new URLPermission(url); // should not throw } diff --git a/test/jdk/java/net/URLPermission/InvalidCharacterTest.java b/test/jdk/java/net/URLPermission/InvalidCharacterTest.java index 37179f5dfe2..ae49353df0f 100644 --- a/test/jdk/java/net/URLPermission/InvalidCharacterTest.java +++ b/test/jdk/java/net/URLPermission/InvalidCharacterTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved. * 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,15 +23,18 @@ import java.net.URLPermission; -import org.testng.Assert; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; -/** +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/* * @test * @bug 8297311 * @summary Verify that the exception thrown by URLPermission class, for invalid host name, * contains expected exception message - * @run testng InvalidCharacterTest + * @run junit InvalidCharacterTest */ public class InvalidCharacterTest { @@ -45,13 +48,13 @@ public class InvalidCharacterTest { // we expect this string in the exception message final String expectedStringInMessage = String.format("\\u%04x", (int) invalidChar); final String url = "http://foo" + invalidChar + "bar.com:12345"; - final IllegalArgumentException iae = Assert.expectThrows(IllegalArgumentException.class, + final IllegalArgumentException iae = assertThrows(IllegalArgumentException.class, () -> new URLPermission(url)); // additionally check the error message contains the invalid char final String exMessage = iae.getMessage(); System.out.println("Got exception message: " + exMessage); - Assert.assertNotNull(exMessage, "Exception message is null"); - Assert.assertTrue(exMessage.contains(expectedStringInMessage), + assertNotNull(exMessage, "Exception message is null"); + assertTrue(exMessage.contains(expectedStringInMessage), expectedStringInMessage + " missing from exception message: " + exMessage); } } diff --git a/test/jdk/java/net/URLStreamHandler/TestDefaultBehavior.java b/test/jdk/java/net/URLStreamHandler/TestDefaultBehavior.java index 9fe4eff4150..ed01791acdd 100644 --- a/test/jdk/java/net/URLStreamHandler/TestDefaultBehavior.java +++ b/test/jdk/java/net/URLStreamHandler/TestDefaultBehavior.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,7 @@ * @test * @bug 8224973 * @summary Basic test for the default behavior of openConnection(URL,Proxy) - * @run testng TestDefaultBehavior + * @run junit ${test.main.class} */ import java.io.IOException; @@ -35,9 +35,10 @@ import java.net.URI; import java.net.URL; import java.net.URLConnection; import java.net.URLStreamHandler; -import org.testng.annotations.Test; import static java.net.Proxy.*; -import static org.testng.Assert.expectThrows; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertThrows; public class TestDefaultBehavior { @@ -51,15 +52,15 @@ public class TestDefaultBehavior { public void testDefaultBehavior() { CustomURLStreamHandler handler = new CustomURLStreamHandler(); - expectThrows(IAE, () -> handler.openConnection(null, null)); - expectThrows(IAE, () -> handler.openConnection(null, NO_PROXY)); - expectThrows(IAE, () -> handler.openConnection(null, new Proxy(Type.SOCKS, ADDR))); - expectThrows(IAE, () -> handler.openConnection(null, new Proxy(Type.HTTP, ADDR))); - expectThrows(IAE, () -> handler.openConnection(uri.toURL(), null)); + assertThrows(IAE, () -> handler.openConnection(null, null)); + assertThrows(IAE, () -> handler.openConnection(null, NO_PROXY)); + assertThrows(IAE, () -> handler.openConnection(null, new Proxy(Type.SOCKS, ADDR))); + assertThrows(IAE, () -> handler.openConnection(null, new Proxy(Type.HTTP, ADDR))); + assertThrows(IAE, () -> handler.openConnection(uri.toURL(), null)); - expectThrows(UOE, () -> handler.openConnection(uri.toURL(), NO_PROXY)); - expectThrows(UOE, () -> handler.openConnection(uri.toURL(), new Proxy(Type.SOCKS, ADDR))); - expectThrows(UOE, () -> handler.openConnection(uri.toURL(), new Proxy(Type.HTTP, ADDR))); + assertThrows(UOE, () -> handler.openConnection(uri.toURL(), NO_PROXY)); + assertThrows(UOE, () -> handler.openConnection(uri.toURL(), new Proxy(Type.SOCKS, ADDR))); + assertThrows(UOE, () -> handler.openConnection(uri.toURL(), new Proxy(Type.HTTP, ADDR))); } // A URLStreamHandler that delegates the overloaded openConnection that From dd76306903a869752d955a45f0b5a7ea7e680c68 Mon Sep 17 00:00:00 2001 From: Erik Gahlin Date: Mon, 13 Apr 2026 13:55:27 +0000 Subject: [PATCH 262/359] 8382048: JFR: RecordingFile::write doesn't truncate when overwriting Reviewed-by: mgronlun --- .../jdk/jfr/internal/consumer/filter/RecordingOutput.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/filter/RecordingOutput.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/filter/RecordingOutput.java index 9aebb27238c..9c8187c7a46 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/filter/RecordingOutput.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/filter/RecordingOutput.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ package jdk.jfr.internal.consumer.filter; import java.io.Closeable; import java.io.File; +import java.io.FileOutputStream; import java.io.IOException; import java.io.RandomAccessFile; @@ -39,6 +40,9 @@ final class RecordingOutput implements Closeable { private long position; public RecordingOutput(File file) throws IOException { + // Truncates existing file if it exists + var fos = new FileOutputStream(file); + fos.close(); this.file = new RandomAccessFile(file, "rw"); } From 8882e7b64a6e47db906920d9509b24a67277a028 Mon Sep 17 00:00:00 2001 From: Erik Gahlin Date: Mon, 13 Apr 2026 16:42:22 +0000 Subject: [PATCH 263/359] 8382034: JFR: jdk-agents view is missing information Reviewed-by: mgronlun --- .../share/jfr/periodic/jfrPeriodic.cpp | 18 +++++++----- .../classes/jdk/jfr/internal/query/view.ini | 4 +-- .../jdk/jfr/event/runtime/TestAgentEvent.java | 29 ++++++++++++++++++- 3 files changed, 41 insertions(+), 10 deletions(-) diff --git a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp index 426ba4e7650..969c9ca60c1 100644 --- a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp +++ b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -281,7 +281,9 @@ TRACE_REQUEST_FUNC(SystemProcess) { #if INCLUDE_JVMTI template -static void send_agent_event(AgentEvent& event, const JvmtiAgent* agent) { +static void send_agent_event(AgentEvent& event, const JvmtiAgent* agent, Ticks& timestamp) { + event.set_starttime(timestamp); + event.set_endtime(timestamp); event.set_name(agent->name()); event.set_options(agent->options()); event.set_dynamic(agent->is_dynamic()); @@ -292,29 +294,31 @@ static void send_agent_event(AgentEvent& event, const JvmtiAgent* agent) { TRACE_REQUEST_FUNC(JavaAgent) { JvmtiAgentList::Iterator it = JvmtiAgentList::java_agents(); + Ticks ticks = timestamp(); while (it.has_next()) { const JvmtiAgent* agent = it.next(); assert(agent->is_jplis(), "invariant"); EventJavaAgent event; - send_agent_event(event, agent); + send_agent_event(event, agent, ticks); } } -static void send_native_agent_events(JvmtiAgentList::Iterator& it) { +static void send_native_agent_events(JvmtiAgentList::Iterator& it, Ticks& timestamp) { while (it.has_next()) { const JvmtiAgent* agent = it.next(); assert(!agent->is_jplis(), "invariant"); EventNativeAgent event; event.set_path(agent->os_lib_path()); - send_agent_event(event, agent); + send_agent_event(event, agent, timestamp); } } TRACE_REQUEST_FUNC(NativeAgent) { + Ticks ticks = timestamp(); JvmtiAgentList::Iterator native_agents_it = JvmtiAgentList::native_agents(); - send_native_agent_events(native_agents_it); + send_native_agent_events(native_agents_it, ticks); JvmtiAgentList::Iterator xrun_agents_it = JvmtiAgentList::xrun_agents(); - send_native_agent_events(xrun_agents_it); + send_native_agent_events(xrun_agents_it, ticks); } #else // INCLUDE_JVMTI TRACE_REQUEST_FUNC(JavaAgent) {} diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/query/view.ini b/src/jdk.jfr/share/classes/jdk/jfr/internal/query/view.ini index 5d72a9f85dc..d8b740e1a66 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/query/view.ini +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/query/view.ini @@ -433,8 +433,8 @@ form = "COLUMN 'Successful Samples', 'Failed Samples', 'Biased Samples', 'Total label = "JDK Agents" table = "COLUMN 'Time', 'Initialization', 'Name', 'Options' FORMAT none, none, truncate-beginning;cell-height:10, cell-height:10 - SELECT LAST(initializationTime) AS t, LAST(initializationDuration), LAST(name), LAST(JavaAgent.options) - FROM JavaAgent, NativeAgent + SELECT LAST_BATCH(initializationTime) AS t, LAST_BATCH(initializationDuration), LAST_BATCH(name), LAST_BATCH(options) + FROM JavaAgent, NativeAgent GROUP BY initializationTime ORDER BY t" [environment.jvm-flags] diff --git a/test/jdk/jdk/jfr/event/runtime/TestAgentEvent.java b/test/jdk/jdk/jfr/event/runtime/TestAgentEvent.java index ca7b6dfc0f1..6e168153947 100644 --- a/test/jdk/jdk/jfr/event/runtime/TestAgentEvent.java +++ b/test/jdk/jdk/jfr/event/runtime/TestAgentEvent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +68,12 @@ import jdk.test.lib.jfr.TestClassLoader; * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=0 * jdk.jfr.event.runtime.TestAgentEvent * testNativeStatic + * + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps + * -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=0 + * -javaagent:JavaAgent.jar=foo=bar + * jdk.jfr.event.runtime.TestAgentEvent + * testMultipleAgents */ public final class TestAgentEvent { @StackTrace(false) @@ -179,4 +185,25 @@ public final class TestAgentEvent { Events.assertField(events.get(4), "options").equal("="); } } + + private static void testMultipleAgents() throws Exception { + try (Recording r = new Recording()) { + r.enable(EventNames.NativeAgent).with("period", "endChunk"); + r.enable(EventNames.JavaAgent).with("period", "endChunk"); + r.start(); + r.stop(); + List events = Events.fromRecording(r); + if (events.size() != 2) { + throw new Exception("Expected two agents"); + } + Instant timestamp = events.getFirst().getStartTime(); + for (RecordedEvent event : events) { + if (!event.getStartTime().equals(timestamp) || + !event.getEndTime().equals(timestamp)) { + System.out.println(events); + throw new Exception("Expected agent to have the same start and end time"); + } + } + } + } } From 5cbc5653f4a331a0c976c7db44c3160f7ee6e84e Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Mon, 13 Apr 2026 16:45:08 +0000 Subject: [PATCH 264/359] 8382081: AOT tests fail in add_stub_entries without JVMCI Reviewed-by: chagedorn, mhaessig, kvn --- src/hotspot/share/code/codeBlob.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/code/codeBlob.hpp b/src/hotspot/share/code/codeBlob.hpp index 1c6904e7446..d372e72fc23 100644 --- a/src/hotspot/share/code/codeBlob.hpp +++ b/src/hotspot/share/code/codeBlob.hpp @@ -604,7 +604,7 @@ class DeoptimizationBlob: public SingletonBlob { ); public: - static const int ENTRY_COUNT = 4 JVMTI_ONLY(+ 2); + static const int ENTRY_COUNT = 4 JVMCI_ONLY(+ 2); // Creation static DeoptimizationBlob* create( CodeBuffer* cb, From 121165ec91134dbeab0a243246624e935a916955 Mon Sep 17 00:00:00 2001 From: Vladimir Ivanov Date: Mon, 13 Apr 2026 16:49:57 +0000 Subject: [PATCH 265/359] 8290892: C2: Intrinsify Reference.reachabilityFence Co-authored-by: Tobias Holenstein Co-authored-by: Vladimir Ivanov Reviewed-by: dlong, epeter --- src/hotspot/share/classfile/vmIntrinsics.hpp | 3 + src/hotspot/share/opto/block.cpp | 4 +- src/hotspot/share/opto/c2_globals.hpp | 11 + src/hotspot/share/opto/c2compiler.cpp | 1 + src/hotspot/share/opto/callGenerator.cpp | 14 + src/hotspot/share/opto/callnode.cpp | 57 +- src/hotspot/share/opto/callnode.hpp | 67 ++- src/hotspot/share/opto/classes.cpp | 1 + src/hotspot/share/opto/classes.hpp | 1 + src/hotspot/share/opto/compile.cpp | 57 +- src/hotspot/share/opto/compile.hpp | 20 +- src/hotspot/share/opto/escape.cpp | 29 +- src/hotspot/share/opto/gcm.cpp | 9 +- src/hotspot/share/opto/graphKit.cpp | 10 + src/hotspot/share/opto/graphKit.hpp | 1 + src/hotspot/share/opto/library_call.cpp | 9 + src/hotspot/share/opto/library_call.hpp | 1 + src/hotspot/share/opto/loopTransform.cpp | 69 ++- src/hotspot/share/opto/loopnode.cpp | 61 ++- src/hotspot/share/opto/loopnode.hpp | 27 + src/hotspot/share/opto/macro.cpp | 30 +- src/hotspot/share/opto/memnode.cpp | 2 +- src/hotspot/share/opto/node.cpp | 26 + src/hotspot/share/opto/node.hpp | 6 + src/hotspot/share/opto/parse.hpp | 1 + src/hotspot/share/opto/parse1.cpp | 54 ++ src/hotspot/share/opto/phase.cpp | 3 + src/hotspot/share/opto/phase.hpp | 3 + src/hotspot/share/opto/phasetype.hpp | 1 + src/hotspot/share/opto/reachability.cpp | 512 ++++++++++++++++++ src/hotspot/share/opto/reachability.hpp | 83 +++ .../classes/java/lang/ref/Reference.java | 9 +- .../c2/ReachabilityFenceFlagsTest.java | 52 ++ .../c2/ReachabilityFenceOnConstantTest.java | 117 ++++ .../compiler/c2/ReachabilityFenceTest.java | 353 ++++++++++++ .../c2/irTests/ReachabilityFenceTest.java | 125 +++++ .../lib/ir_framework/CompilePhase.java | 1 + .../compiler/lib/ir_framework/IRNode.java | 5 + 38 files changed, 1769 insertions(+), 66 deletions(-) create mode 100644 src/hotspot/share/opto/reachability.cpp create mode 100644 src/hotspot/share/opto/reachability.hpp create mode 100644 test/hotspot/jtreg/compiler/c2/ReachabilityFenceFlagsTest.java create mode 100644 test/hotspot/jtreg/compiler/c2/ReachabilityFenceOnConstantTest.java create mode 100644 test/hotspot/jtreg/compiler/c2/ReachabilityFenceTest.java create mode 100644 test/hotspot/jtreg/compiler/c2/irTests/ReachabilityFenceTest.java diff --git a/src/hotspot/share/classfile/vmIntrinsics.hpp b/src/hotspot/share/classfile/vmIntrinsics.hpp index e84acd62284..3f85fd16b61 100644 --- a/src/hotspot/share/classfile/vmIntrinsics.hpp +++ b/src/hotspot/share/classfile/vmIntrinsics.hpp @@ -469,6 +469,9 @@ class methodHandle; do_intrinsic(_Reference_clear0, java_lang_ref_Reference, clear0_name, void_method_signature, F_RN) \ do_intrinsic(_PhantomReference_clear0, java_lang_ref_PhantomReference, clear0_name, void_method_signature, F_RN) \ \ + do_intrinsic(_Reference_reachabilityFence, java_lang_ref_Reference, reachabilityFence_name, object_void_signature, F_S) \ + do_name(reachabilityFence_name, "reachabilityFence") \ + \ /* support for com.sun.crypto.provider.AES_Crypt and some of its callers */ \ do_class(com_sun_crypto_provider_aescrypt, "com/sun/crypto/provider/AES_Crypt") \ do_intrinsic(_aescrypt_encryptBlock, com_sun_crypto_provider_aescrypt, encryptBlock_name, byteArray_int_byteArray_int_signature, F_R) \ diff --git a/src/hotspot/share/opto/block.cpp b/src/hotspot/share/opto/block.cpp index 7d3d4ec16f4..a93e2e43a29 100644 --- a/src/hotspot/share/opto/block.cpp +++ b/src/hotspot/share/opto/block.cpp @@ -179,9 +179,11 @@ int Block::is_Empty() const { // Ideal nodes (except BoxLock) are allowable in empty blocks: skip them. Only // Mach and BoxLock nodes turn directly into code via emit(). + // Keep ReachabilityFence for diagnostic purposes. while ((end_idx > 0) && !get_node(end_idx)->is_Mach() && - !get_node(end_idx)->is_BoxLock()) { + !get_node(end_idx)->is_BoxLock() && + !get_node(end_idx)->is_ReachabilityFence()) { end_idx--; } diff --git a/src/hotspot/share/opto/c2_globals.hpp b/src/hotspot/share/opto/c2_globals.hpp index 6974d50741e..dacc8ce9c26 100644 --- a/src/hotspot/share/opto/c2_globals.hpp +++ b/src/hotspot/share/opto/c2_globals.hpp @@ -76,6 +76,17 @@ develop(bool, StressBailout, false, \ "Perform bailouts randomly at C2 failing() checks") \ \ + product(bool, OptimizeReachabilityFences, true, DIAGNOSTIC, \ + "Optimize reachability fences " \ + "(leave reachability fence nodes intact when turned off)") \ + \ + product(bool, PreserveReachabilityFencesOnConstants, false, DIAGNOSTIC, \ + "Keep reachability fences on compile-time constants") \ + \ + product(bool, StressReachabilityFences, false, DIAGNOSTIC, \ + "Aggressively insert reachability fences " \ + "for all oop method arguments") \ + \ develop(uint, StressBailoutMean, 100000, \ "The expected number of failing() checks made until " \ "a random bailout.") \ diff --git a/src/hotspot/share/opto/c2compiler.cpp b/src/hotspot/share/opto/c2compiler.cpp index ead1b78cdea..5d170f919c8 100644 --- a/src/hotspot/share/opto/c2compiler.cpp +++ b/src/hotspot/share/opto/c2compiler.cpp @@ -775,6 +775,7 @@ bool C2Compiler::is_intrinsic_supported(vmIntrinsics::ID id) { case vmIntrinsics::_longBitsToDouble: case vmIntrinsics::_Reference_get0: case vmIntrinsics::_Reference_refersTo0: + case vmIntrinsics::_Reference_reachabilityFence: case vmIntrinsics::_PhantomReference_refersTo0: case vmIntrinsics::_Reference_clear0: case vmIntrinsics::_PhantomReference_clear0: diff --git a/src/hotspot/share/opto/callGenerator.cpp b/src/hotspot/share/opto/callGenerator.cpp index 1465da02ac8..49897ca3c17 100644 --- a/src/hotspot/share/opto/callGenerator.cpp +++ b/src/hotspot/share/opto/callGenerator.cpp @@ -611,6 +611,20 @@ void CallGenerator::do_late_inline_helper() { } Compile* C = Compile::current(); + + uint endoff = call->jvms()->endoff(); + if (C->inlining_incrementally()) { + // No reachability edges should be present when incremental inlining takes place. + // Inlining logic doesn't expect any extra edges past debug info and fails with + // an assert in SafePointNode::grow_stack. + assert(endoff == call->req(), "reachability edges not supported"); + } else { + if (call->req() > endoff) { // reachability edges present + assert(OptimizeReachabilityFences, "required"); + return; // keep the original call node as the holder of reachability info + } + } + // Remove inlined methods from Compiler's lists. if (call->is_macro()) { C->remove_macro_node(call); diff --git a/src/hotspot/share/opto/callnode.cpp b/src/hotspot/share/opto/callnode.cpp index b2b01079379..eb4f506d14f 100644 --- a/src/hotspot/share/opto/callnode.cpp +++ b/src/hotspot/share/opto/callnode.cpp @@ -898,7 +898,7 @@ bool CallNode::may_modify(const TypeOopPtr* t_oop, PhaseValues* phase) const { } // Does this call have a direct reference to n other than debug information? -bool CallNode::has_non_debug_use(Node *n) { +bool CallNode::has_non_debug_use(const Node *n) { const TypeTuple * d = tf()->domain(); for (uint i = TypeFunc::Parms; i < d->cnt(); i++) { Node *arg = in(i); @@ -940,7 +940,7 @@ Node *CallNode::result_cast() { } -void CallNode::extract_projections(CallProjections* projs, bool separate_io_proj, bool do_asserts) const { +void CallNode::extract_projections(CallProjections* projs, bool separate_io_proj, bool do_asserts, bool allow_handlers) const { projs->fallthrough_proj = nullptr; projs->fallthrough_catchproj = nullptr; projs->fallthrough_ioproj = nullptr; @@ -961,14 +961,13 @@ void CallNode::extract_projections(CallProjections* projs, bool separate_io_proj projs->fallthrough_proj = pn; const Node* cn = pn->unique_ctrl_out_or_null(); if (cn != nullptr && cn->is_Catch()) { - ProjNode *cpn = nullptr; for (DUIterator_Fast kmax, k = cn->fast_outs(kmax); k < kmax; k++) { - cpn = cn->fast_out(k)->as_Proj(); - assert(cpn->is_CatchProj(), "must be a CatchProjNode"); - if (cpn->_con == CatchProjNode::fall_through_index) + CatchProjNode* cpn = cn->fast_out(k)->as_CatchProj(); + assert(allow_handlers || !cpn->is_handler_proj(), "not allowed"); + if (cpn->_con == CatchProjNode::fall_through_index) { + assert(cpn->handler_bci() == CatchProjNode::no_handler_bci, ""); projs->fallthrough_catchproj = cpn; - else { - assert(cpn->_con == CatchProjNode::catch_all_index, "must be correct index."); + } else if (!cpn->is_handler_proj()) { projs->catchall_catchproj = cpn; } } @@ -976,15 +975,20 @@ void CallNode::extract_projections(CallProjections* projs, bool separate_io_proj break; } case TypeFunc::I_O: - if (pn->_is_io_use) + if (pn->_is_io_use) { projs->catchall_ioproj = pn; - else + } else { projs->fallthrough_ioproj = pn; + } for (DUIterator j = pn->outs(); pn->has_out(j); j++) { Node* e = pn->out(j); - if (e->Opcode() == Op_CreateEx && e->in(0)->is_CatchProj() && e->outcnt() > 0) { - assert(projs->exobj == nullptr, "only one"); - projs->exobj = e; + if (e->Opcode() == Op_CreateEx && e->outcnt() > 0) { + CatchProjNode* ecpn = e->in(0)->isa_CatchProj(); + assert(allow_handlers || ecpn == nullptr || !ecpn->is_handler_proj(), "not allowed"); + if (ecpn != nullptr && ecpn->_con != CatchProjNode::fall_through_index && !ecpn->is_handler_proj()) { + assert(projs->exobj == nullptr, "only one"); + projs->exobj = e; + } } } break; @@ -1609,6 +1613,33 @@ void SafePointNode::disconnect_from_root(PhaseIterGVN *igvn) { } } +void SafePointNode::remove_non_debug_edges(NodeEdgeTempStorage& non_debug_edges) { + assert(non_debug_edges._state == NodeEdgeTempStorage::state_initial, "not processed"); + assert(non_debug_edges.is_empty(), "edges not processed"); + + while (req() > jvms()->endoff()) { + uint last = req() - 1; + non_debug_edges.push(in(last)); + del_req(last); + } + + assert(jvms()->endoff() == req(), "no extra edges past debug info allowed"); + DEBUG_ONLY(non_debug_edges._state = NodeEdgeTempStorage::state_populated); +} + +void SafePointNode::restore_non_debug_edges(NodeEdgeTempStorage& non_debug_edges) { + assert(non_debug_edges._state == NodeEdgeTempStorage::state_populated, "not populated"); + assert(jvms()->endoff() == req(), "no extra edges past debug info allowed"); + + while (!non_debug_edges.is_empty()) { + Node* non_debug_edge = non_debug_edges.pop(); + add_req(non_debug_edge); + } + + assert(non_debug_edges.is_empty(), "edges not processed"); + DEBUG_ONLY(non_debug_edges._state = NodeEdgeTempStorage::state_processed); +} + //============== SafePointScalarObjectNode ============== SafePointScalarObjectNode::SafePointScalarObjectNode(const TypeOopPtr* tp, Node* alloc, uint first_index, uint depth, uint n_fields) : diff --git a/src/hotspot/share/opto/callnode.hpp b/src/hotspot/share/opto/callnode.hpp index 5241ae6cd2b..e4c548fc744 100644 --- a/src/hotspot/share/opto/callnode.hpp +++ b/src/hotspot/share/opto/callnode.hpp @@ -503,6 +503,66 @@ public: return _has_ea_local_in_scope; } + // A temporary storge for node edges. + // Intended for a single use. + class NodeEdgeTempStorage : public StackObj { + friend class SafePointNode; + + PhaseIterGVN& _igvn; + Node* _node_hook; + +#ifdef ASSERT + enum State { state_initial, state_populated, state_processed }; + + State _state; // monotonically transitions from initial to processed state. +#endif // ASSERT + + bool is_empty() const { + return _node_hook == nullptr || _node_hook->req() == 1; + } + void push(Node* n) { + assert(n != nullptr, ""); + if (_node_hook == nullptr) { + _node_hook = new Node(nullptr); + } + _node_hook->add_req(n); + } + Node* pop() { + assert(!is_empty(), ""); + int idx = _node_hook->req()-1; + Node* r = _node_hook->in(idx); + _node_hook->del_req(idx); + assert(r != nullptr, ""); + return r; + } + + public: + NodeEdgeTempStorage(PhaseIterGVN &igvn) : _igvn(igvn), _node_hook(nullptr) + DEBUG_ONLY(COMMA _state(state_initial)) { + assert(is_empty(), ""); + } + + ~NodeEdgeTempStorage() { + assert(_state == state_processed, "not processed"); + assert(is_empty(), ""); + if (_node_hook != nullptr) { + _node_hook->destruct(&_igvn); + } + } + + void remove_edge_if_present(Node* n) { + if (!is_empty()) { + int idx = _node_hook->find_edge(n); + if (idx > 0) { + _node_hook->del_req(idx); + } + } + } + }; + + void remove_non_debug_edges(NodeEdgeTempStorage& non_debug_edges); + void restore_non_debug_edges(NodeEdgeTempStorage& non_debug_edges); + void disconnect_from_root(PhaseIterGVN *igvn); // Standard Node stuff @@ -736,7 +796,7 @@ public: // Returns true if the call may modify n virtual bool may_modify(const TypeOopPtr* t_oop, PhaseValues* phase) const; // Does this node have a use of n other than in debug information? - bool has_non_debug_use(Node* n); + bool has_non_debug_use(const Node* n); // Returns the unique CheckCastPP of a call // or result projection is there are several CheckCastPP // or returns null if there is no one. @@ -751,7 +811,10 @@ public: // Collect all the interesting edges from a call for use in // replacing the call by something else. Used by macro expansion // and the late inlining support. - void extract_projections(CallProjections* projs, bool separate_io_proj, bool do_asserts = true) const; + void extract_projections(CallProjections* projs, + bool separate_io_proj, + bool do_asserts = true, + bool allow_handlers = false) const; virtual uint match_edge(uint idx) const; diff --git a/src/hotspot/share/opto/classes.cpp b/src/hotspot/share/opto/classes.cpp index b760a179b57..1cd6c52393b 100644 --- a/src/hotspot/share/opto/classes.cpp +++ b/src/hotspot/share/opto/classes.cpp @@ -43,6 +43,7 @@ #include "opto/narrowptrnode.hpp" #include "opto/node.hpp" #include "opto/opaquenode.hpp" +#include "opto/reachability.hpp" #include "opto/rootnode.hpp" #include "opto/subnode.hpp" #include "opto/subtypenode.hpp" diff --git a/src/hotspot/share/opto/classes.hpp b/src/hotspot/share/opto/classes.hpp index d9290492337..3c1a68d6224 100644 --- a/src/hotspot/share/opto/classes.hpp +++ b/src/hotspot/share/opto/classes.hpp @@ -547,3 +547,4 @@ macro(MaskAll) macro(AndVMask) macro(OrVMask) macro(XorVMask) +macro(ReachabilityFence) diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index 7b5f78a8ad3..db3cbd4109c 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -74,6 +74,7 @@ #include "opto/output.hpp" #include "opto/parse.hpp" #include "opto/phaseX.hpp" +#include "opto/reachability.hpp" #include "opto/rootnode.hpp" #include "opto/runtime.hpp" #include "opto/stringopts.hpp" @@ -396,6 +397,9 @@ void Compile::remove_useless_node(Node* dead) { if (dead->is_expensive()) { remove_expensive_node(dead); } + if (dead->is_ReachabilityFence()) { + remove_reachability_fence(dead->as_ReachabilityFence()); + } if (dead->is_OpaqueTemplateAssertionPredicate()) { remove_template_assertion_predicate_opaque(dead->as_OpaqueTemplateAssertionPredicate()); } @@ -459,6 +463,7 @@ void Compile::disconnect_useless_nodes(Unique_Node_List& useful, Unique_Node_Lis // Remove useless Template Assertion Predicate opaque nodes remove_useless_nodes(_template_assertion_predicate_opaques, useful); remove_useless_nodes(_expensive_nodes, useful); // remove useless expensive nodes + remove_useless_nodes(_reachability_fences, useful); // remove useless node recorded for post loop opts IGVN pass remove_useless_nodes(_for_post_loop_igvn, useful); // remove useless node recorded for post loop opts IGVN pass remove_useless_nodes(_for_merge_stores_igvn, useful); // remove useless node recorded for merge stores IGVN pass remove_useless_unstable_if_traps(useful); // remove useless unstable_if traps @@ -665,6 +670,7 @@ Compile::Compile(ciEnv* ci_env, ciMethod* target, int osr_bci, _parse_predicates(comp_arena(), 8, 0, nullptr), _template_assertion_predicate_opaques(comp_arena(), 8, 0, nullptr), _expensive_nodes(comp_arena(), 8, 0, nullptr), + _reachability_fences(comp_arena(), 8, 0, nullptr), _for_post_loop_igvn(comp_arena(), 8, 0, nullptr), _for_merge_stores_igvn(comp_arena(), 8, 0, nullptr), _unstable_if_traps(comp_arena(), 8, 0, nullptr), @@ -934,6 +940,7 @@ Compile::Compile(ciEnv* ci_env, _directive(directive), _log(ci_env->log()), _first_failure_details(nullptr), + _reachability_fences(comp_arena(), 8, 0, nullptr), _for_post_loop_igvn(comp_arena(), 8, 0, nullptr), _for_merge_stores_igvn(comp_arena(), 8, 0, nullptr), _congraph(nullptr), @@ -2510,12 +2517,23 @@ void Compile::Optimize() { return; } - if (failing()) return; - C->clear_major_progress(); // ensure that major progress is now clear process_for_post_loop_opts_igvn(igvn); + if (failing()) return; + + // Once loop optimizations are over, it is safe to get rid of all reachability fence nodes and + // migrate reachability edges to safepoints. + if (OptimizeReachabilityFences && _reachability_fences.length() > 0) { + TracePhase tp1(_t_idealLoop); + TracePhase tp2(_t_reachability); + PhaseIdealLoop::optimize(igvn, PostLoopOptsExpandReachabilityFences); + print_method(PHASE_EXPAND_REACHABILITY_FENCES, 2); + if (failing()) return; + assert(_reachability_fences.length() == 0 || PreserveReachabilityFencesOnConstants, "no RF nodes allowed"); + } + process_for_merge_stores_igvn(igvn); if (failing()) return; @@ -3973,10 +3991,28 @@ void Compile::final_graph_reshaping_walk(Node_Stack& nstack, Node* root, Final_R } } + expand_reachability_edges(sfpt); + // Skip next transformation if compressed oops are not used. if (UseCompressedOops && !Matcher::gen_narrow_oop_implicit_null_checks()) return; + // Go over ReachabilityFence nodes to skip DecodeN nodes for referents. + // The sole purpose of RF node is to keep the referent oop alive and + // decoding the oop for that is not needed. + for (int i = 0; i < C->reachability_fences_count(); i++) { + ReachabilityFenceNode* rf = C->reachability_fence(i); + DecodeNNode* dn = rf->in(1)->isa_DecodeN(); + if (dn != nullptr) { + if (!dn->has_non_debug_uses() || Matcher::narrow_oop_use_complex_address()) { + rf->set_req(1, dn->in(1)); + if (dn->outcnt() == 0) { + dn->disconnect_inputs(this); + } + } + } + } + // Go over safepoints nodes to skip DecodeN/DecodeNKlass nodes for debug edges. // It could be done for an uncommon traps or any safepoints/calls // if the DecodeN/DecodeNKlass node is referenced only in a debug info. @@ -3990,21 +4026,8 @@ void Compile::final_graph_reshaping_walk(Node_Stack& nstack, Node* root, Final_R n->as_CallStaticJava()->uncommon_trap_request() != 0); for (int j = start; j < end; j++) { Node* in = n->in(j); - if (in->is_DecodeNarrowPtr()) { - bool safe_to_skip = true; - if (!is_uncommon ) { - // Is it safe to skip? - for (uint i = 0; i < in->outcnt(); i++) { - Node* u = in->raw_out(i); - if (!u->is_SafePoint() || - (u->is_Call() && u->as_Call()->has_non_debug_use(n))) { - safe_to_skip = false; - } - } - } - if (safe_to_skip) { - n->set_req(j, in->in(1)); - } + if (in->is_DecodeNarrowPtr() && (is_uncommon || !in->has_non_debug_uses())) { + n->set_req(j, in->in(1)); if (in->outcnt() == 0) { in->disconnect_inputs(this); } diff --git a/src/hotspot/share/opto/compile.hpp b/src/hotspot/share/opto/compile.hpp index eb6be669f24..ff0085d79de 100644 --- a/src/hotspot/share/opto/compile.hpp +++ b/src/hotspot/share/opto/compile.hpp @@ -80,6 +80,7 @@ class PhaseIterGVN; class PhaseRegAlloc; class PhaseCCP; class PhaseOutput; +class ReachabilityFenceNode; class RootNode; class relocInfo; class StartNode; @@ -107,7 +108,8 @@ enum LoopOptsMode { LoopOptsMaxUnroll, LoopOptsShenandoahExpand, LoopOptsSkipSplitIf, - LoopOptsVerify + LoopOptsVerify, + PostLoopOptsExpandReachabilityFences }; // The type of all node counts and indexes. @@ -385,6 +387,7 @@ class Compile : public Phase { // of Template Assertion Predicates themselves. GrowableArray _template_assertion_predicate_opaques; GrowableArray _expensive_nodes; // List of nodes that are expensive to compute and that we'd better not let the GVN freely common + GrowableArray _reachability_fences; // List of reachability fences GrowableArray _for_post_loop_igvn; // List of nodes for IGVN after loop opts are over GrowableArray _for_merge_stores_igvn; // List of nodes for IGVN merge stores GrowableArray _unstable_if_traps; // List of ifnodes after IGVN @@ -714,11 +717,13 @@ public: int template_assertion_predicate_count() const { return _template_assertion_predicate_opaques.length(); } int expensive_count() const { return _expensive_nodes.length(); } int coarsened_count() const { return _coarsened_locks.length(); } - Node* macro_node(int idx) const { return _macro_nodes.at(idx); } Node* expensive_node(int idx) const { return _expensive_nodes.at(idx); } + ReachabilityFenceNode* reachability_fence(int idx) const { return _reachability_fences.at(idx); } + int reachability_fences_count() const { return _reachability_fences.length(); } + ConnectionGraph* congraph() { return _congraph;} void set_congraph(ConnectionGraph* congraph) { _congraph = congraph;} void add_macro_node(Node * n) { @@ -740,6 +745,14 @@ public: _expensive_nodes.remove_if_existing(n); } + void add_reachability_fence(ReachabilityFenceNode* rf) { + _reachability_fences.append(rf); + } + + void remove_reachability_fence(ReachabilityFenceNode* n) { + _reachability_fences.remove_if_existing(n); + } + void add_parse_predicate(ParsePredicateNode* n) { assert(!_parse_predicates.contains(n), "duplicate entry in Parse Predicate list"); _parse_predicates.append(n); @@ -1300,6 +1313,9 @@ public: // Definitions of pd methods static void pd_compiler2_init(); + // Materialize reachability fences from reachability edges on safepoints. + void expand_reachability_edges(Unique_Node_List& safepoints); + // Static parse-time type checking logic for gen_subtype_check: enum SubTypeCheckResult { SSC_always_false, SSC_always_true, SSC_easy_test, SSC_full_test }; SubTypeCheckResult static_subtype_check(const TypeKlassPtr* superk, const TypeKlassPtr* subk, bool skip = StressReflectiveCode); diff --git a/src/hotspot/share/opto/escape.cpp b/src/hotspot/share/opto/escape.cpp index 64ee60037d6..a05ad0ef99a 100644 --- a/src/hotspot/share/opto/escape.cpp +++ b/src/hotspot/share/opto/escape.cpp @@ -1273,21 +1273,33 @@ bool ConnectionGraph::reduce_phi_on_safepoints_helper(Node* ophi, Node* cast, No for (uint spi = 0; spi < safepoints.size(); spi++) { SafePointNode* sfpt = safepoints.at(spi)->as_SafePoint(); - JVMState *jvms = sfpt->jvms(); - uint merge_idx = (sfpt->req() - jvms->scloff()); - int debug_start = jvms->debug_start(); + + SafePointNode::NodeEdgeTempStorage non_debug_edges_worklist(*_igvn); + + // All sfpt inputs are implicitly included into debug info during the scalarization process below. + // Keep non-debug inputs separately, so they stay non-debug. + sfpt->remove_non_debug_edges(non_debug_edges_worklist); + + JVMState* jvms = sfpt->jvms(); + uint merge_idx = (sfpt->req() - jvms->scloff()); + int debug_start = jvms->debug_start(); SafePointScalarMergeNode* smerge = new SafePointScalarMergeNode(merge_t, merge_idx); smerge->init_req(0, _compile->root()); _igvn->register_new_node_with_optimizer(smerge); + assert(sfpt->jvms()->endoff() == sfpt->req(), "no extra edges past debug info allowed"); + // The next two inputs are: // (1) A copy of the original pointer to NSR objects. // (2) A selector, used to decide if we need to rematerialize an object // or use the pointer to a NSR object. - // See more details of these fields in the declaration of SafePointScalarMergeNode + // See more details of these fields in the declaration of SafePointScalarMergeNode. + // It is safe to include them into debug info straight away since create_scalarized_object_description() + // will include all newly added inputs into debug info anyway. sfpt->add_req(nsr_merge_pointer); sfpt->add_req(selector); + sfpt->jvms()->set_endoff(sfpt->req()); for (uint i = 1; i < ophi->req(); i++) { Node* base = ophi->in(i); @@ -1302,13 +1314,15 @@ bool ConnectionGraph::reduce_phi_on_safepoints_helper(Node* ophi, Node* cast, No AllocateNode* alloc = ptn->ideal_node()->as_Allocate(); SafePointScalarObjectNode* sobj = mexp.create_scalarized_object_description(alloc, sfpt); if (sobj == nullptr) { - return false; + sfpt->restore_non_debug_edges(non_debug_edges_worklist); + return false; // non-recoverable failure; recompile } // Now make a pass over the debug information replacing any references // to the allocated object with "sobj" Node* ccpp = alloc->result_cast(); sfpt->replace_edges_in_range(ccpp, sobj, debug_start, jvms->debug_end(), _igvn); + non_debug_edges_worklist.remove_edge_if_present(ccpp); // drop scalarized input from non-debug info // Register the scalarized object as a candidate for reallocation smerge->add_req(sobj); @@ -1316,11 +1330,15 @@ bool ConnectionGraph::reduce_phi_on_safepoints_helper(Node* ophi, Node* cast, No // Replaces debug information references to "original_sfpt_parent" in "sfpt" with references to "smerge" sfpt->replace_edges_in_range(original_sfpt_parent, smerge, debug_start, jvms->debug_end(), _igvn); + non_debug_edges_worklist.remove_edge_if_present(original_sfpt_parent); // drop scalarized input from non-debug info // The call to 'replace_edges_in_range' above might have removed the // reference to ophi that we need at _merge_pointer_idx. The line below make // sure the reference is maintained. sfpt->set_req(smerge->merge_pointer_idx(jvms), nsr_merge_pointer); + + sfpt->restore_non_debug_edges(non_debug_edges_worklist); + _igvn->_worklist.push(sfpt); } @@ -4712,6 +4730,7 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist, op == Op_StrIndexOf || op == Op_StrIndexOfChar || op == Op_SubTypeCheck || op == Op_ReinterpretS2HF || + op == Op_ReachabilityFence || BarrierSet::barrier_set()->barrier_set_c2()->is_gc_barrier_node(use))) { n->dump(); use->dump(); diff --git a/src/hotspot/share/opto/gcm.cpp b/src/hotspot/share/opto/gcm.cpp index 4a1553b1e00..e3d3108a22e 100644 --- a/src/hotspot/share/opto/gcm.cpp +++ b/src/hotspot/share/opto/gcm.cpp @@ -152,9 +152,12 @@ bool PhaseCFG::is_CFG(Node* n) { } bool PhaseCFG::is_control_proj_or_safepoint(Node* n) const { - bool result = (n->is_Mach() && n->as_Mach()->ideal_Opcode() == Op_SafePoint) || (n->is_Proj() && n->as_Proj()->bottom_type() == Type::CONTROL); - assert(!result || (n->is_Mach() && n->as_Mach()->ideal_Opcode() == Op_SafePoint) - || (n->is_Proj() && n->as_Proj()->_con == 0), "If control projection, it must be projection 0"); + bool result = n->is_ReachabilityFence() || + (n->is_Mach() && n->as_Mach()->ideal_Opcode() == Op_SafePoint) || + (n->is_Proj() && n->as_Proj()->bottom_type() == Type::CONTROL); + assert(!n->is_Proj() || + n->as_Proj()->bottom_type() != Type::CONTROL || + n->as_Proj()->_con == 0, "If control projection, it must be projection 0"); return result; } diff --git a/src/hotspot/share/opto/graphKit.cpp b/src/hotspot/share/opto/graphKit.cpp index 8d32694e9a5..bbd00d111f7 100644 --- a/src/hotspot/share/opto/graphKit.cpp +++ b/src/hotspot/share/opto/graphKit.cpp @@ -41,6 +41,7 @@ #include "opto/machnode.hpp" #include "opto/opaquenode.hpp" #include "opto/parse.hpp" +#include "opto/reachability.hpp" #include "opto/rootnode.hpp" #include "opto/runtime.hpp" #include "opto/subtypenode.hpp" @@ -3541,6 +3542,15 @@ Node* GraphKit::insert_mem_bar_volatile(int opcode, int alias_idx, Node* precede return membar; } +//------------------------------insert_reachability_fence---------------------- +Node* GraphKit::insert_reachability_fence(Node* referent) { + assert(!referent->is_top(), ""); + Node* rf = _gvn.transform(new ReachabilityFenceNode(C, control(), referent)); + set_control(rf); + C->record_for_igvn(rf); + return rf; +} + //------------------------------shared_lock------------------------------------ // Emit locking code. FastLockNode* GraphKit::shared_lock(Node* obj) { diff --git a/src/hotspot/share/opto/graphKit.hpp b/src/hotspot/share/opto/graphKit.hpp index 273009ca7ce..f53f73d0978 100644 --- a/src/hotspot/share/opto/graphKit.hpp +++ b/src/hotspot/share/opto/graphKit.hpp @@ -805,6 +805,7 @@ class GraphKit : public Phase { int next_monitor(); Node* insert_mem_bar(int opcode, Node* precedent = nullptr); Node* insert_mem_bar_volatile(int opcode, int alias_idx, Node* precedent = nullptr); + Node* insert_reachability_fence(Node* referent); // Optional 'precedent' is appended as an extra edge, to force ordering. FastLockNode* shared_lock(Node* obj); void shared_unlock(Node* box, Node* obj); diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index e0f95377cde..26417436ed9 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -568,6 +568,7 @@ bool LibraryCallKit::try_to_inline(int predicate) { case vmIntrinsics::_Reference_get0: return inline_reference_get0(); case vmIntrinsics::_Reference_refersTo0: return inline_reference_refersTo0(false); + case vmIntrinsics::_Reference_reachabilityFence: return inline_reference_reachabilityFence(); case vmIntrinsics::_PhantomReference_refersTo0: return inline_reference_refersTo0(true); case vmIntrinsics::_Reference_clear0: return inline_reference_clear0(false); case vmIntrinsics::_PhantomReference_clear0: return inline_reference_clear0(true); @@ -7025,6 +7026,14 @@ bool LibraryCallKit::inline_reference_clear0(bool is_phantom) { return true; } +//-----------------------inline_reference_reachabilityFence----------------- +// bool java.lang.ref.Reference.reachabilityFence(); +bool LibraryCallKit::inline_reference_reachabilityFence() { + Node* referent = argument(0); + insert_reachability_fence(referent); + return true; +} + Node* LibraryCallKit::load_field_from_object(Node* fromObj, const char* fieldName, const char* fieldTypeString, DecoratorSet decorators, bool is_static, ciInstanceKlass* fromKls) { diff --git a/src/hotspot/share/opto/library_call.hpp b/src/hotspot/share/opto/library_call.hpp index 9b87df645e1..9aae48302cf 100644 --- a/src/hotspot/share/opto/library_call.hpp +++ b/src/hotspot/share/opto/library_call.hpp @@ -312,6 +312,7 @@ class LibraryCallKit : public GraphKit { bool inline_divmod_methods(vmIntrinsics::ID id); bool inline_reference_get0(); bool inline_reference_refersTo0(bool is_phantom); + bool inline_reference_reachabilityFence(); bool inline_reference_clear0(bool is_phantom); bool inline_Class_cast(); bool inline_aescrypt_Block(vmIntrinsics::ID id); diff --git a/src/hotspot/share/opto/loopTransform.cpp b/src/hotspot/share/opto/loopTransform.cpp index 60a61b6bb4e..b65f90093ab 100644 --- a/src/hotspot/share/opto/loopTransform.cpp +++ b/src/hotspot/share/opto/loopTransform.cpp @@ -52,17 +52,70 @@ // Given an IfNode, return the loop-exiting projection or null if both // arms remain in the loop. Node *IdealLoopTree::is_loop_exit(Node *iff) const { - if (iff->outcnt() != 2) return nullptr; // Ignore partially dead tests - PhaseIdealLoop *phase = _phase; + assert(iff->is_If(), "not an If: %s", iff->Name()); + assert(is_member(_phase->get_loop(iff)), "not related"); + + if (iff->outcnt() != 2) { + return nullptr; // Ignore partially dead tests + } // Test is an IfNode, has 2 projections. If BOTH are in the loop // we need loop unswitching instead of peeling. - if (!is_member(phase->get_loop(iff->raw_out(0)))) + if (!is_member(_phase->get_loop(iff->raw_out(0)))) { return iff->raw_out(0); - if (!is_member(phase->get_loop(iff->raw_out(1)))) + } + if (!is_member(_phase->get_loop(iff->raw_out(1)))) { return iff->raw_out(1); + } return nullptr; } +//------------------------------unique_loop_exit_or_null---------------------- +// Return the loop-exit projection if loop exit is unique. +IfFalseNode* IdealLoopTree::unique_loop_exit_proj_or_null() { + if (is_loop() && head()->is_BaseCountedLoop()) { + IfNode* loop_end = head()->as_BaseCountedLoop()->loopexit_or_null(); + if (loop_end == nullptr) { + return nullptr; // malformed loop shape + } + // Look for other loop exits. + assert(_phase->is_dominator(head(), tail()), "sanity"); + for (Node* ctrl = tail(); ctrl != head(); ctrl = ctrl->in(0)) { + assert(is_member(_phase->get_loop(ctrl)), "sanity"); + if (ctrl->is_If()) { + if (!is_loop_exit(ctrl->as_If())) { + continue; // local branch + } else if (ctrl != loop_end) { + return nullptr; // multiple loop exits + } + } else if (ctrl->is_Region()) { + return nullptr; // give up on control flow merges + } else if (ctrl->is_ReachabilityFence() || + ctrl->is_SafePoint() || + ctrl->is_MemBar() || + ctrl->Opcode() == Op_Blackhole) { + continue; // skip + } else if (ctrl->is_Proj()) { + if (ctrl->is_IfProj() || + ctrl->Opcode() == Op_SCMemProj || + ctrl->Opcode() == Op_Proj) { + continue; // skip simple control projections + } else if (ctrl->is_CatchProj() || + ctrl->is_JumpProj()) { + return nullptr; // give up on control flow splits + } else { + assert(false, "unknown control projection: %s", ctrl->Name()); + return nullptr; // stop on unknown control node + } + } else { + assert(false, "unknown CFG node: %s", ctrl->Name()); + return nullptr; // stop on unknown control node + } + } + assert(is_loop_exit(loop_end), "not a loop exit?"); + return loop_end->false_proj_or_null(); + } + return nullptr; // not found or multiple loop exits +} //============================================================================= @@ -3135,9 +3188,13 @@ static CountedLoopNode* locate_pre_from_main(CountedLoopNode* main_loop) { Node* ctrl = main_loop->skip_assertion_predicates_with_halt(); assert(ctrl->Opcode() == Op_IfTrue || ctrl->Opcode() == Op_IfFalse, ""); Node* iffm = ctrl->in(0); - assert(iffm->Opcode() == Op_If, ""); + assert(iffm->Opcode() == Op_If, "%s", iffm->Name()); Node* p_f = iffm->in(0); - assert(p_f->Opcode() == Op_IfFalse, ""); + // Skip ReachabilityFences hoisted out of pre-loop. + while (p_f->is_ReachabilityFence()) { + p_f = p_f->in(0); + } + assert(p_f->Opcode() == Op_IfFalse, "%s", p_f->Name()); CountedLoopNode* pre_loop = p_f->in(0)->as_CountedLoopEnd()->loopnode(); assert(pre_loop->is_pre_loop(), "No pre loop found"); return pre_loop; diff --git a/src/hotspot/share/opto/loopnode.cpp b/src/hotspot/share/opto/loopnode.cpp index 6963a67118f..35a9108892c 100644 --- a/src/hotspot/share/opto/loopnode.cpp +++ b/src/hotspot/share/opto/loopnode.cpp @@ -44,6 +44,7 @@ #include "opto/opaquenode.hpp" #include "opto/opcodes.hpp" #include "opto/predicates.hpp" +#include "opto/reachability.hpp" #include "opto/rootnode.hpp" #include "opto/runtime.hpp" #include "opto/vectorization.hpp" @@ -3934,6 +3935,7 @@ IdealLoopTree::IdealLoopTree(PhaseIdealLoop* phase, Node* head, Node* tail): _pa _has_range_checks(0), _has_range_checks_computed(0), _safepts(nullptr), _required_safept(nullptr), + _reachability_fences(nullptr), _allow_optimizations(true) { precond(_head != nullptr); precond(_tail != nullptr); @@ -4855,6 +4857,15 @@ uint IdealLoopTree::est_loop_flow_merge_sz() const { return 0; } +void IdealLoopTree::register_reachability_fence(ReachabilityFenceNode* rf) { + if (_reachability_fences == nullptr) { + _reachability_fences = new Node_List(); + } + if (!_reachability_fences->contains(rf)) { + _reachability_fences->push(rf); + } +} + #ifndef PRODUCT //------------------------------dump_head-------------------------------------- // Dump 1 liner for loop header info @@ -4914,6 +4925,9 @@ void IdealLoopTree::dump_head() { if (_has_call) tty->print(" has_call"); if (_has_sfpt) tty->print(" has_sfpt"); if (_rce_candidate) tty->print(" rce"); + if (_reachability_fences != nullptr && _reachability_fences->size() > 0) { + tty->print(" has_rf"); + } if (_safepts != nullptr && _safepts->size() > 0) { tty->print(" sfpts={"); _safepts->dump_simple(); tty->print(" }"); } @@ -4921,6 +4935,9 @@ void IdealLoopTree::dump_head() { tty->print(" req={"); _required_safept->dump_simple(); tty->print(" }"); } if (Verbose) { + if (_reachability_fences != nullptr && _reachability_fences->size() > 0) { + tty->print(" rfs={"); _reachability_fences->dump_simple(); tty->print(" }"); + } tty->print(" body={"); _body.dump_simple(); tty->print(" }"); } if (_head->is_Loop() && _head->as_Loop()->is_strip_mined()) { @@ -5179,12 +5196,14 @@ bool PhaseIdealLoop::process_expensive_nodes() { // Create a PhaseLoop. Build the ideal Loop tree. Map each Ideal Node to // its corresponding LoopNode. If 'optimize' is true, do some loop cleanups. void PhaseIdealLoop::build_and_optimize() { - assert(!C->post_loop_opts_phase(), "no loop opts allowed"); - bool do_split_ifs = (_mode == LoopOptsDefault); bool skip_loop_opts = (_mode == LoopOptsNone); bool do_max_unroll = (_mode == LoopOptsMaxUnroll); + bool do_verify = (_mode == LoopOptsVerify); + bool do_expand_reachability_fences = (_mode == PostLoopOptsExpandReachabilityFences); + assert(!C->post_loop_opts_phase() || do_expand_reachability_fences || do_verify, + "no loop opts allowed"); bool old_progress = C->major_progress(); uint orig_worklist_size = _igvn._worklist.size(); @@ -5251,11 +5270,13 @@ void PhaseIdealLoop::build_and_optimize() { BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2(); // Nothing to do, so get out - bool stop_early = !C->has_loops() && !skip_loop_opts && !do_split_ifs && !do_max_unroll && !_verify_me && - !_verify_only && !bs->is_gc_specific_loop_opts_pass(_mode); + bool stop_early = !C->has_loops() && !skip_loop_opts && !do_split_ifs && !do_max_unroll && + !do_expand_reachability_fences && !_verify_me && !_verify_only && + !bs->is_gc_specific_loop_opts_pass(_mode) ; bool do_expensive_nodes = C->should_optimize_expensive_nodes(_igvn); + bool do_optimize_reachability_fences = OptimizeReachabilityFences && (C->reachability_fences_count() > 0); bool strip_mined_loops_expanded = bs->strip_mined_loops_expanded(_mode); - if (stop_early && !do_expensive_nodes) { + if (stop_early && !do_expensive_nodes && !do_optimize_reachability_fences) { return; } @@ -5331,7 +5352,7 @@ void PhaseIdealLoop::build_and_optimize() { // Given early legal placement, try finding counted loops. This placement // is good enough to discover most loop invariants. - if (!_verify_me && !_verify_only && !strip_mined_loops_expanded) { + if (!_verify_me && !_verify_only && !strip_mined_loops_expanded && !do_expand_reachability_fences) { _ltree_root->counted_loop( this ); } @@ -5361,8 +5382,14 @@ void PhaseIdealLoop::build_and_optimize() { eliminate_useless_multiversion_if(); if (stop_early) { - assert(do_expensive_nodes, "why are we here?"); - if (process_expensive_nodes()) { + assert(do_expensive_nodes || do_optimize_reachability_fences, "why are we here?"); + // Use the opportunity to optimize reachability fence nodes irrespective of + // whether loop optimizations are performed or not. + if (do_optimize_reachability_fences && optimize_reachability_fences()) { + recompute_dom_depth(); + DEBUG_ONLY( if (VerifyLoopOptimizations) { verify(); } ); + } + if (do_expensive_nodes && process_expensive_nodes()) { // If we made some progress when processing expensive nodes then // the IGVN may modify the graph in a way that will allow us to // make some more progress: we need to try processing expensive @@ -5390,6 +5417,22 @@ void PhaseIdealLoop::build_and_optimize() { } #endif + if (do_optimize_reachability_fences && optimize_reachability_fences()) { + recompute_dom_depth(); + DEBUG_ONLY( if (VerifyLoopOptimizations) { verify(); } ); + } + + if (do_expand_reachability_fences) { + assert(C->post_loop_opts_phase(), "required"); + if (expand_reachability_fences()) { + recompute_dom_depth(); + DEBUG_ONLY( if (VerifyLoopOptimizations) { verify(); } ); + } + return; + } + + assert(!C->post_loop_opts_phase(), "required"); + if (skip_loop_opts) { C->restore_major_progress(old_progress); return; @@ -6286,6 +6329,8 @@ int PhaseIdealLoop::build_loop_tree_impl(Node* n, int pre_order) { // Record all safepoints in this loop. if (innermost->_safepts == nullptr) innermost->_safepts = new Node_List(); innermost->_safepts->push(n); + } else if (n->is_ReachabilityFence()) { + innermost->register_reachability_fence(n->as_ReachabilityFence()); } } } diff --git a/src/hotspot/share/opto/loopnode.hpp b/src/hotspot/share/opto/loopnode.hpp index 6667c71511c..26b82259327 100644 --- a/src/hotspot/share/opto/loopnode.hpp +++ b/src/hotspot/share/opto/loopnode.hpp @@ -44,6 +44,7 @@ class PredicateBlock; class PathFrequency; class PhaseIdealLoop; class LoopSelector; +class ReachabilityFenceNode; class UnswitchedLoopSelector; class VectorSet; class VSharedData; @@ -662,6 +663,7 @@ public: Node_List* _safepts; // List of safepoints in this loop Node_List* _required_safept; // A inner loop cannot delete these safepts; + Node_List* _reachability_fences; // List of reachability fences in this loop bool _allow_optimizations; // Allow loop optimizations IdealLoopTree(PhaseIdealLoop* phase, Node* head, Node* tail); @@ -720,6 +722,9 @@ public: // Check for Node being a loop-breaking test Node *is_loop_exit(Node *iff) const; + // Return unique loop-exit projection or null if the loop has multiple exits. + IfFalseNode* unique_loop_exit_proj_or_null(); + // Remove simplistic dead code from loop body void DCE_loop_body(); @@ -825,6 +830,9 @@ public: return _head->as_Loop()->is_strip_mined() ? _parent : this; } + // Registers a reachability fence node in the loop. + void register_reachability_fence(ReachabilityFenceNode* rf); + #ifndef PRODUCT void dump_head(); // Dump loop head only void dump(); // Dump this loop recursively @@ -1167,6 +1175,16 @@ public: forward_ctrl(old_node, new_node); } + void remove_dead_data_node(Node* dead) { + assert(dead->outcnt() == 0 && !dead->is_top(), "must be dead"); + assert(!dead->is_CFG(), "not a data node"); + Node* c = get_ctrl(dead); + IdealLoopTree* lpt = get_loop(c); + _loop_or_ctrl.map(dead->_idx, nullptr); // This node is useless + lpt->_body.yank(dead); + igvn().remove_dead_node(dead, PhaseIterGVN::NodeOrigin::Graph); + } + private: // Place 'n' in some loop nest, where 'n' is a CFG node @@ -1599,6 +1617,15 @@ public: // Implementation of the loop predication to promote checks outside the loop bool loop_predication_impl(IdealLoopTree *loop); + // Reachability Fence (RF) support. + private: + void insert_rf(Node* ctrl, Node* referent); + void replace_rf(Node* old_node, Node* new_node); + void remove_rf(ReachabilityFenceNode* rf); + public: + bool optimize_reachability_fences(); + bool expand_reachability_fences(); + private: bool loop_predication_impl_helper(IdealLoopTree* loop, IfProjNode* if_success_proj, ParsePredicateSuccessProj* parse_predicate_proj, CountedLoopNode* cl, ConNode* zero, diff --git a/src/hotspot/share/opto/macro.cpp b/src/hotspot/share/opto/macro.cpp index 01c67187883..8c5dbe7fb48 100644 --- a/src/hotspot/share/opto/macro.cpp +++ b/src/hotspot/share/opto/macro.cpp @@ -44,6 +44,7 @@ #include "opto/node.hpp" #include "opto/opaquenode.hpp" #include "opto/phaseX.hpp" +#include "opto/reachability.hpp" #include "opto/rootnode.hpp" #include "opto/runtime.hpp" #include "opto/subnode.hpp" @@ -683,6 +684,8 @@ bool PhaseMacroExpand::can_eliminate_allocation(PhaseIterGVN* igvn, AllocateNode use->as_ArrayCopy()->is_copyofrange_validated()) && use->in(ArrayCopyNode::Dest) == res) { // ok to eliminate + } else if (use->is_ReachabilityFence() && OptimizeReachabilityFences) { + // ok to eliminate } else if (use->is_SafePoint()) { SafePointNode* sfpt = use->as_SafePoint(); if (sfpt->is_Call() && sfpt->as_Call()->has_non_debug_use(res)) { @@ -778,7 +781,13 @@ void PhaseMacroExpand::undo_previous_scalarizations(GrowableArray 0) { SafePointNode* sfpt_done = safepoints_done.pop(); + + SafePointNode::NodeEdgeTempStorage non_debug_edges_worklist(igvn()); + + sfpt_done->remove_non_debug_edges(non_debug_edges_worklist); + // remove any extra entries we added to the safepoint + assert(sfpt_done->jvms()->endoff() == sfpt_done->req(), "no extra edges past debug info allowed"); uint last = sfpt_done->req() - 1; for (int k = 0; k < nfields; k++) { sfpt_done->del_req(last--); @@ -799,6 +808,9 @@ void PhaseMacroExpand::undo_previous_scalarizations(GrowableArray restore_non_debug_edges(non_debug_edges_worklist); + _igvn._worklist.push(sfpt_done); } } @@ -839,6 +851,8 @@ void PhaseMacroExpand::undo_previous_scalarizations(GrowableArray jvms()->endoff() == sfpt->req(), "no extra edges past debug info allowed"); + // Fields of scalar objs are referenced only at the end // of regular debuginfo at the last (youngest) JVMS. // Record relative start index. @@ -964,17 +978,25 @@ SafePointScalarObjectNode* PhaseMacroExpand::create_scalarized_object_descriptio } // Do scalar replacement. -bool PhaseMacroExpand::scalar_replacement(AllocateNode *alloc, GrowableArray & safepoints) { - GrowableArray safepoints_done; +bool PhaseMacroExpand::scalar_replacement(AllocateNode* alloc, GrowableArray& safepoints) { + GrowableArray safepoints_done; Node* res = alloc->result_cast(); assert(res == nullptr || res->is_CheckCastPP(), "unexpected AllocateNode result"); // Process the safepoint uses while (safepoints.length() > 0) { SafePointNode* sfpt = safepoints.pop(); + + SafePointNode::NodeEdgeTempStorage non_debug_edges_worklist(igvn()); + + // All sfpt inputs are implicitly included into debug info during the scalarization process below. + // Keep non-debug inputs separately, so they stay non-debug. + sfpt->remove_non_debug_edges(non_debug_edges_worklist); + SafePointScalarObjectNode* sobj = create_scalarized_object_description(alloc, sfpt); if (sobj == nullptr) { + sfpt->restore_non_debug_edges(non_debug_edges_worklist); undo_previous_scalarizations(safepoints_done, alloc); return false; } @@ -983,6 +1005,8 @@ bool PhaseMacroExpand::scalar_replacement(AllocateNode *alloc, GrowableArray jvms(); sfpt->replace_edges_in_range(res, sobj, jvms->debug_start(), jvms->debug_end(), &_igvn); + non_debug_edges_worklist.remove_edge_if_present(res); // drop scalarized input from non-debug info + sfpt->restore_non_debug_edges(non_debug_edges_worklist); _igvn._worklist.push(sfpt); // keep it for rollback @@ -1073,6 +1097,8 @@ void PhaseMacroExpand::process_users_of_allocation(CallNode *alloc) { } } _igvn._worklist.push(ac); + } else if (use->is_ReachabilityFence() && OptimizeReachabilityFences) { + use->as_ReachabilityFence()->clear_referent(_igvn); // redundant fence; will be removed during IGVN } else { eliminate_gc_barrier(use); } diff --git a/src/hotspot/share/opto/memnode.cpp b/src/hotspot/share/opto/memnode.cpp index 9ec3402c701..c7fe4508473 100644 --- a/src/hotspot/share/opto/memnode.cpp +++ b/src/hotspot/share/opto/memnode.cpp @@ -4081,7 +4081,7 @@ uint LoadStoreNode::ideal_reg() const { bool LoadStoreNode::result_not_used() const { for (DUIterator_Fast imax, i = fast_outs(imax); i < imax; i++) { Node *x = fast_out(i); - if (x->Opcode() == Op_SCMemProj) { + if (x->Opcode() == Op_SCMemProj || x->is_ReachabilityFence()) { continue; } if (x->bottom_type() == TypeTuple::MEMBAR && diff --git a/src/hotspot/share/opto/node.cpp b/src/hotspot/share/opto/node.cpp index cb5795a1250..3eafd97d7c1 100644 --- a/src/hotspot/share/opto/node.cpp +++ b/src/hotspot/share/opto/node.cpp @@ -38,6 +38,7 @@ #include "opto/matcher.hpp" #include "opto/node.hpp" #include "opto/opcodes.hpp" +#include "opto/reachability.hpp" #include "opto/regmask.hpp" #include "opto/rootnode.hpp" #include "opto/type.hpp" @@ -503,6 +504,9 @@ Node *Node::clone() const { if (is_expensive()) { C->add_expensive_node(n); } + if (is_ReachabilityFence()) { + C->add_reachability_fence(n->as_ReachabilityFence()); + } if (for_post_loop_opts_igvn()) { // Don't add cloned node to Compile::_for_post_loop_opts_igvn list automatically. // If it is applicable, it will happen anyway when the cloned node is registered with IGVN. @@ -622,6 +626,9 @@ void Node::destruct(PhaseValues* phase) { if (is_expensive()) { compile->remove_expensive_node(this); } + if (is_ReachabilityFence()) { + compile->remove_reachability_fence(as_ReachabilityFence()); + } if (is_OpaqueTemplateAssertionPredicate()) { compile->remove_template_assertion_predicate_opaque(as_OpaqueTemplateAssertionPredicate()); } @@ -2994,6 +3001,25 @@ 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_CallLeafPure(); } +//--------------------------has_non_debug_uses------------------------------ +// Checks whether the node has any non-debug uses or not. +bool Node::has_non_debug_uses() const { + for (DUIterator_Fast imax, i = fast_outs(imax); i < imax; i++) { + Node* u = fast_out(i); + if (u->is_SafePoint()) { + if (u->is_Call() && u->as_Call()->has_non_debug_use(this)) { + return true; + } + // Non-call safepoints have only debug uses. + } else if (u->is_ReachabilityFence()) { + // Reachability fence is treated as debug use. + } else { + return true; // everything else is conservatively treated as non-debug use + } + } + return false; // no non-debug uses found +} + //============================================================================= //------------------------------yank------------------------------------------- // Find and remove diff --git a/src/hotspot/share/opto/node.hpp b/src/hotspot/share/opto/node.hpp index 46b89aa2c5f..36855d659ba 100644 --- a/src/hotspot/share/opto/node.hpp +++ b/src/hotspot/share/opto/node.hpp @@ -168,6 +168,7 @@ class Pipeline; class PopulateIndexNode; class ProjNode; class RangeCheckNode; +class ReachabilityFenceNode; class ReductionNode; class RegMask; class RegionNode; @@ -452,6 +453,9 @@ public: // Check whether node has become unreachable bool is_unreachable(PhaseIterGVN &igvn) const; + // Does the node have any immediate non-debug uses? + bool has_non_debug_uses() const; + // Set a required input edge, also updates corresponding output edge void add_req( Node *n ); // Append a NEW required input void add_req( Node *n0, Node *n1 ) { @@ -824,6 +828,7 @@ public: DEFINE_CLASS_ID(Move, Node, 20) DEFINE_CLASS_ID(LShift, Node, 21) DEFINE_CLASS_ID(Neg, Node, 22) + DEFINE_CLASS_ID(ReachabilityFence, Node, 23) _max_classes = ClassMask_Neg }; @@ -1013,6 +1018,7 @@ public: DEFINE_CLASS_QUERY(PCTable) DEFINE_CLASS_QUERY(Phi) DEFINE_CLASS_QUERY(Proj) + DEFINE_CLASS_QUERY(ReachabilityFence) DEFINE_CLASS_QUERY(Reduction) DEFINE_CLASS_QUERY(Region) DEFINE_CLASS_QUERY(Root) diff --git a/src/hotspot/share/opto/parse.hpp b/src/hotspot/share/opto/parse.hpp index 42f44f0f7ea..5118019fc31 100644 --- a/src/hotspot/share/opto/parse.hpp +++ b/src/hotspot/share/opto/parse.hpp @@ -356,6 +356,7 @@ class Parse : public GraphKit { bool _wrote_stable; // Did we write a @Stable field? bool _wrote_fields; // Did we write any field? Node* _alloc_with_final_or_stable; // An allocation node with final or @Stable field + Node* _stress_rf_hook; // StressReachabilityFences support // Variables which track Java semantics during bytecode parsing: diff --git a/src/hotspot/share/opto/parse1.cpp b/src/hotspot/share/opto/parse1.cpp index 683633f6355..6a400631bff 100644 --- a/src/hotspot/share/opto/parse1.cpp +++ b/src/hotspot/share/opto/parse1.cpp @@ -369,6 +369,15 @@ void Parse::load_interpreter_state(Node* osr_buf) { continue; } set_local(index, check_interpreter_type(l, type, bad_type_exit)); + if (StressReachabilityFences && type->isa_oopptr() != nullptr) { + // Keep all oop locals alive until the method returns as if there are + // reachability fences for them at the end of the method. + Node* loc = local(index); + if (loc->bottom_type() != TypePtr::NULL_PTR) { + assert(loc->bottom_type()->isa_oopptr() != nullptr, "%s", Type::str(loc->bottom_type())); + _stress_rf_hook->add_req(loc); + } + } } for (index = 0; index < sp(); index++) { @@ -377,6 +386,15 @@ void Parse::load_interpreter_state(Node* osr_buf) { if (l->is_top()) continue; // nothing here const Type *type = osr_block->stack_type_at(index); set_stack(index, check_interpreter_type(l, type, bad_type_exit)); + if (StressReachabilityFences && type->isa_oopptr() != nullptr) { + // Keep all oops on stack alive until the method returns as if there are + // reachability fences for them at the end of the method. + Node* stk = stack(index); + if (stk->bottom_type() != TypePtr::NULL_PTR) { + assert(stk->bottom_type()->isa_oopptr() != nullptr, "%s", Type::str(stk->bottom_type())); + _stress_rf_hook->add_req(stk); + } + } } if (bad_type_exit->control()->req() > 1) { @@ -411,6 +429,7 @@ Parse::Parse(JVMState* caller, ciMethod* parse_method, float expected_uses) _wrote_stable = false; _wrote_fields = false; _alloc_with_final_or_stable = nullptr; + _stress_rf_hook = (StressReachabilityFences ? new Node(1) : nullptr); _block = nullptr; _first_return = true; _replaced_nodes_for_exceptions = false; @@ -642,6 +661,11 @@ Parse::Parse(JVMState* caller, ciMethod* parse_method, float expected_uses) if (log) log->done("parse nodes='%d' live='%d' memory='%zu'", C->unique(), C->live_nodes(), C->node_arena()->used()); + + if (StressReachabilityFences) { + _stress_rf_hook->destruct(&_gvn); + _stress_rf_hook = nullptr; + } } //---------------------------do_all_blocks------------------------------------- @@ -1194,6 +1218,14 @@ SafePointNode* Parse::create_entry_map() { return entry_map; } +//-----------------------is_auto_boxed_primitive------------------------------ +// Helper method to detect auto-boxed primitives (result of valueOf() call). +static bool is_auto_boxed_primitive(Node* n) { + return (n->is_Proj() && n->as_Proj()->_con == TypeFunc::Parms && + n->in(0)->is_CallJava() && + n->in(0)->as_CallJava()->method()->is_boxing_method()); +} + //-----------------------------do_method_entry-------------------------------- // Emit any code needed in the pseudo-block before BCI zero. // The main thing to do is lock the receiver of a synchronized method. @@ -1207,6 +1239,19 @@ void Parse::do_method_entry() { make_dtrace_method_entry(method()); } + if (StressReachabilityFences) { + // Keep all oop arguments alive until the method returns as if there are + // reachability fences for them at the end of the method. + int max_locals = jvms()->loc_size(); + for (int idx = 0; idx < max_locals; idx++) { + Node* loc = local(idx); + if (loc->bottom_type()->isa_oopptr() != nullptr && + !is_auto_boxed_primitive(loc)) { // ignore auto-boxed primitives + _stress_rf_hook->add_req(loc); + } + } + } + #ifdef ASSERT // Narrow receiver type when it is too broad for the method being parsed. if (!method()->is_static()) { @@ -2197,6 +2242,15 @@ void Parse::return_current(Node* value) { call_register_finalizer(); } + if (StressReachabilityFences) { + // Insert reachability fences for all oop arguments at the end of the method. + for (uint i = 1; i < _stress_rf_hook->req(); i++) { + Node* referent = _stress_rf_hook->in(i); + assert(referent->bottom_type()->isa_oopptr(), "%s", Type::str(referent->bottom_type())); + insert_reachability_fence(referent); + } + } + // Do not set_parse_bci, so that return goo is credited to the return insn. set_bci(InvocationEntryBci); if (method()->is_synchronized()) { diff --git a/src/hotspot/share/opto/phase.cpp b/src/hotspot/share/opto/phase.cpp index 5603033ce69..3f1866990e2 100644 --- a/src/hotspot/share/opto/phase.cpp +++ b/src/hotspot/share/opto/phase.cpp @@ -90,6 +90,9 @@ void Phase::print_timers() { tty->print_cr (" Prune Useless: %7.3f s", timers[_t_vector_pru].seconds()); tty->print_cr (" Renumber Live: %7.3f s", timers[_t_renumberLive].seconds()); tty->print_cr (" IdealLoop: %7.3f s", timers[_t_idealLoop].seconds()); + tty->print_cr (" ReachabilityFence: %7.3f s", timers[_t_reachability].seconds()); + tty->print_cr (" Optimize: %7.3f s", timers[_t_reachability_optimize].seconds()); + tty->print_cr (" Expand: %7.3f s", timers[_t_reachability_expand].seconds()); tty->print_cr (" AutoVectorize: %7.3f s", timers[_t_autoVectorize].seconds()); tty->print_cr (" IdealLoop Verify: %7.3f s", timers[_t_idealLoopVerify].seconds()); tty->print_cr (" Cond Const Prop: %7.3f s", timers[_t_ccp].seconds()); diff --git a/src/hotspot/share/opto/phase.hpp b/src/hotspot/share/opto/phase.hpp index 6700df6ec17..5bd3c34f15f 100644 --- a/src/hotspot/share/opto/phase.hpp +++ b/src/hotspot/share/opto/phase.hpp @@ -85,6 +85,9 @@ public: f( _t_vector_pru, "vector_pru") \ f( _t_renumberLive, "") \ f( _t_idealLoop, "idealLoop") \ + f( _t_reachability, "reachabilityFence") \ + f( _t_reachability_optimize, "reachabilityFence_optimize") \ + f( _t_reachability_expand, "reachabilityFence_expand") \ f( _t_autoVectorize, "autoVectorize") \ f( _t_idealLoopVerify, "idealLoopVerify") \ f( _t_ccp, "ccp") \ diff --git a/src/hotspot/share/opto/phasetype.hpp b/src/hotspot/share/opto/phasetype.hpp index ce432fbfc01..2b599ace03a 100644 --- a/src/hotspot/share/opto/phasetype.hpp +++ b/src/hotspot/share/opto/phasetype.hpp @@ -106,6 +106,7 @@ flags(PHASEIDEALLOOP1, "PhaseIdealLoop 1") \ flags(PHASEIDEALLOOP2, "PhaseIdealLoop 2") \ flags(PHASEIDEALLOOP3, "PhaseIdealLoop 3") \ + flags(EXPAND_REACHABILITY_FENCES, "Expand Reachability Fences") \ flags(AUTO_VECTORIZATION1_BEFORE_APPLY, "AutoVectorization 1, before Apply") \ flags(AUTO_VECTORIZATION3_AFTER_ADJUST_LIMIT, "AutoVectorization 2, after Adjusting Pre-loop Limit") \ flags(AUTO_VECTORIZATION4_AFTER_SPECULATIVE_RUNTIME_CHECKS, "AutoVectorization 3, after Adding Speculative Runtime Checks") \ diff --git a/src/hotspot/share/opto/reachability.cpp b/src/hotspot/share/opto/reachability.cpp new file mode 100644 index 00000000000..b45b340ab85 --- /dev/null +++ b/src/hotspot/share/opto/reachability.cpp @@ -0,0 +1,512 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 "opto/c2_MacroAssembler.hpp" +#include "opto/callnode.hpp" +#include "opto/compile.hpp" +#include "opto/loopnode.hpp" +#include "opto/phaseX.hpp" +#include "opto/reachability.hpp" +#include "opto/regalloc.hpp" +#include "opto/runtime.hpp" +#include "utilities/pair.hpp" + +/* + * java.lang.ref.Reference::reachabilityFence support. + * + * Reachability Fence (RF) ensures that the given object (referent) remains strongly reachable + * regardless of any optimizing transformations the virtual machine may perform that might otherwise + * allow the object to become unreachable. + * + * RFs are intended to be used in performance-critical code, so the primary goal for C2 support is + * to reduce their runtime overhead as much as possible. + * + * Reference::reachabilityFence() calls are intrinsified into ReachabilityFence CFG nodes. RF node keeps + * its referent alive, so the referent's location is recorded at every safepoint (in its oop map) which + * interferes with referent's live range. + * + * It is tempting to directly attach referents to interfering safepoints right from the beginning, but it + * doesn't play well with some optimizations C2 does (e.g., during loop-invariant code motion a safepoint + * can become interfering once a load is hoisted). + * + * Instead, reachability representation transitions through multiple phases: + * (0) initial set of RFs is materialized during parsing (as a result of + * Reference.reachabilityFence intrinsification); + * (1) optimization pass during loop opts eliminates redundant RF nodes and + * moves the ones with loop-invariant referents outside (after) loops; + * (2) after loop opts are over, RF nodes are eliminated and their referents are transferred to + * safepoint nodes (appended as edges after debug info); + * (3) during final graph reshaping, referent edges are removed from safepoints and materialized as RF nodes + * attached to their safepoint node (closely following it in CFG graph). + * + * Some implementation considerations. + * + * (a) It looks attractive to get rid of RF nodes early and transfer to safepoint-attached representation, + * but it is not correct until loop opts are done. + * + * Live ranges of values are routinely extended during loop opts. And it can break the invariant that + * all interfering safepoints contain the referent in their oop map. (If an interfering safepoint doesn't + * keep the referent alive, then it becomes possible for the referent to be prematurely GCed.) + * + * compiler/c2/TestReachabilityFence.java demonstrates a situation where a load is hoisted out of a loop thus + * extending the live range of the value it produces beyond the safepoint on loop-back edge. + * + * After loop opts are over, it becomes possible to reliably enumerate all interfering safepoints and + * to ensure that the referent is present in their oop maps. Current assumption is that after loop opts the IR graph + * is stable enough, so relative order of memory operations and safepoints is preserved and only safepoints between + * a referent and it's uses are taken into account. A more conservative analysis can be employed -- any safepoint dominated + * by a referent is treated as interfering with it -- if it turns out that the assumption doesn't hold. + * + * (b) RF nodes may interfere with Register Allocator (RA). If a safepoint is pruned during macro expansion, + * it can make some RF nodes redundant, but we don't have information about their relations anymore to detect that. + * Redundant RF node unnecessarily extends referent's live range and increases register pressure. + * + * Hence, we eliminate RF nodes and transfer their referents to corresponding safepoints (phase #2). + * When safepoints are pruned, corresponding reachability edges also go away. + * + * (c) Unfortunately, it's not straightforward to stay with safepoint-attached representation till the very end, + * because information about derived oops is attached to safepoints in a similar way. So, for now RFs are + * rematerialized at safepoints before RA (phase #3). + */ + +bool ReachabilityFenceNode::is_redundant(PhaseGVN& gvn) { + const Type* referent_t = gvn.type(referent()); + if (referent_t == TypePtr::NULL_PTR) { + return true; // no-op fence: null referent + } + if (!OptimizeReachabilityFences) { + return false; // keep reachability fence nodes intact + } + if (!PreserveReachabilityFencesOnConstants && referent_t->singleton()) { + return true; // no-op fence: constants are strongly reachable + } + return false; +} + +Node* ReachabilityFenceNode::Ideal(PhaseGVN* phase, bool can_reshape) { + return (remove_dead_region(phase, can_reshape) ? this : nullptr); +} + +Node* ReachabilityFenceNode::Identity(PhaseGVN* phase) { + if (is_redundant(*phase)) { + return in(0); + } + return this; +} + +// Turn the RF node into a no-op by setting its referent to null. +// Subsequent IGVN pass removes cleared nodes. +bool ReachabilityFenceNode::clear_referent(PhaseIterGVN& phase) { + if (phase.type(referent()) == TypePtr::NULL_PTR) { + return false; + } else { + phase.replace_input_of(this, 1, phase.makecon(TypePtr::NULL_PTR)); + return true; + } +} + +#ifndef PRODUCT +static void rf_desc(outputStream* st, const ReachabilityFenceNode* rf, PhaseRegAlloc* ra) { + char buf[50]; + ra->dump_register(rf->referent(), buf, sizeof(buf)); + st->print("reachability fence [%s]", buf); +} + +void ReachabilityFenceNode::format(PhaseRegAlloc* ra, outputStream* st) const { + rf_desc(st, this, ra); +} + +void ReachabilityFenceNode::emit(C2_MacroAssembler* masm, PhaseRegAlloc* ra) const { + ResourceMark rm; + stringStream ss; + rf_desc(&ss, this, ra); + const char* desc = masm->code_string(ss.freeze()); + masm->block_comment(desc); +} +#endif + +// Detect safepoint nodes which are important for reachability tracking purposes. +// Some SafePoint nodes can't affect referent's reachability in any noticeable way and +// can be safely ignored during the analysis. +static bool is_interfering_sfpt_candidate(SafePointNode* sfpt) { + if (sfpt->jvms() == nullptr) { + return false; // not a real safepoint + } else if (sfpt->is_CallStaticJava() && sfpt->as_CallStaticJava()->is_uncommon_trap()) { + return false; // uncommon traps are exit points + } + return true; // a full-blown safepoint can interfere with a reachability fence and its referent +} + +void PhaseIdealLoop::insert_rf(Node* ctrl, Node* referent) { + IdealLoopTree* lpt = get_loop(ctrl); + Node* ctrl_end = ctrl->unique_ctrl_out(); + + auto new_rf = new ReachabilityFenceNode(C, ctrl, referent); + + register_control(new_rf, lpt, ctrl); + set_idom(new_rf, ctrl, dom_depth(ctrl) + 1); + lpt->register_reachability_fence(new_rf); + + igvn().rehash_node_delayed(ctrl_end); + ctrl_end->replace_edge(ctrl, new_rf); + + if (idom(ctrl_end) == ctrl) { + set_idom(ctrl_end, new_rf, dom_depth(new_rf) + 1); + } else { + assert(ctrl_end->is_Region(), ""); + } +} + +void PhaseIdealLoop::replace_rf(Node* old_node, Node* new_node) { + assert(old_node->is_ReachabilityFence() || + (old_node->is_Proj() && old_node->in(0)->is_ReachabilityFence()), + "%s", NodeClassNames[old_node->Opcode()]); + + IdealLoopTree* lpt = get_loop(old_node); + lpt->_body.yank(old_node); + assert(lpt->_reachability_fences != nullptr, "missing"); + assert(lpt->_reachability_fences->contains(old_node), "missing"); + lpt->_reachability_fences->yank(old_node); + replace_node_and_forward_ctrl(old_node, new_node); +} + +void PhaseIdealLoop::remove_rf(ReachabilityFenceNode* rf) { + Node* rf_ctrl_in = rf->in(0); + Node* referent = rf->referent(); + if (rf->clear_referent(igvn()) && referent->outcnt() == 0) { + remove_dead_data_node(referent); + } + replace_rf(rf, rf_ctrl_in); +} + +//====================================================================== +//---------------------------- Phase 1 --------------------------------- +// Optimization pass over reachability fences during loop opts. +// Moves RFs with loop-invariant referents out of the loop. +bool PhaseIdealLoop::optimize_reachability_fences() { + Compile::TracePhase tp(_t_reachability_optimize); + + assert(OptimizeReachabilityFences, "required"); + + // ResourceMark rm; // NB! not safe because insert_rf may trigger _idom reallocation + Unique_Node_List redundant_rfs; + typedef Pair LoopExit; + GrowableArray worklist; + + for (int i = 0; i < C->reachability_fences_count(); i++) { + ReachabilityFenceNode* rf = C->reachability_fence(i); + assert(!rf->is_redundant(igvn()), "required"); + // Move RFs out of counted loops when possible. + IdealLoopTree* lpt = get_loop(rf); + Node* referent = rf->referent(); + if (lpt->is_invariant(referent)) { + IfFalseNode* unique_loop_exit = lpt->unique_loop_exit_proj_or_null(); + if (unique_loop_exit != nullptr) { + // Skip over an outer strip-mined loop. + if (!lpt->is_root()) { + IdealLoopTree* outer_lpt = lpt->_parent; + if (outer_lpt->head()->is_OuterStripMinedLoop()) { + if (outer_lpt->is_invariant(referent)) { + IfNode* outer_loop_end = outer_lpt->head()->as_OuterStripMinedLoop()->outer_loop_end(); + if (outer_loop_end != nullptr && outer_loop_end->false_proj_or_null() != nullptr) { + unique_loop_exit = outer_loop_end->false_proj_or_null(); + } + } else { + // An attempt to insert an RF node inside outer strip-mined loop breaks + // its IR invariants and manifests as assertion failures. + assert(false, "not loop invariant in outer strip-mined loop"); + continue; // skip + } + } + } + + LoopExit p(referent, unique_loop_exit); + worklist.push(p); + redundant_rfs.push(rf); + +#ifndef PRODUCT + if (TraceLoopOpts) { + IdealLoopTree* loop = get_loop(unique_loop_exit->in(0)); + tty->print_cr("ReachabilityFence: N%d: %s N%d/N%d -> loop exit N%d (%s N%d/N%d)", + rf->_idx, lpt->head()->Name(), lpt->head()->_idx, lpt->tail()->_idx, + unique_loop_exit->_idx, + loop->head()->Name(), loop->head()->_idx, loop->tail()->_idx); + } +#endif // !PRODUCT + } + } + } + + // Populate RFs outside loops. + while (worklist.is_nonempty()) { + LoopExit p = worklist.pop(); + Node* referent = p.first; + Node* ctrl_out = p.second; + insert_rf(ctrl_out, referent); + } + + // Eliminate redundant RFs. + bool progress = (redundant_rfs.size() > 0); + while (redundant_rfs.size() > 0) { + remove_rf(redundant_rfs.pop()->as_ReachabilityFence()); + } + + return progress; +} + +//====================================================================== +//---------------------------- Phase 2 --------------------------------- + +// Linearly traverse CFG upwards starting at ctrl_start until first merge point. +// All encountered safepoints are recorded in safepoints list, except +// the ones filtered out by is_interfering_sfpt_candidate(). +static void enumerate_interfering_sfpts_linear_traversal(Node* ctrl_start, Node_Stack& stack, VectorSet& visited, + Node_List& interfering_sfpts) { + for (Node* ctrl = ctrl_start; ctrl != nullptr; ctrl = ctrl->in(0)) { + assert(ctrl->is_CFG(), ""); + if (visited.test_set(ctrl->_idx)) { + return; + } else { + if (ctrl->is_Region()) { + stack.push(ctrl, 1); + return; // stop at merge points + } else if (ctrl->is_SafePoint() && is_interfering_sfpt_candidate(ctrl->as_SafePoint())) { + assert(!ctrl->is_CallStaticJava() || !ctrl->as_CallStaticJava()->is_uncommon_trap(), + "uncommon traps should not be enumerated"); + interfering_sfpts.push(ctrl); + } + } + } +} + +// Enumerate all safepoints which are reachable from the RF to its referent through CFG. +// Start at RF node and traverse CFG upwards until referent's control node is reached. +static void enumerate_interfering_sfpts(ReachabilityFenceNode* rf, PhaseIdealLoop* phase, + Node_Stack& stack, VectorSet& visited, + Node_List& interfering_sfpts) { + assert(stack.is_empty(), "required"); + assert(visited.is_empty(), "required"); + + Node* referent = rf->referent(); + Node* referent_ctrl = phase->get_ctrl(referent); + assert(phase->is_dominator(referent_ctrl, rf), "sanity"); + + visited.set(referent_ctrl->_idx); // end point + enumerate_interfering_sfpts_linear_traversal(rf, stack, visited, interfering_sfpts); // starting point in CFG + while (stack.is_nonempty()) { + Node* cur = stack.node(); + uint idx = stack.index(); + + assert(cur != nullptr, ""); + assert(cur->is_Region(), "%s", NodeClassNames[cur->Opcode()]); + assert(phase->is_dominator(referent_ctrl, cur), ""); + assert(idx > 0 && idx <= cur->req(), "%d %d", idx, cur->req()); + + if (idx < cur->req()) { + stack.set_index(idx + 1); + enumerate_interfering_sfpts_linear_traversal(cur->in(idx), stack, visited, interfering_sfpts); + } else { + stack.pop(); + } + } + // Reset temporary structures to their initial state. + assert(stack.is_empty(), "required"); + visited.clear(); +} + +// Start offset for reachability info on a safepoint node. +static uint rf_base_offset(SafePointNode* sfpt) { + return sfpt->jvms()->debug_end(); +} + +static bool dominates_another_rf(ReachabilityFenceNode* rf, PhaseIdealLoop* phase) { + assert(!rf->is_redundant(phase->igvn()), ""); + + for (int i = 0; i < phase->C->reachability_fences_count(); i++) { + ReachabilityFenceNode* other_rf = phase->C->reachability_fence(i); + assert(other_rf->outcnt() > 0, "dead node"); + if (rf != other_rf && rf->referent()->eqv_uncast(other_rf->referent()) && + phase->is_dominator(rf, other_rf)) { + return true; // dominates another reachability fence with the same referent + } + } + return false; +} + +// Phase 2: migrate reachability info to safepoints. +// All RFs are replaced with edges from corresponding referents to interfering safepoints. +// Interfering safepoints are safepoint nodes which are reachable from the RF to its referent through CFG. +bool PhaseIdealLoop::expand_reachability_fences() { + Compile::TracePhase tp(_t_reachability_expand); + + assert(OptimizeReachabilityFences, "required"); + assert(C->post_loop_opts_phase(), "required"); + DEBUG_ONLY( int no_of_constant_rfs = 0; ) + + ResourceMark rm; + Unique_Node_List for_removal; + typedef Pair ReachabilityEdge; + GrowableArray reachability_edges; + { + // Reuse temporary structures to avoid allocating them for every single RF node. + Node_List sfpt_worklist; + Node_Stack stack(0); + VectorSet visited; + + for (int i = 0; i < C->reachability_fences_count(); i++) { + ReachabilityFenceNode* rf = C->reachability_fence(i); + assert(!rf->is_redundant(igvn()), "missed"); + if (PreserveReachabilityFencesOnConstants) { + const Type* referent_t = igvn().type(rf->referent()); + assert(referent_t != TypePtr::NULL_PTR, "redundant rf"); + bool is_constant_rf = referent_t->singleton(); + if (is_constant_rf) { + DEBUG_ONLY( no_of_constant_rfs += 1; ) + continue; // leave RFs on constants intact + } + } + if (dominates_another_rf(rf, this)) { + // Redundant fence: dominates another RF with the same referent. + // RF is redundant for some referent oop when the referent has another RF which + // keeps it alive across the RF. In terms of dominance relation it can be formulated + // as "a referent has another RF which is dominated by the redundant RF". + // + // NB! It is safe to assume that dominating RF is redundant only during expansion. + // Otherwise, there's a chance for the superseding RF node to go away before expansion. + // Non-RF users are ignored for a similar reason: they can go away before or after expansion + // takes place, so no guarantees reachability information is preserved. + } else { + assert(sfpt_worklist.size() == 0, "not empty"); + enumerate_interfering_sfpts(rf, this, stack, visited, sfpt_worklist); + + Node* referent = rf->referent(); + while (sfpt_worklist.size() > 0) { + SafePointNode* sfpt = sfpt_worklist.pop()->as_SafePoint(); + assert(is_dominator(get_ctrl(referent), sfpt), ""); + assert(sfpt->req() == rf_base_offset(sfpt), "no extra edges allowed"); + if (sfpt->find_edge(referent) == -1) { + ReachabilityEdge p(sfpt, referent); + reachability_edges.push(p); + } + } + } + for_removal.push(rf); + } + } + // Materialize reachability edges. + while (reachability_edges.length() > 0) { + ReachabilityEdge p = reachability_edges.pop(); + SafePointNode* sfpt = p.first; + Node* referent = p.second; + if (sfpt->find_edge(referent) == -1) { + sfpt->add_req(referent); + igvn()._worklist.push(sfpt); + } + } + // Eliminate processed RFs. They become redundant once reachability edges are added. + bool progress = (for_removal.size() > 0); + while (for_removal.size() > 0) { + remove_rf(for_removal.pop()->as_ReachabilityFence()); + } + + assert(C->reachability_fences_count() == no_of_constant_rfs, ""); + return progress; +} + +//====================================================================== +//---------------------------- Phase 3 --------------------------------- + +// Find a point in CFG right after safepoint node to insert reachability fence. +static Node* sfpt_ctrl_out(SafePointNode* sfpt) { + if (sfpt->is_Call()) { + CallProjections callprojs; + sfpt->as_Call()->extract_projections(&callprojs, + false /*separate_io_proj*/, + false /*do_asserts*/, + true /*allow_handlers*/); + // Calls can have multiple control projections. However, reachability edge expansion + // happens during final graph reshaping which is performed very late in compilation pipeline. + // The assumption here is that the control path chosen for insertion can't go away. + // So, materializing a reachability fence on a single control path produced by a call + // is enough to keep the referent oop alive across the call. + if (callprojs.fallthrough_catchproj != nullptr) { + return callprojs.fallthrough_catchproj; + } else if (callprojs.catchall_catchproj != nullptr) { + return callprojs.catchall_catchproj; // rethrow stub + } else if (callprojs.fallthrough_proj != nullptr) { + return callprojs.fallthrough_proj; // no exceptions thrown + } else { + ShouldNotReachHere(); + } + } else { + return sfpt; + } +} + +// Phase 3: materialize reachability fences from reachability edges on safepoints. +// Turn extra safepoint edges into reachability fences immediately following the safepoint. +// +// NB! As of now, a special care is needed to properly enumerate reachability edges because +// there are other use cases for non-debug safepoint edges. expand_reachability_edges() runs +// after macro expansion where runtime calls during array allocation are annotated with +// valid_length_test_input as an extra edges. Until there's a mechanism to distinguish between +// different types of non-debug edges, unrelated cases are filtered out explicitly and in ad-hoc manner. +void Compile::expand_reachability_edges(Unique_Node_List& safepoints) { + for (uint i = 0; i < safepoints.size(); i++) { + SafePointNode* sfpt = safepoints.at(i)->as_SafePoint(); + + uint rf_offset = rf_base_offset(sfpt); + if (sfpt->jvms() != nullptr && sfpt->req() > rf_offset) { + assert(is_interfering_sfpt_candidate(sfpt), ""); + Node* ctrl_out = sfpt_ctrl_out(sfpt); + Node* ctrl_end = ctrl_out->unique_ctrl_out(); + + Node* extra_edge = nullptr; + if (sfpt->is_Call()) { + address entry = sfpt->as_Call()->entry_point(); + if (entry == OptoRuntime::new_array_Java() || + entry == OptoRuntime::new_array_nozero_Java()) { + // valid_length_test_input is appended during macro expansion at the very end + int last_idx = sfpt->req() - 1; + extra_edge = sfpt->in(last_idx); + sfpt->del_req(last_idx); + } + } + + while (sfpt->req() > rf_offset) { + int idx = sfpt->req() - 1; + Node* referent = sfpt->in(idx); + sfpt->del_req(idx); + + Node* new_rf = new ReachabilityFenceNode(C, ctrl_out, referent); + ctrl_end->replace_edge(ctrl_out, new_rf); + ctrl_end = new_rf; + } + + if (extra_edge != nullptr) { + sfpt->add_req(extra_edge); // Add valid_length_test_input edge back + } + } + } +} diff --git a/src/hotspot/share/opto/reachability.hpp b/src/hotspot/share/opto/reachability.hpp new file mode 100644 index 00000000000..ba435c8484f --- /dev/null +++ b/src/hotspot/share/opto/reachability.hpp @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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_OPTO_REACHABILITY_HPP +#define SHARE_OPTO_REACHABILITY_HPP + +#include "opto/multnode.hpp" +#include "opto/node.hpp" +#include "opto/opcodes.hpp" +#include "opto/type.hpp" + +//------------------------ReachabilityFenceNode-------------------------- +// Represents a Reachability Fence (RF) in the code. +// +// RF ensures that the given object (referent) remains strongly reachable regardless of +// any optimizing transformations the virtual machine may perform that might otherwise +// allow the object to become unreachable. + +// java.lang.ref.Reference::reachabilityFence calls are intrinsified into ReachabilityFence nodes. +// +// More details in reachability.cpp. +class ReachabilityFenceNode : public Node { +public: + ReachabilityFenceNode(Compile* C, Node* ctrl, Node* referent) + : Node(1) { + assert(referent->bottom_type()->isa_oopptr() || + referent->bottom_type()->isa_narrowoop() != nullptr || + referent->bottom_type() == TypePtr::NULL_PTR, + "%s", Type::str(referent->bottom_type())); + init_class_id(Class_ReachabilityFence); + init_req(TypeFunc::Control, ctrl); + add_req(referent); + C->add_reachability_fence(this); + } + virtual int Opcode() const; + virtual bool is_CFG() const { return true; } + virtual uint hash() const { return NO_HASH; } // CFG nodes do not hash + virtual bool depends_only_on_test() const { return false; }; + virtual uint ideal_reg() const { return 0; } // not matched in the AD file + virtual const Type* bottom_type() const { return Type::CONTROL; } + virtual const RegMask& in_RegMask(uint idx) const { + // Fake input register mask for the referent: accepts all registers and all stack slots. + // This avoids redundant register moves around reachability fences. + return RegMask::ALL; + } + virtual const RegMask& out_RegMask() const { + return RegMask::EMPTY; + } + + virtual Node* Ideal(PhaseGVN* phase, bool can_reshape); + virtual Node* Identity(PhaseGVN* phase); + + Node* referent() const { return in(1); } + bool is_redundant(PhaseGVN& gvn); + bool clear_referent(PhaseIterGVN& phase); + +#ifndef PRODUCT + virtual void format(PhaseRegAlloc* ra, outputStream* st) const; + virtual void emit(C2_MacroAssembler* masm, PhaseRegAlloc* ra) const; +#endif +}; + +#endif // SHARE_OPTO_REACHABILITY_HPP diff --git a/src/java.base/share/classes/java/lang/ref/Reference.java b/src/java.base/share/classes/java/lang/ref/Reference.java index 88bdb99dfd6..df46ffe6ca6 100644 --- a/src/java.base/share/classes/java/lang/ref/Reference.java +++ b/src/java.base/share/classes/java/lang/ref/Reference.java @@ -644,12 +644,9 @@ public abstract sealed class Reference<@jdk.internal.RequiresIdentity T> * {@code null}, this method has no effect. * @since 9 */ - @ForceInline + @IntrinsicCandidate public static void reachabilityFence(Object ref) { - // Does nothing. This method is annotated with @ForceInline to eliminate - // most of the overhead that using @DontInline would cause with the - // HotSpot JVM, when this fence is used in a wide variety of situations. - // HotSpot JVM retains the ref and does not GC it before a call to - // this method, because the JIT-compilers do not have GC-only safepoints. + // Does nothing. HotSpot JVM retains the ref and does not GC it before a call to this method. + // Using an intrinsic allows JIT-compilers to further optimize it while retaining the correct semantics. } } diff --git a/test/hotspot/jtreg/compiler/c2/ReachabilityFenceFlagsTest.java b/test/hotspot/jtreg/compiler/c2/ReachabilityFenceFlagsTest.java new file mode 100644 index 00000000000..4289794b278 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/ReachabilityFenceFlagsTest.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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.c2; + +/* + * @test + * @bug 8290892 + * @summary Test diagnostic modes for Reference.reachabilityFence support + * + * @requires vm.compiler2.enabled + * + * @run main/othervm -Xcomp -XX:-TieredCompilation -XX:+UnlockDiagnosticVMOptions + * -XX:+StressReachabilityFences -XX:-OptimizeReachabilityFences -XX:-PreserveReachabilityFencesOnConstants + * compiler.c2.ReachabilityFenceFlagsTest + * + * @run main/othervm -Xcomp -XX:-TieredCompilation -XX:+UnlockDiagnosticVMOptions + * -XX:+StressReachabilityFences -XX:-OptimizeReachabilityFences -XX:+PreserveReachabilityFencesOnConstants + * compiler.c2.ReachabilityFenceFlagsTest + * + * @run main/othervm -Xcomp -XX:-TieredCompilation -XX:+UnlockDiagnosticVMOptions + * -XX:+StressReachabilityFences -XX:+OptimizeReachabilityFences -XX:-PreserveReachabilityFencesOnConstants + * compiler.c2.ReachabilityFenceFlagsTest + * + * @run main/othervm -Xcomp -XX:-TieredCompilation -XX:+UnlockDiagnosticVMOptions + * -XX:+StressReachabilityFences -XX:+OptimizeReachabilityFences -XX:+PreserveReachabilityFencesOnConstants + * compiler.c2.ReachabilityFenceFlagsTest + */ +public class ReachabilityFenceFlagsTest { + public static void main(String[] args) throws Throwable { + } +} diff --git a/test/hotspot/jtreg/compiler/c2/ReachabilityFenceOnConstantTest.java b/test/hotspot/jtreg/compiler/c2/ReachabilityFenceOnConstantTest.java new file mode 100644 index 00000000000..db8590865fb --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/ReachabilityFenceOnConstantTest.java @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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.c2; + +import jdk.internal.misc.Unsafe; +import jdk.internal.vm.annotation.Stable; + +import java.lang.ref.Cleaner; +import java.lang.ref.Reference; + +/* + * @test + * @bug 8290892 + * @summary Tests to ensure that reachabilityFence() correctly keeps objects from being collected prematurely. + * @modules java.base/jdk.internal.misc + * java.base/jdk.internal.vm.annotation + * @run main/bootclasspath/othervm -Xbatch -XX:-TieredCompilation -XX:CompileCommand=quiet + * -XX:CompileCommand=compileonly,*::test + * -XX:+UnlockDiagnosticVMOptions -XX:+PreserveReachabilityFencesOnConstants + * compiler.c2.ReachabilityFenceOnConstantTest + */ +public class ReachabilityFenceOnConstantTest { + static final Unsafe U = Unsafe.getUnsafe(); + + static final long BUFFER_SIZE = 1024; + static @Stable MyBuffer BUFFER = new MyBuffer(); + + static volatile boolean isCleaned = false; + + static class MyBuffer { + final @Stable long address; + final @Stable long limit; + + MyBuffer() { + final long adr = U.allocateMemory(BUFFER_SIZE); + U.setMemory(adr, BUFFER_SIZE, (byte)0); + address = adr; + limit = BUFFER_SIZE; + System.out.printf("Allocated memory (%d bytes): 0x%016x\n", BUFFER_SIZE, adr); + Cleaner.create().register(this, () -> { + System.out.printf("Freed memory (%d bytes): 0x%016x\n", BUFFER_SIZE, adr); + U.setMemory(adr, BUFFER_SIZE, (byte)-1); // clear + U.freeMemory(adr); + isCleaned = true; + }); + } + + byte getByte(long offset) { + return U.getByte(null, address + offset); + } + } + + static int test() { + int acc = 0; + MyBuffer buf = BUFFER; + try { + for (long i = 0; i < buf.limit; i++) { + acc += buf.getByte(i); + } + } finally { + Reference.reachabilityFence(buf); + } + return acc; + } + + static void runTest() { + for (int i = 0; i < 20_000; i++) { + if (test() != 0) { + throw new AssertionError("observed stale buffer: TestConstantOop::isCleaned=" + isCleaned); + } + } + } + + public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException { + runTest(); // run test() and constant fold accesses to BUFFER (and it's state) during JIT-compilation + + BUFFER = null; // remove last strong root + + // Ensure the instance is GCed. + while (!isCleaned) { + try { + System.gc(); + Thread.sleep(100); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + + try { + runTest(); // repeat to ensure stale BUFFER contents is not accessed + } catch (NullPointerException e) { + // expected; ignore + } + System.out.println("TEST PASSED"); + } +} diff --git a/test/hotspot/jtreg/compiler/c2/ReachabilityFenceTest.java b/test/hotspot/jtreg/compiler/c2/ReachabilityFenceTest.java new file mode 100644 index 00000000000..d0bce024696 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/ReachabilityFenceTest.java @@ -0,0 +1,353 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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.c2; + +import java.lang.ref.Cleaner; +import java.lang.ref.Reference; +import java.util.Arrays; +import java.util.concurrent.Callable; +import java.util.concurrent.CountDownLatch; +import jdk.internal.misc.Unsafe; + +import compiler.lib.ir_framework.*; + +/* + * @test + * @bug 8290892 + * @summary Tests to ensure that reachabilityFence() correctly keeps objects from being collected prematurely. + * @modules java.base/jdk.internal.misc + * @library /test/lib / + * @run main/othervm -Xbatch compiler.c2.ReachabilityFenceTest + */ +public class ReachabilityFenceTest { + private static final int SIZE = 100; + + static final boolean[] STATUS = new boolean[2]; + + interface MyBuffer { + byte get(int offset); + } + static class MyBufferOnHeap implements MyBuffer { + + private static int current = 0; + private final static byte[][] payload = new byte[10][]; + + private final int id; + + public MyBufferOnHeap() { + // Get a unique id, allocate memory, and save the address in the payload array. + id = current++; + payload[id] = new byte[SIZE]; + + // Initialize buffer + for (int i = 0; i < SIZE; ++i) { + put(i, (byte) 42); + } + + // Register a cleaner to free the memory when the buffer is garbage collected. + int lid = id; // Capture current value + Cleaner.create().register(this, () -> { free(lid); }); + + System.out.println("Created new buffer of size = " + SIZE + " with id = " + id); + } + + private static void free(int id) { + System.out.println("Freeing buffer with id = " + id); + for (int i = 0; i < SIZE; ++i) { + payload[id][i] = (byte)0; + } + payload[id] = null; + + synchronized (STATUS) { + STATUS[0] = true; + STATUS.notifyAll(); + } + } + + public void put(int offset, byte b) { + payload[id][offset] = b; + } + + public byte get(int offset) { + try { + return payload[id][offset]; + } finally { + Reference.reachabilityFence(this); + } + } + } + + static class MyBufferOffHeap implements MyBuffer { + private static Unsafe UNSAFE = Unsafe.getUnsafe(); + + private static int current = 0; + private static long payload[] = new long[10]; + + private final int id; + + public MyBufferOffHeap() { + // Get a unique id, allocate memory, and save the address in the payload array. + id = current++; + payload[id] = UNSAFE.allocateMemory(SIZE); + + // Initialize buffer + for (int i = 0; i < SIZE; ++i) { + put(i, (byte) 42); + } + + // Register a cleaner to free the memory when the buffer is garbage collected + int lid = id; // Capture current value + Cleaner.create().register(this, () -> { free(lid); }); + + System.out.println("Created new buffer of size = " + SIZE + " with id = " + id); + } + + private static void free(int id) { + System.out.println("Freeing buffer with id = " + id); + for (int i = 0; i < SIZE; ++i) { + UNSAFE.putByte(payload[id] + i, (byte)0); + } + // UNSAFE.freeMemory(payload[id]); // don't deallocate backing memory to avoid crashes + payload[id] = 0; + + synchronized (STATUS) { + STATUS[1] = true; + STATUS.notifyAll(); + } + } + + public void put(int offset, byte b) { + UNSAFE.putByte(payload[id] + offset, b); + } + + public byte get(int offset) { + try { + return UNSAFE.getByte(payload[id] + offset); + } finally { + Reference.reachabilityFence(this); + } + } + } + + static MyBufferOffHeap bufferOff = new MyBufferOffHeap(); + static MyBufferOnHeap bufferOn = new MyBufferOnHeap(); + + static long[] counters = new long[4]; + + @ForceInline + static boolean test(MyBuffer buf) { + if (buf == null) { + return false; + } + for (int i = 0; i < SIZE; i++) { + // The access is split into base address load (payload[id]), offset computation, and data load. + // While offset is loop-variant, payload[id] is not and can be hoisted. + // If bufferOff and payload[id] loads are hoisted outside outermost loop, it eliminates all usages of + // myBuffer oop inside the loop and bufferOff can be GCed at the safepoint on outermost loop back branch. + byte b = buf.get(i); // inlined + if (b != 42) { + String msg = "Unexpected value = " + b + ". Buffer was garbage collected before reachabilityFence was reached!"; + throw new AssertionError(msg); + } + } + return true; + } + + /* ===================================== Off-heap versions ===================================== */ + + @Test + @Arguments(values = {Argument.NUMBER_42}) + @IR(counts = {IRNode.REACHABILITY_FENCE, "1"}, phase = CompilePhase.AFTER_PARSING) + @IR(counts = {IRNode.REACHABILITY_FENCE, ">=1"}, phase = CompilePhase.AFTER_LOOP_OPTS) + @IR(counts = {IRNode.REACHABILITY_FENCE, "0"}, phase = CompilePhase.EXPAND_REACHABILITY_FENCES) + @IR(counts = {IRNode.REACHABILITY_FENCE, "1"}, phase = CompilePhase.FINAL_CODE) + static long testOffHeap1(int limit) { + for (long j = 0; j < limit; j++) { + MyBufferOffHeap myBuffer = bufferOff; // local + if (!test(myBuffer)) { + return j; + } + counters[0] = j; + } // safepoint on loop backedge does NOT contain myBuffer local as part of its JVM state + return limit; + } + + @Test + @Arguments(values = {Argument.NUMBER_42}) + @IR(counts = {IRNode.REACHABILITY_FENCE, "2"}, phase = CompilePhase.AFTER_PARSING) + @IR(counts = {IRNode.REACHABILITY_FENCE, ">=2"}, phase = CompilePhase.AFTER_LOOP_OPTS) + @IR(counts = {IRNode.REACHABILITY_FENCE, "0"}, phase = CompilePhase.EXPAND_REACHABILITY_FENCES) + @IR(counts = {IRNode.REACHABILITY_FENCE, "1"}, phase = CompilePhase.FINAL_CODE) + // Both RF nodes share the same referent and there's a single safepoint on loop-back edge. + // That's the reason why there are 2 RF nodes after parsing, but 1 RF node at the end. + static long testOffHeap2(int limit) { + for (long j = 0; j < limit; j++) { + MyBufferOffHeap myBuffer = bufferOff; // local + try { + if (!test(myBuffer)) { + return j; + } + counters[1] = j; + } finally { + Reference.reachabilityFence(myBuffer); + } + } // safepoint on loop-back edge does NOT contain myBuffer local as part of its JVM state + return limit; + } + + /* ===================================== On-heap versions ===================================== */ + + @Test + @Arguments(values = {Argument.NUMBER_42}) + @IR(counts = {IRNode.REACHABILITY_FENCE, "1"}, phase = CompilePhase.AFTER_PARSING) + @IR(counts = {IRNode.REACHABILITY_FENCE, ">=1"}, phase = CompilePhase.AFTER_LOOP_OPTS) + @IR(counts = {IRNode.REACHABILITY_FENCE, "0"}, phase = CompilePhase.EXPAND_REACHABILITY_FENCES) + @IR(counts = {IRNode.REACHABILITY_FENCE, "1"}, phase = CompilePhase.FINAL_CODE) + static long testOnHeap1(int limit) { + for (long j = 0; j < limit; j++) { + MyBufferOnHeap myBuffer = bufferOn; // local + if (!test(myBuffer)) { + return j; + } + counters[2] = j; + } // safepoint on loop backedge does NOT contain myBuffer local as part of its JVM state + return limit; + } + + @Test + @Arguments(values = {Argument.NUMBER_42}) + @IR(counts = {IRNode.REACHABILITY_FENCE, "2"}, phase = CompilePhase.AFTER_PARSING) + @IR(counts = {IRNode.REACHABILITY_FENCE, ">=2"}, phase = CompilePhase.AFTER_LOOP_OPTS) + @IR(counts = {IRNode.REACHABILITY_FENCE, "0"}, phase = CompilePhase.EXPAND_REACHABILITY_FENCES) + @IR(counts = {IRNode.REACHABILITY_FENCE, "1"}, phase = CompilePhase.FINAL_CODE) + static long testOnHeap2(int limit) { + for (long j = 0; j < limit; j++) { + MyBufferOnHeap myBuffer = bufferOn; // local + try { + if (!test(myBuffer)) { + return j; + } + counters[3] = j; + } finally { + Reference.reachabilityFence(myBuffer); + } + } // safepoint on loop backedge does NOT contain myBuffer local as part of its JVM state + return limit; + } + + /* ===================================== Helper methods ===================================== */ + + static void runJavaTestCases() throws Throwable { + // Warmup to trigger compilations. + for (int i = 0; i < 10_000; i++) { + testOffHeap1(10); + testOffHeap2(10); + testOnHeap1(10); + testOnHeap2(10); + } + + @SuppressWarnings("unchecked") + Callable[] tasks = new Callable[] { + () -> testOffHeap1(100_000_000), + () -> testOffHeap2(100_000_000), + () -> testOnHeap1(100_000_000), + () -> testOnHeap2(100_000_000), + }; + int taskCount = tasks.length; + CountDownLatch latch = new CountDownLatch(taskCount + 1); + final Thread[] workers = new Thread[taskCount]; + final Throwable[] result = new Throwable[taskCount]; + + for (int i = 0; i < taskCount; i++) { + final int id = i; + workers[id] = new Thread(() -> { + latch.countDown(); // synchronize with main thread + try { + System.out.printf("Computation thread #%d has started\n", id); + long cnt = tasks[id].call(); + System.out.printf("#%d Finished after %d iterations\n", id, cnt); + } catch (Throwable e) { + System.out.printf("#%d Finished with an exception %s\n", id, e); + result[id] = e; + } + }); + } + + for (Thread worker : workers) { + worker.start(); + } + + latch.countDown(); // synchronize with worker threads + + Thread.sleep(100); // let workers proceed + + // Clear references to buffers and make sure it's garbage collected. + System.out.printf("Buffers set to null. Waiting for garbage collection. (counters = %s)\n", Arrays.toString(counters)); + bufferOn = null; + bufferOff = null; + + System.gc(); + + synchronized (STATUS) { + do { + if (STATUS[0] && STATUS[1]) { + break; + } else { + System.out.printf("Waiting for cleanup... (counters = %s)\n", Arrays.toString(counters)); + System.gc(); + STATUS.wait(100); + } + } while (true); + } + + for (Thread worker : workers) { + worker.join(); + } + + System.out.printf("Results: %s\n", Arrays.deepToString(result)); + + for (Throwable e : result) { + if (e != null) { + throw e; + } + } + } + + static void runIRTestCases() { + TestFramework framework = new TestFramework(); + framework.addFlags("--add-exports", "java.base/jdk.internal.misc=ALL-UNNAMED"); + framework.start(); + } + + public static void main(String[] args) throws Throwable { + try { + runIRTestCases(); + runJavaTestCases(); + System.out.println("TEST PASSED"); + } catch (Throwable e) { + System.out.println("TEST FAILED"); + throw e; + } + } +} diff --git a/test/hotspot/jtreg/compiler/c2/irTests/ReachabilityFenceTest.java b/test/hotspot/jtreg/compiler/c2/irTests/ReachabilityFenceTest.java new file mode 100644 index 00000000000..7f4142c18d3 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/irTests/ReachabilityFenceTest.java @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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.c2.irTests; + +import java.lang.ref.Cleaner; +import java.lang.ref.Reference; + +import compiler.lib.ir_framework.*; +import jdk.internal.misc.Unsafe; + +/* + * @test + * @bug 8290892 + * @summary IR tests on reachability fence-related loop transformations. + * @modules java.base/jdk.internal.misc + * @library /test/lib / + * @run driver compiler.c2.irTests.ReachabilityFenceTest + */ +public class ReachabilityFenceTest { + private static int SIZE = 100; + + /* ===================================== On-heap version ===================================== */ + + private static int[] a = new int[SIZE]; + private static int[] b = new int[SIZE]; + private static int[] c = new int[SIZE]; + + @Test + @IR(counts = {IRNode.REACHABILITY_FENCE, "3"}, phase = CompilePhase.AFTER_PARSING) + @IR(counts = {IRNode.REACHABILITY_FENCE, "3"}, phase = CompilePhase.AFTER_LOOP_OPTS) + @IR(counts = {IRNode.REACHABILITY_FENCE, "0"}, phase = CompilePhase.EXPAND_REACHABILITY_FENCES) + @IR(counts = {IRNode.REACHABILITY_FENCE, "3"}, phase = CompilePhase.FINAL_CODE) + static void testCountedLoopInt() { + for (int i = 0; i < a.length; i++) { + try { + c[i] = a[i] + b[i]; + } finally { + Reference.reachabilityFence(a); + Reference.reachabilityFence(b); + Reference.reachabilityFence(c); + } + } + } + + /* ===================================== Off-heap version ===================================== */ + + static class OffHeapBuffer { + private static Unsafe UNSAFE = Unsafe.getUnsafe(); + + private final long payload; + + public final long size; + + OffHeapBuffer() { + size = SIZE; + payload = UNSAFE.allocateMemory(SIZE); + + Cleaner.create().register(this, () -> { + UNSAFE.freeMemory(payload); + }); + } + + public void put(long offset, byte b) { + try { + UNSAFE.putByte(payload + offset, b); + } finally { + Reference.reachabilityFence(this); + } + } + + public byte get(long offset) { + try { + return UNSAFE.getByte(payload + offset); + } finally { + Reference.reachabilityFence(this); + } + } + } + + private static OffHeapBuffer bufA = new OffHeapBuffer(); + private static OffHeapBuffer bufB = new OffHeapBuffer(); + private static OffHeapBuffer bufC = new OffHeapBuffer(); + + @Test + @IR(counts = {IRNode.REACHABILITY_FENCE, "3"}, phase = CompilePhase.AFTER_PARSING) + @IR(counts = {IRNode.REACHABILITY_FENCE, "3"}, phase = CompilePhase.AFTER_LOOP_OPTS) + @IR(counts = {IRNode.REACHABILITY_FENCE, "0"}, phase = CompilePhase.EXPAND_REACHABILITY_FENCES) + @IR(counts = {IRNode.REACHABILITY_FENCE, "3"}, phase = CompilePhase.FINAL_CODE) + static void testCountedLoopLong() { + for (long i = 0; i < bufA.size; i++) { + byte a = bufA.get(i); // +1 RF + byte b = bufB.get(i); // +1 RF + bufC.put(i, (byte)(a+b)); // +1 RF + } + } + + /* ============================================================================================ */ + + public static void main(String[] args) throws Throwable { + TestFramework framework = new TestFramework(); + framework.addFlags("--add-exports", "java.base/jdk.internal.misc=ALL-UNNAMED"); + framework.start(); + } +} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/CompilePhase.java b/test/hotspot/jtreg/compiler/lib/ir_framework/CompilePhase.java index 1e3ba7c314e..43178f41185 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/CompilePhase.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/CompilePhase.java @@ -114,6 +114,7 @@ public enum CompilePhase { PHASEIDEALLOOP1( "PhaseIdealLoop 1"), PHASEIDEALLOOP2( "PhaseIdealLoop 2"), PHASEIDEALLOOP3( "PhaseIdealLoop 3"), + EXPAND_REACHABILITY_FENCES( "Expand Reachability Fences"), AUTO_VECTORIZATION1_BEFORE_APPLY( "AutoVectorization 1, before Apply"), AUTO_VECTORIZATION3_AFTER_ADJUST_LIMIT( "AutoVectorization 2, after Adjusting Pre-loop Limit"), AUTO_VECTORIZATION4_AFTER_SPECULATIVE_RUNTIME_CHECKS("AutoVectorization 3, after Adding Speculative Runtime Checks"), diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java index 0e1accf8a50..3f742a0ce62 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java @@ -3130,6 +3130,11 @@ public class IRNode { fromBeforeRemoveUselessToFinalCode(BLACKHOLE, "Blackhole"); } + public static final String REACHABILITY_FENCE = PREFIX + "REACHABILITY_FENCE" + POSTFIX; + static { + fromBeforeRemoveUselessToFinalCode(REACHABILITY_FENCE, "ReachabilityFence"); + } + public static final String SELECT_FROM_TWO_VECTOR_VB = VECTOR_PREFIX + "SELECT_FROM_TWO_VECTOR_VB" + POSTFIX; static { vectorNode(SELECT_FROM_TWO_VECTOR_VB, "SelectFromTwoVector", TYPE_BYTE); From 531dad0cd7df3fa4e6a06d5727677f881a8d3721 Mon Sep 17 00:00:00 2001 From: Mark Powers Date: Mon, 13 Apr 2026 20:37:18 +0000 Subject: [PATCH 266/359] 8369917: LMS/HSS RFC 9858 Support Reviewed-by: weijun --- .../sun/security/provider/DigestBase.java | 19 +- .../classes/sun/security/provider/HSS.java | 362 +++++++++++++----- .../classes/sun/security/provider/SHA2.java | 3 +- .../classes/sun/security/provider/SHA3.java | 24 +- .../classes/sun/security/util/KeyUtil.java | 7 +- .../sun/security/provider/hss/TestHSS.java | 135 +++++-- 6 files changed, 408 insertions(+), 142 deletions(-) diff --git a/src/java.base/share/classes/sun/security/provider/DigestBase.java b/src/java.base/share/classes/sun/security/provider/DigestBase.java index 2aaf0a2fac6..0bb15ef3efe 100644 --- a/src/java.base/share/classes/sun/security/provider/DigestBase.java +++ b/src/java.base/share/classes/sun/security/provider/DigestBase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -242,4 +242,21 @@ abstract class DigestBase extends MessageDigestSpi implements Cloneable { padding = new byte[136]; padding[0] = (byte)0x80; } + + /** + * Digest block-length bytes in a single operation. + * Subclasses are expected to override this method. It is intended + * for fixed-length short input where input includes padding bytes. + * @param input byte array to be digested + * @param inLen the length of the input + * @param output the output buffer + * @param outOffset the offset into output buffer where digest should be written + * @param outLen the length of the output buffer + * @throws UnsupportedOperationException if a subclass does not override this method + */ + void implDigestFixedLengthPreprocessed ( + byte[] input, int inLen, byte[] output, int outOffset, int outLen) + throws UnsupportedOperationException { + throw new UnsupportedOperationException("should not be here"); + } } diff --git a/src/java.base/share/classes/sun/security/provider/HSS.java b/src/java.base/share/classes/sun/security/provider/HSS.java index c1cb5ed6a30..50afba7cab8 100644 --- a/src/java.base/share/classes/sun/security/provider/HSS.java +++ b/src/java.base/share/classes/sun/security/provider/HSS.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * 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,16 +24,22 @@ */ package sun.security.provider; +import java.io.ByteArrayOutputStream; +import java.io.InvalidObjectException; +import java.io.Serial; +import java.io.Serializable; +import java.security.SecureRandom; +import java.security.*; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; +import java.security.spec.X509EncodedKeySpec; +import java.util.Arrays; + import sun.security.util.*; import sun.security.x509.AlgorithmId; import sun.security.x509.X509Key; -import java.io.*; -import java.security.*; -import java.security.SecureRandom; -import java.security.spec.*; -import java.util.Arrays; - /** * Implementation of the Hierarchical Signature System using the * Leighton-Micali Signatures (HSS/LMS) as described in RFC 8554 and @@ -196,42 +202,94 @@ public final class HSS extends SignatureSpi { static class LMSUtils { static final int LMS_RESERVED = 0; - static final int LMS_SHA256_M32_H5 = 5; - static final int LMS_SHA256_M32_H10 = 6; - static final int LMS_SHA256_M32_H15 = 7; - static final int LMS_SHA256_M32_H20 = 8; - static final int LMS_SHA256_M32_H25 = 9; + static final int LMS_SHA256_M32_H5 = 0x05; + static final int LMS_SHA256_M32_H10 = 0x06; + static final int LMS_SHA256_M32_H15 = 0x07; + static final int LMS_SHA256_M32_H20 = 0x08; + static final int LMS_SHA256_M32_H25 = 0x09; + static final int LMS_SHA256_M24_H5 = 0x0a; + static final int LMS_SHA256_M24_H10 = 0x0b; + static final int LMS_SHA256_M24_H15 = 0x0c; + static final int LMS_SHA256_M24_H20 = 0x0d; + static final int LMS_SHA256_M24_H25 = 0x0e; + static final int LMS_SHAKE_M32_H5 = 0x0f; + static final int LMS_SHAKE_M32_H10 = 0x10; + static final int LMS_SHAKE_M32_H15 = 0x11; + static final int LMS_SHAKE_M32_H20 = 0x12; + static final int LMS_SHAKE_M32_H25 = 0x13; + static final int LMS_SHAKE_M24_H5 = 0x14; + static final int LMS_SHAKE_M24_H10 = 0x15; + static final int LMS_SHAKE_M24_H15 = 0x16; + static final int LMS_SHAKE_M24_H20 = 0x17; + static final int LMS_SHAKE_M24_H25 = 0x18; static String lmsType(int type) { - String typeStr; - switch (type) { - case LMS_RESERVED: typeStr = "LMS_RESERVED"; break; - case LMS_SHA256_M32_H5: typeStr = "LMS_SHA256_M32_H5"; break; - case LMS_SHA256_M32_H10: typeStr = "LMS_SHA256_M32_H10"; break; - case LMS_SHA256_M32_H15: typeStr = "LMS_SHA256_M32_H15"; break; - case LMS_SHA256_M32_H20: typeStr = "LMS_SHA256_M32_H20"; break; - case LMS_SHA256_M32_H25: typeStr = "LMS_SHA256_M32_H25"; break; - default: typeStr = "unrecognized"; - } + String typeStr = switch (type) { + case LMS_RESERVED -> "LMS_RESERVED"; + case LMS_SHA256_M32_H5 -> "LMS_SHA256_M32_H5"; + case LMS_SHA256_M32_H10 -> "LMS_SHA256_M32_H10"; + case LMS_SHA256_M32_H15 -> "LMS_SHA256_M32_H15"; + case LMS_SHA256_M32_H20 -> "LMS_SHA256_M32_H20"; + case LMS_SHA256_M32_H25 -> "LMS_SHA256_M32_H25"; + case LMS_SHA256_M24_H5 -> "LMS_SHA256_M24_H5"; + case LMS_SHA256_M24_H10 -> "LMS_SHA256_M24_H10"; + case LMS_SHA256_M24_H15 -> "LMS_SHA256_M24_H15"; + case LMS_SHA256_M24_H20 -> "LMS_SHA256_M24_H20"; + case LMS_SHA256_M24_H25 -> "LMS_SHA256_M24_H25"; + case LMS_SHAKE_M32_H5 -> "LMS_SHAKE_M32_H5"; + case LMS_SHAKE_M32_H10 -> "LMS_SHAKE_M32_H10"; + case LMS_SHAKE_M32_H15 -> "LMS_SHAKE_M32_H15"; + case LMS_SHAKE_M32_H20 -> "LMS_SHAKE_M32_H20"; + case LMS_SHAKE_M32_H25 -> "LMS_SHAKE_M32_H25"; + case LMS_SHAKE_M24_H5 -> "LMS_SHAKE_M24_H5"; + case LMS_SHAKE_M24_H10 -> "LMS_SHAKE_M24_H10"; + case LMS_SHAKE_M24_H15 -> "LMS_SHAKE_M24_H15"; + case LMS_SHAKE_M24_H20 -> "LMS_SHAKE_M24_H20"; + case LMS_SHAKE_M24_H25 -> "LMS_SHAKE_M24_H25"; + default -> "unrecognized"; + }; return typeStr; } static final int LMOTS_RESERVED = 0; - static final int LMOTS_SHA256_N32_W1 = 1; - static final int LMOTS_SHA256_N32_W2 = 2; - static final int LMOTS_SHA256_N32_W4 = 3; - static final int LMOTS_SHA256_N32_W8 = 4; + static final int LMOTS_SHA256_N32_W1 = 0x01; + static final int LMOTS_SHA256_N32_W2 = 0x02; + static final int LMOTS_SHA256_N32_W4 = 0x03; + static final int LMOTS_SHA256_N32_W8 = 0x04; + static final int LMOTS_SHA256_N24_W1 = 0x05; + static final int LMOTS_SHA256_N24_W2 = 0x06; + static final int LMOTS_SHA256_N24_W4 = 0x07; + static final int LMOTS_SHA256_N24_W8 = 0x08; + static final int LMOTS_SHAKE_N32_W1 = 0x09; + static final int LMOTS_SHAKE_N32_W2 = 0x0a; + static final int LMOTS_SHAKE_N32_W4 = 0x0b; + static final int LMOTS_SHAKE_N32_W8 = 0x0c; + static final int LMOTS_SHAKE_N24_W1 = 0x0d; + static final int LMOTS_SHAKE_N24_W2 = 0x0e; + static final int LMOTS_SHAKE_N24_W4 = 0x0f; + static final int LMOTS_SHAKE_N24_W8 = 0x10; static String lmotsType(int type) { - String typeStr; - switch (type) { - case LMOTS_RESERVED: typeStr = "LMOTS_RESERVED"; break; - case LMOTS_SHA256_N32_W1: typeStr = "LMOTS_SHA256_N32_W1"; break; - case LMOTS_SHA256_N32_W2: typeStr = "LMOTS_SHA256_N32_W2"; break; - case LMOTS_SHA256_N32_W4: typeStr = "LMOTS_SHA256_N32_W4"; break; - case LMOTS_SHA256_N32_W8: typeStr = "LMOTS_SHA256_N32_W8"; break; - default: typeStr = "unrecognized"; - } + String typeStr = switch (type) { + case LMOTS_RESERVED -> "LMOTS_RESERVED"; + case LMOTS_SHA256_N32_W1 -> "LMOTS_SHA256_N32_W1"; + case LMOTS_SHA256_N32_W2 -> "LMOTS_SHA256_N32_W2"; + case LMOTS_SHA256_N32_W4 -> "LMOTS_SHA256_N32_W4"; + case LMOTS_SHA256_N32_W8 -> "LMOTS_SHA256_N32_W8"; + case LMOTS_SHA256_N24_W1 -> "LMOTS_SHA256_N24_W1"; + case LMOTS_SHA256_N24_W2 -> "LMOTS_SHA256_N24_W2"; + case LMOTS_SHA256_N24_W4 -> "LMOTS_SHA256_N24_W4"; + case LMOTS_SHA256_N24_W8 -> "LMOTS_SHA256_N24_W8"; + case LMOTS_SHAKE_N32_W1 -> "LMOTS_SHAKE_N32_W1"; + case LMOTS_SHAKE_N32_W2 -> "LMOTS_SHAKE_N32_W2"; + case LMOTS_SHAKE_N32_W4 -> "LMOTS_SHAKE_N32_W4"; + case LMOTS_SHAKE_N32_W8 -> "LMOTS_SHAKE_N32_W8"; + case LMOTS_SHAKE_N24_W1 -> "LMOTS_SHAKE_N24_W1"; + case LMOTS_SHAKE_N24_W2 -> "LMOTS_SHAKE_N24_W2"; + case LMOTS_SHAKE_N24_W4 -> "LMOTS_SHAKE_N24_W4"; + case LMOTS_SHAKE_N24_W8 -> "LMOTS_SHAKE_N24_W8"; + default -> "unrecognized"; + }; return typeStr; } @@ -352,53 +410,65 @@ public final class HSS extends SignatureSpi { static class LMSParams { final int m; // the number of bytes used from the hash output - final int hashAlg_m = 32; // output length of the LMS tree hash function + final int hashAlg_m; // output length of the LMS tree hash function final int h; // height of the LMS tree final int twoPowh; final String hashAlgStr; - LMSParams(int m, int h, String hashAlgStr) { + private LMSParams(int m, int h, String hashAlgStr, int hashAlg_m) { this.m = m; this.h = h; this.hashAlgStr = hashAlgStr; + this.hashAlg_m = hashAlg_m; twoPowh = 1 << h; } static LMSParams of(int type) { - int m; - int h; - String hashAlgStr; - switch (type) { - case LMSUtils.LMS_SHA256_M32_H5: - m = 32; - h = 5; - hashAlgStr = "SHA-256"; - break; - case LMSUtils.LMS_SHA256_M32_H10: - m = 32; - h = 10; - hashAlgStr = "SHA-256"; - break; - case LMSUtils.LMS_SHA256_M32_H15: - m = 32; - h = 15; - hashAlgStr = "SHA-256"; - break; - case LMSUtils.LMS_SHA256_M32_H20: - m = 32; - h = 20; - hashAlgStr = "SHA-256"; - break; - case LMSUtils.LMS_SHA256_M32_H25: - m = 32; - h = 25; - hashAlgStr = "SHA-256"; - break; - default: + LMSParams params = switch (type) { + case LMSUtils.LMS_SHA256_M32_H5 -> + new LMSParams(32, 5, "SHA-256", 32); + case LMSUtils.LMS_SHA256_M32_H10 -> + new LMSParams(32, 10, "SHA-256", 32); + case LMSUtils.LMS_SHA256_M32_H15 -> + new LMSParams(32, 15, "SHA-256", 32); + case LMSUtils.LMS_SHA256_M32_H20 -> + new LMSParams(32, 20, "SHA-256", 32); + case LMSUtils.LMS_SHA256_M32_H25 -> + new LMSParams(32, 25, "SHA-256", 32); + case LMSUtils.LMS_SHA256_M24_H5 -> + new LMSParams(24, 5, "SHA-256", 32); + case LMSUtils.LMS_SHA256_M24_H10 -> + new LMSParams(24, 10, "SHA-256", 32); + case LMSUtils.LMS_SHA256_M24_H15 -> + new LMSParams(24, 15, "SHA-256", 32); + case LMSUtils.LMS_SHA256_M24_H20 -> + new LMSParams(24, 20, "SHA-256", 32); + case LMSUtils.LMS_SHA256_M24_H25 -> + new LMSParams(24, 25, "SHA-256", 32); + case LMSUtils.LMS_SHAKE_M32_H5 -> + new LMSParams(32, 5, "SHAKE256-512", 64); + case LMSUtils.LMS_SHAKE_M32_H10 -> + new LMSParams(32, 10, "SHAKE256-512", 64); + case LMSUtils.LMS_SHAKE_M32_H15 -> + new LMSParams(32, 15, "SHAKE256-512", 64); + case LMSUtils.LMS_SHAKE_M32_H20 -> + new LMSParams(32, 20, "SHAKE256-512", 64); + case LMSUtils.LMS_SHAKE_M32_H25 -> + new LMSParams(32, 25, "SHAKE256-512", 64); + case LMSUtils.LMS_SHAKE_M24_H5 -> + new LMSParams(24, 5, "SHAKE256-512", 64); + case LMSUtils.LMS_SHAKE_M24_H10 -> + new LMSParams(24, 10, "SHAKE256-512", 64); + case LMSUtils.LMS_SHAKE_M24_H15 -> + new LMSParams(24, 15, "SHAKE256-512", 64); + case LMSUtils.LMS_SHAKE_M24_H20 -> + new LMSParams(24, 20, "SHAKE256-512", 64); + case LMSUtils.LMS_SHAKE_M24_H25 -> + new LMSParams(24, 25, "SHAKE256-512", 64); + default -> throw new IllegalArgumentException("Unsupported or bad LMS type"); - } - - return new LMSParams(m, h, hashAlgStr); + }; + return params; } boolean hasSameHash(LMSParams other) { @@ -495,7 +565,7 @@ public final class HSS extends SignatureSpi { static class LMOTSParams { final int lmotSigType; final int n; // the number of bytes used from the hash output - final int hashAlg_n = 32; // the output length of the hash function + int hashAlg_n; // the output length of the hash function final int w; final int twoPowWMinus1; final int ls; @@ -511,6 +581,7 @@ public final class HSS extends SignatureSpi { // back into the buffer. This way, we avoid memory allocations and some // computations that would have to be done otherwise. final byte[] hashBuf; + // Precomputed block for SHA256 when the message size is 55 bytes // (i.e. when SHA256 is used) private static final byte[] hashbufSha256_32 = { @@ -523,10 +594,64 @@ public final class HSS extends SignatureSpi { 0, 0, 0, 0, 0, 0, 0, (byte) 0x80, 0, 0, 0, 0, 0, 0, 1, (byte) 0xb8 }; + // Precomputed block for SHA256 when the message size is 47 bytes + // (i.e. when SHA256-192 is used) + private static final byte[] hashbufSha256_24 = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, (byte) 0x80, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 0x78 + }; + // Precomputed block for SHAKE256 when the message size is 55 bytes + // (i.e. when SHAKE256 is used) + private static final byte[] hashbufShake256_32 = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, (byte) 0x1F, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, (byte) 0x80 + }; + // Precomputed block for SHAKE256 when the message size is 47 bytes + // (i.e. when SHAKE256-192 is used) + private static final byte[] hashbufShake256_24 = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, (byte) 0x1F, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, (byte) 0x80 + }; private LMOTSParams( int lmotSigType, int hLen, int w, - int ls, int p, String hashAlgName) { + int ls, int p, String hashAlgName, int hashAlg_n) { this.lmotSigType = lmotSigType; this.n = hLen; this.w = w; @@ -534,32 +659,60 @@ public final class HSS extends SignatureSpi { this.p = p; twoPowWMinus1 = (1 << w) - 1; this.hashAlgName = hashAlgName; - hashBuf = hashbufSha256_32; + this.hashAlg_n = hashAlg_n; + hashBuf = switch (hashAlgName) { + case "SHAKE256-512" -> { + yield this.n == 24 ? + hashbufShake256_24 : hashbufShake256_32; + } + case "SHA-256" -> { + yield this.n == 24 ? + hashbufSha256_24 : hashbufSha256_32; + } + default -> + throw new IllegalArgumentException( + "Unknown hash algorithm "+hashAlgName); + }; } static LMOTSParams of(int lmotsType) { - LMOTSParams params; - switch (lmotsType) { - case LMSUtils.LMOTS_SHA256_N32_W1: - params = new LMOTSParams( - lmotsType, 32, 1, 7, 265, "SHA-256"); - break; - case LMSUtils.LMOTS_SHA256_N32_W2: - params = new LMOTSParams( - lmotsType, 32, 2, 6, 133, "SHA-256"); - break; - case LMSUtils.LMOTS_SHA256_N32_W4: - params = new LMOTSParams( - lmotsType, 32, 4, 4, 67, "SHA-256"); - break; - case LMSUtils.LMOTS_SHA256_N32_W8: - params = new LMOTSParams( - lmotsType, 32, 8, 0, 34, "SHA-256"); - break; - default: + LMOTSParams params = switch (lmotsType) { + case LMSUtils.LMOTS_SHA256_N32_W1 -> + new LMOTSParams(lmotsType, 32, 1, 7, 265, "SHA-256", 32); + case LMSUtils.LMOTS_SHA256_N32_W2 -> + new LMOTSParams(lmotsType, 32, 2, 6, 133, "SHA-256", 32); + case LMSUtils.LMOTS_SHA256_N32_W4 -> + new LMOTSParams(lmotsType, 32, 4, 4, 67, "SHA-256", 32); + case LMSUtils.LMOTS_SHA256_N32_W8 -> + new LMOTSParams(lmotsType, 32, 8, 0, 34, "SHA-256", 32); + case LMSUtils.LMOTS_SHA256_N24_W1 -> + new LMOTSParams(lmotsType, 24, 1, 8, 200, "SHA-256", 32); + case LMSUtils.LMOTS_SHA256_N24_W2 -> + new LMOTSParams(lmotsType, 24, 2, 6, 101, "SHA-256", 32); + case LMSUtils.LMOTS_SHA256_N24_W4 -> + new LMOTSParams(lmotsType, 24, 4, 4, 51, "SHA-256", 32); + case LMSUtils.LMOTS_SHA256_N24_W8 -> + new LMOTSParams(lmotsType, 24, 8, 0, 26, "SHA-256", 32); + case LMSUtils.LMOTS_SHAKE_N32_W1 -> + new LMOTSParams(lmotsType, 32, 1, 7, 265, "SHAKE256-512", 64); + case LMSUtils.LMOTS_SHAKE_N32_W2 -> + new LMOTSParams(lmotsType, 32, 2, 6, 133, "SHAKE256-512", 64); + case LMSUtils.LMOTS_SHAKE_N32_W4 -> + new LMOTSParams(lmotsType, 32, 4, 4, 67, "SHAKE256-512", 64); + case LMSUtils.LMOTS_SHAKE_N32_W8 -> + new LMOTSParams(lmotsType, 32, 8, 0, 34, "SHAKE256-512", 64); + case LMSUtils.LMOTS_SHAKE_N24_W1 -> + new LMOTSParams(lmotsType, 24, 1, 8, 200, "SHAKE256-512", 64); + case LMSUtils.LMOTS_SHAKE_N24_W2 -> + new LMOTSParams(lmotsType, 24, 2, 6, 101, "SHAKE256-512", 64); + case LMSUtils.LMOTS_SHAKE_N24_W4 -> + new LMOTSParams(lmotsType, 24, 4, 4, 51, "SHAKE256-512", 64); + case LMSUtils.LMOTS_SHAKE_N24_W8 -> + new LMOTSParams(lmotsType, 24, 8, 0, 26, "SHAKE256-512", 64); + default -> throw new IllegalArgumentException( "Unsupported or bad OTS Algorithm Identifier."); - } + }; return params; } @@ -580,13 +733,6 @@ public final class HSS extends SignatureSpi { S[len + 1] = (byte) (sum & 0xff); } - void digestFixedLengthPreprocessed( - SHA2.SHA256 sha256, byte[] input, int inLen, - byte[] output, int outOffset, int outLen) { - sha256.implDigestFixedLengthPreprocessed( - input, inLen, output, outOffset, outLen); - } - byte[] lmotsPubKeyCandidate( LMSignature lmSig, byte[] message, LMSPublicKey pKey) throws SignatureException { @@ -625,7 +771,13 @@ public final class HSS extends SignatureSpi { byte[] preZi = hashBuf.clone(); int hashLen = hashBuf.length; - SHA2.SHA256 sha256 = new SHA2.SHA256(); + + DigestBase db; + if (hashAlgName.startsWith("SHAKE")) { + db = new SHA3.SHAKE256Hash(); + } else { + db = new SHA2.SHA256(); + } pKey.getI(preZi, 0); lmSig.getQArr(preZi, 16); @@ -643,11 +795,11 @@ public final class HSS extends SignatureSpi { for (int j = a; j < twoPowWMinus1; j++) { preZi[22] = (byte) j; if (j < twoPowWMinus2) { - digestFixedLengthPreprocessed( - sha256, preZi, hashLen, preZi, 23, n); + db.implDigestFixedLengthPreprocessed(preZi, + hashLen, preZi, 23, n); } else { - digestFixedLengthPreprocessed( - sha256, preZi, hashLen, preCandidate, 22 + i * n, n); + db.implDigestFixedLengthPreprocessed(preZi, + hashLen, preCandidate, 22 + i * n, n); } } } diff --git a/src/java.base/share/classes/sun/security/provider/SHA2.java b/src/java.base/share/classes/sun/security/provider/SHA2.java index e966e6b77f8..7d8c2840de9 100644 --- a/src/java.base/share/classes/sun/security/provider/SHA2.java +++ b/src/java.base/share/classes/sun/security/provider/SHA2.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +117,7 @@ abstract class SHA2 extends DigestBase { } + @Override protected void implDigestFixedLengthPreprocessed( byte[] input, int inLen, byte[] output, int outOffset, int outLen) { implReset(); diff --git a/src/java.base/share/classes/sun/security/provider/SHA3.java b/src/java.base/share/classes/sun/security/provider/SHA3.java index a096cac5f50..0578645c1cd 100644 --- a/src/java.base/share/classes/sun/security/provider/SHA3.java +++ b/src/java.base/share/classes/sun/security/provider/SHA3.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +98,15 @@ public abstract class SHA3 extends DigestBase { this.suffix = suffix; } + @Override + protected void implDigestFixedLengthPreprocessed( + byte[] input, int inLen, byte[] output, int outOffset, int outLen) { + implReset(); + + implCompress(input, 0); + implDigest0(output, outOffset, outLen); + } + private void implCompressCheck(byte[] b, int ofs) { Objects.requireNonNull(b); Preconditions.checkIndex(ofs + blockSize - 1, b.length, Preconditions.AIOOBE_FORMATTER); @@ -136,9 +145,6 @@ public abstract class SHA3 extends DigestBase { * DigestBase calls implReset() when necessary. */ void implDigest(byte[] out, int ofs) { - // Moving this allocation to the block where it is used causes a little - // performance drop, that is why it is here. - byte[] byteState = new byte[8]; if (engineGetDigestLength() == 0) { // This is an XOF, so the digest() call is illegal. throw new ProviderException("Calling digest() is not allowed in an XOF"); @@ -146,8 +152,12 @@ public abstract class SHA3 extends DigestBase { finishAbsorb(); + implDigest0(out, ofs, engineGetDigestLength()); + } + + void implDigest0(byte[] out, int ofs, int outLen) { int availableBytes = blockSize; - int numBytes = engineGetDigestLength(); + int numBytes = outLen; while (numBytes > availableBytes) { for (int i = 0; i < availableBytes / 8; i++) { @@ -163,6 +173,10 @@ public abstract class SHA3 extends DigestBase { asLittleEndian.set(out, ofs, state[i]); ofs += 8; } + + // Moving this allocation to the block where it is used causes a little + // performance drop, that is why it is here. + byte[] byteState = new byte[8]; if (numBytes % 8 != 0) { asLittleEndian.set(byteState, 0, state[numLongs]); System.arraycopy(byteState, 0, out, ofs, numBytes % 8); diff --git a/src/java.base/share/classes/sun/security/util/KeyUtil.java b/src/java.base/share/classes/sun/security/util/KeyUtil.java index 942a91d61b8..e9dabdc5b06 100644 --- a/src/java.base/share/classes/sun/security/util/KeyUtil.java +++ b/src/java.base/share/classes/sun/security/util/KeyUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -444,15 +444,16 @@ public final class KeyUtil { // is the LMS public key for the top-level tree. // Section 5.3: LMS public key is u32str(type) || u32str(otstype) || I || T[1] // Section 8: type is the numeric identifier for an LMS specification. - // This RFC defines 5 SHA-256 based types, value from 5 to 9. if (rawKey.length < 8) { throw new NoSuchAlgorithmException("Cannot decode public key"); } int num = ((rawKey[4] & 0xff) << 24) + ((rawKey[5] & 0xff) << 16) + ((rawKey[6] & 0xff) << 8) + (rawKey[7] & 0xff); return switch (num) { - // RFC 8554 only supports SHA_256 hash algorithm + // RFC 8554 only supports SHA_256 hash algorithms case 5, 6, 7, 8, 9 -> AlgorithmId.SHA256_oid; + // RFC 9858 supports SHAKE_256 hash algorithms + case 15, 16, 17, 18, 19 -> AlgorithmId.SHAKE256_512_oid; default -> throw new NoSuchAlgorithmException("Unknown LMS type: " + num); }; } catch (IOException e) { diff --git a/test/jdk/sun/security/provider/hss/TestHSS.java b/test/jdk/sun/security/provider/hss/TestHSS.java index 8056855cc1a..48019d4e465 100644 --- a/test/jdk/sun/security/provider/hss/TestHSS.java +++ b/test/jdk/sun/security/provider/hss/TestHSS.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * 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 8298127 8347596 + * @bug 8298127 8347596 8369917 * @library /test/lib * @summary tests for HSS/LMS provider * @modules java.base/sun.security.util @@ -194,6 +194,8 @@ public class TestHSS { static TestCase[] TestCases = new TestCase[] { // Test Case #1 // RFC 8554 Test Case 1 + // LM_SHA256_M32_H5, LMOTS_SHA256_N32_W8 + // LM_SHA256_M32_H5, LMOTS_SHA256_N32_W8 new TestCase( null, // exception true, // expected result @@ -307,6 +309,8 @@ public class TestHSS { // Test Case #2 // RFC 8554 Test Case 2 + // LM_SHA256_M32_H10, LMOTS_SHA256_N32_W4 + // LM_SHA256_M32_H5, LMOTS_SHA256_N32_W8 new TestCase( null, // exception true, // expected result @@ -456,11 +460,11 @@ public class TestHSS { ), // Test Case #3 - // Additional Parameter sets for LMS Hash-Based Signatures (fluhrer) - // This test should fail because SHA256_M24 is supported. + // RFC 9858 A.1 + // LMS_SHA256_M24_H5, LMOTS_SHA256_N24_W8 new TestCase( - new InvalidKeySpecException(), - false, // expected result + null, // exception + true, // expected result decode(""" 00000001 0000000a @@ -502,11 +506,11 @@ public class TestHSS { ), // Test Case #4 - // Additional Parameter sets for LMS Hash-Based Signatures (fluhrer) - // This test should fail because SHAKE is not supported. + // RFC 9858 A.2 + // LMS_SHAKE_M24_H5, LMOTS_SHAKE_N24_W8 new TestCase( - new InvalidKeySpecException(), - false, // expected result + null, // exception + true, // expected result decode(""" 00000001 00000014 @@ -549,11 +553,11 @@ public class TestHSS { ), // Test Case #5 - // Additional Parameter sets for LMS Hash-Based Signatures (fluhrer) - // This test should fail because SHAKE is not supported. + // RFC 9858 A.3 + // LMS_SHAKE_M32_H5, LMOTS_SHAKE_N32_W8 new TestCase( - new InvalidKeySpecException(), - false, // expected result + null, // exception + true, // expected result decode(""" 00000001 0000000f @@ -611,6 +615,83 @@ public class TestHSS { ), // Test Case #6 + // RFC 9858 A.4 + // LMS_SHA256_M24_H20, LMOTS_SHA256_N24_W4 + new TestCase( + null, // exception + true, // expected result + decode(""" + 00000001 + 0000000d + 00000007 + 404142434445464748494a4b4c4d4e4f9c08a50d170406869892802ee4142fcd + eac990f110c2460c"""), + decode(""" + 54657374206d65737361676520666f72205348413235362f31393220773d34 + """), + decode(""" + 00000000 + 00000064 + 00000007 + 853fa6e1a65fef076acd2485505b93be9aeb2641e3d3805c1887f26f4bcdb6ac + 0337b76fa5d6603834287e010b20516f7c336df2134c0a981f1ec2bb7baee516 + e91e67d3bd16c8d945a7f2be4fd84a604ae3743efc609ee0e69572e9c6d4a682 + 50e877b75d3cae63e9d5c15a32bb3cd17045f6b3e195284fdd1ee3cfbe18f1cb + d06ef3e7af34b1844d42dac453115a4507ed525cec120d054b403c61a7e5034f + ac4be6ef5412d194d4b6bbc0ae6cd3fe9993d583ee06f4030bc832efec24d1f7 + 13f5088731b91a98491fa3adf1b322bce26df24c8415e3a46bdfe07a6fd48e6d + 951515758cd6434991098bf6949249fca338ec235871dd564998d07d9b1b1b8d + 644e657fee8039da8fe195d129faddb12d543b86b0ab8cf6f26c121783f3b828 + d03f793b42909272f688e4ef6d46e82bdd1a02b1ff86c3b79920b2e6f19faf75 + c623242f1f2c549f84fb2f4c3ffead3120d97baea507467bb2da79f132bbe15b + 596fdfcb70983107ebca2597de9d55bd83bcae5c28a85259dadb354859986e60 + c8afa0b10bd08a8f9ed9b1ede3377075fe0ae36349f7d2ed7bfc9ece0d4cd697 + 2059329419feaf3b9a1045b6cfa4ae89b1cea8950aea4af870d1a3a3909ebc5a + 3013d6deb927abc0f95093e83cb36a9c1d6f13add19268ac7a0371f8335b0952 + a57fdb0141d55d937dd6ebb08fee8a5cf426ac97d54ee7aa17e6c57be5e62a52 + a6b1b986730d3a3aad8a7d327ddf883e6bc7b636eb2a5c4f2a635ae5bada5418 + d43dfedb69c0a0209334fac89d420d6ad5a2e1df95d26a1bfeb99a5e8455061b + fdf2d6e8394caf8a4be699b8afa38e524d4053330af478f85bf33d3ca3a35bc9 + 6987282bd513a8f6a52db9ba36aa90882b3bf573fa275449d8d49eb30bed2bb1 + 7a0ecc7d8a20807f2ea3dd37acd46c713cc2ac9d01a20a30d6832eef86a1e26d + 1cad7761bf4130a6565572766026509deeddaf46b605452b218a4e137a7ce063 + b546a35c52510f0ea2cac879192ec443e43b37c5ffa23da7a7fc254324a3de70 + 5c771794f10ea356e5a747e5146fd804a47719803c185b380e34b8dcc8269c2b + 073d86b2307cf90c6c3ef9271f2d53df2579f0c4cfb632db37a9025965f70b46 + 16673228e98644be6576417b7a97f104350259e7f697408cdf8cf81a3e774162 + 6ccdb87ad8531264cb5ceb7c8c097cec505091a3ee3a826c54f78169abc2e7d0 + a318dac10250ba940e51e79a3f572fb32bf442be6fd81267946e6387f9a8c705 + d945c653f2684655e3fa6b9ee311d8a091bef9898292fa272fb8761f066c23d8 + 7aa10d67871cc5419c843b796855c51ad1272e9264acd2035a82b12c2ddbc85a + dfcd7c22366a36495349391dbf0001064b8f6b28365445d733e48f1b058a6cb3 + e71bbb8df3e90406299894f4ca682943ceeba410b33b07716ffc18d6eab75f2d + 6372f1133605fa3c3ed66f2d8f7c5abe59e87d4500965e347523d73cb356c144 + 827aaa22b1c72a15293c7400e02aaefcf36f68a8246900e6e6228e7ad19d1450 + c23434f1e45043dc2b6db57f20d8f5b344d4162aa651333287cd8bf8fac41c78 + d61fe2929209bfe2dc5a2f80205c043b22e540a29f0ea0a5ff529e55bf1dfe42 + 96fc4bb4ac2e875322ab115db479fe979d64f78409af4ec3ad3b758fff83af1b + 9c48e90ca39366f426c2fb921df55c72786a9217723945a1ac1a66af7def4f8b + 367001732cce0e5bac91ac9d603807f8bab105b46d315d4cb88feb1c8686884b + 0000000d + 13d1a8ef00c5811c15c4d774fdcf75155315aff53ebdff8fb6a54f12c165963d + d5690cc9842b0e2190afc5443497584c832155599d00aced84bb3b59170396f7 + db4fa84aa8577f76cf9367d6e99d3d5be3555d7156b004f2002f505681b1ad22 + 9b9b46a666672aa8ee662c3a0456a9adda7a44fbaca46789577dcd36dc5cdff3 + 4b864d0a32492a0acbcaa6c011748f205b91ab2ab84f2333fb3e3b9acaecdac3 + 8b58aa5f32e718e225631ed6674cccb8c119acbd4992ab3130a6e912deec5983 + 5ab52fbc549430f8b403e4a2a51cc7f46fc143d365763aa1708fd25bcd657a79 + 0e54718d970906242a3b8a97dff18e91a44c4ba818a8dd2d242251265b023b82 + 6077eb740f6682e6c4ada2b85a67988d406132c2ad899099e44cfe610c3a5af7 + 0b406224411a59597e5dda0f31cd16c914b67e96141661f0074f43eb02273481 + bc324ded26c64f2388559d8c8bd0ef8b34ca4afebfac2a689b4246c264241488 + dcf922350dc44f7bc09d57dc1126291b2318810e0f44801c071e572fd032c780 + f44c9503a4c03c37417dc96422ba0849c37956f9fd5d33ea4fcab84276effec6 + 52ca77d7d47ac93c633d99e0a236f03d5587d1990ffaef737fced1f5cdd8f373 + 844e9f316aad41a0b12302639f83a2d74c9fe30d305a942bc0c30352a5e44dfb + """) + ), + + // Test Case #7 // LMSigParameters.lms_sha256_m32_h15, LMOtsParameters.sha256_n32_w8 new TestCase( null, // exception @@ -713,7 +794,7 @@ public class TestHSS { """) ), - // Test Case #7 + // Test Case #8 // LMSigParameters.lms_sha256_m32_h20, LMOtsParameters.sha256_n32_w8 new TestCase( null, // exception @@ -821,7 +902,7 @@ public class TestHSS { """) ), - // Test Case #8 + // Test Case #9 // LMSigParameters.lms_sha256_m32_h15, LMOtsParameters.sha256_n32_w4 new TestCase( null, // exception @@ -957,7 +1038,7 @@ public class TestHSS { """) ), - // Test Case #9 + // Test Case #10 // LMSigParameters.lms_sha256_m32_h20, LMOtsParameters.sha256_n32_w4 new TestCase( null, // exception @@ -1098,7 +1179,7 @@ public class TestHSS { """) ), - // Test Case #10 + // Test Case #11 // LMSigParameters.lms_sha256_m32_h15, LMOtsParameters.sha256_n32_w4 // LMSigParameters.lms_sha256_m32_h10, LMOtsParameters.sha256_n32_w4 new TestCase( @@ -1320,7 +1401,7 @@ public class TestHSS { """) ), - // Test Case #11 + // Test Case #12 // LMSigParameters.lms_sha256_m32_h15, LMOtsParameters.sha256_n32_w4 // LMSigParameters.lms_sha256_m32_h15, LMOtsParameters.sha256_n32_w4 new TestCase( @@ -1547,7 +1628,7 @@ public class TestHSS { """) ), - // Test Case #12 + // Test Case #13 // LMSigParameters.lms_sha256_m32_h20, LMOtsParameters.sha256_n32_w4 // LMSigParameters.lms_sha256_m32_h10, LMOtsParameters.sha256_n32_w4 new TestCase( @@ -1774,7 +1855,7 @@ public class TestHSS { """) ), - // Test Case #13 + // Test Case #14 // LMSigParameters.lms_sha256_m32_h20, LMOtsParameters.sha256_n32_w4 // LMSigParameters.lms_sha256_m32_h15, LMOtsParameters.sha256_n32_w4 new TestCase( @@ -2006,7 +2087,7 @@ public class TestHSS { """) ), - // Test Case #14 + // Test Case #15 // LMS signature length is incorrect new TestCase( new SignatureException(), @@ -2119,7 +2200,7 @@ public class TestHSS { """) ), - // Test Case #15 + // Test Case #16 // HSS signature and public key have different tree heights new TestCase( new SignatureException(), @@ -2232,7 +2313,7 @@ public class TestHSS { """) ), - // Test Case #16 + // Test Case #17 // bad signature new TestCase( null, // exception @@ -2345,7 +2426,7 @@ public class TestHSS { """) ), - // Test Case #17 + // Test Case #18 // Invalid key in HSS signature new TestCase( new SignatureException(), @@ -2458,7 +2539,7 @@ public class TestHSS { """) ), - // Test Case #18 + // Test Case #19 // LMS signature is too short new TestCase( new SignatureException(), @@ -2485,7 +2566,7 @@ public class TestHSS { 965a25bfd37f196b9073f3d4a232feb6""") ), - // Test Case #19 + // Test Case #20 // bad signature new TestCase( null, // exception From 9d6a94ef6789f62ae47f0112e75dc446000e63f4 Mon Sep 17 00:00:00 2001 From: Mahendra Chhipa Date: Mon, 13 Apr 2026 22:43:57 +0000 Subject: [PATCH 267/359] 8368091: Use JUnit Jupiter API in sun/net/ext, sun/net/www and sun/net/spi tests Reviewed-by: dfuchs --- .../net/ext/ExtendedSocketOptionsTest.java | 25 +-- .../sun/net/spi/DefaultProxySelectorTest.java | 34 ++-- test/jdk/sun/net/www/MessageHeaderTest.java | 17 +- .../KeepAliveStreamCleanerTestDriver.java | 4 +- .../www/http/KeepAliveStreamCleanerTest.java | 6 +- .../RequestMethodEquality.java | 29 +-- .../protocol/file/DirPermissionDenied.java | 19 +- .../protocol/http/HttpHeaderParserTest.java | 166 +++++++++--------- .../protocol/http/TestTransparentNTLM.java | 40 ++--- .../jar/MultiReleaseJarURLConnection.java | 96 +++++----- test/jdk/sun/net/www/protocol/jrt/Basic.java | 34 ++-- 11 files changed, 234 insertions(+), 236 deletions(-) diff --git a/test/jdk/sun/net/ext/ExtendedSocketOptionsTest.java b/test/jdk/sun/net/ext/ExtendedSocketOptionsTest.java index d42d780db9d..af9345953b8 100644 --- a/test/jdk/sun/net/ext/ExtendedSocketOptionsTest.java +++ b/test/jdk/sun/net/ext/ExtendedSocketOptionsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,8 +21,7 @@ * questions. */ -import org.testng.Assert; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import java.util.ArrayList; import java.util.Collections; @@ -33,6 +32,10 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertSame; + /** * @test * @bug 8260366 @@ -40,11 +43,11 @@ import java.util.concurrent.Future; * jdk.net.ExtendedSocketOptions doesn't lead to a deadlock * @modules java.base/sun.net.ext:open * jdk.net - * @run testng/othervm ExtendedSocketOptionsTest - * @run testng/othervm ExtendedSocketOptionsTest - * @run testng/othervm ExtendedSocketOptionsTest - * @run testng/othervm ExtendedSocketOptionsTest - * @run testng/othervm ExtendedSocketOptionsTest + * @run junit/othervm ${test.main.class} + * @run junit/othervm ${test.main.class} + * @run junit/othervm ${test.main.class} + * @run junit/othervm ${test.main.class} + * @run junit/othervm ${test.main.class} */ public class ExtendedSocketOptionsTest { @@ -83,13 +86,13 @@ public class ExtendedSocketOptionsTest { // check that the sun.net.ext.ExtendedSocketOptions#getInstance() does indeed return // the registered instance final Object extSocketOptions = callSunNetExtSocketOptionsGetInstance(); - Assert.assertNotNull(extSocketOptions, "sun.net.ext.ExtendedSocketOptions#getInstance()" + + assertNotNull(extSocketOptions, "sun.net.ext.ExtendedSocketOptions#getInstance()" + " unexpectedly returned null"); // now verify that each call to getInstance(), either in the tasks or here, returned the exact // same instance of ExtendedSocketOptions - Assert.assertEquals(2, GetInstanceTask.extendedSocketOptionsInstances.size()); + assertEquals(2, GetInstanceTask.extendedSocketOptionsInstances.size()); for (final Object inst : GetInstanceTask.extendedSocketOptionsInstances) { - Assert.assertSame(inst, extSocketOptions, "sun.net.ext.ExtendedSocketOptions#getInstance()" + + assertSame(extSocketOptions, inst, "sun.net.ext.ExtendedSocketOptions#getInstance()" + " returned different instances"); } } diff --git a/test/jdk/sun/net/spi/DefaultProxySelectorTest.java b/test/jdk/sun/net/spi/DefaultProxySelectorTest.java index 5fdff96f5f2..d070d843fee 100644 --- a/test/jdk/sun/net/spi/DefaultProxySelectorTest.java +++ b/test/jdk/sun/net/spi/DefaultProxySelectorTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * 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,18 +21,19 @@ * questions. */ -import org.testng.Assert; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import sun.net.spi.DefaultProxySelector; import java.net.ProxySelector; import java.net.URI; +import static org.junit.jupiter.api.Assertions.assertThrows; + /** * @test * @bug 6563286 6797318 8177648 * @summary Tests sun.net.spi.DefaultProxySelector#select(URI) - * @run testng DefaultProxySelectorTest + * @run junit ${test.main.class} * @modules java.base/sun.net.spi:+open */ public class DefaultProxySelectorTest { @@ -44,12 +45,7 @@ public class DefaultProxySelectorTest { @Test public void testIllegalArgForNull() { final ProxySelector selector = new DefaultProxySelector(); - try { - selector.select(null); - Assert.fail("select() was expected to fail for null URI"); - } catch (IllegalArgumentException iae) { - // expected - } + assertThrows(IllegalArgumentException.class, () -> selector.select(null)); } /** @@ -61,12 +57,11 @@ public class DefaultProxySelectorTest { @Test public void testIllegalArgForNoHost() throws Exception { final ProxySelector selector = new DefaultProxySelector(); - assertFailsWithIAE(selector, new URI("http", "/test", null)); - assertFailsWithIAE(selector, new URI("https", "/test2", null)); - assertFailsWithIAE(selector, new URI("ftp", "/test3", null)); + assertThrows(IllegalArgumentException.class, () -> selector.select(new URI("http", "/test", null))); + assertThrows(IllegalArgumentException.class, () -> selector.select(new URI("https", "/test2", null))); + assertThrows(IllegalArgumentException.class, () -> selector.select(new URI("ftp", "/test3", null))); } - /** * Tests that {@link DefaultProxySelector} throws a {@link IllegalArgumentException} * for URIs that don't have protocol/scheme information @@ -76,15 +71,6 @@ public class DefaultProxySelectorTest { @Test public void testIllegalArgForNoScheme() throws Exception { final ProxySelector selector = new DefaultProxySelector(); - assertFailsWithIAE(selector, new URI(null, "/test", null)); - } - - private static void assertFailsWithIAE(final ProxySelector selector, final URI uri) { - try { - selector.select(uri); - Assert.fail("select() was expected to fail for URI " + uri); - } catch (IllegalArgumentException iae) { - // expected - } + assertThrows(IllegalArgumentException.class, () -> selector.select(new URI(null, "/test", null))); } } diff --git a/test/jdk/sun/net/www/MessageHeaderTest.java b/test/jdk/sun/net/www/MessageHeaderTest.java index 903e805f5f4..6928173df67 100644 --- a/test/jdk/sun/net/www/MessageHeaderTest.java +++ b/test/jdk/sun/net/www/MessageHeaderTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,16 +25,17 @@ * @test * @bug 8003948 8133686 * @modules java.base/sun.net.www - * @run testng MessageHeaderTest + * @run junit ${test.main.class} */ import java.io.*; import java.util.*; -import org.testng.Assert; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; import sun.net.www.MessageHeader; +import static org.junit.jupiter.api.Assertions.assertEquals; + public class MessageHeaderTest { /* This test checks to see if the MessageHeader.getHeaders method returns headers with the same value field in the order they were added @@ -53,12 +54,12 @@ public class MessageHeaderTest { var actualHeaders = testHeader.getHeaders().get("test"); - Assert.assertEquals(expectedHeaders, actualHeaders, String.format(errorMessageTemplate, expectedHeaders.toString(), actualHeaders.toString())); + assertEquals(expectedHeaders, actualHeaders, String.format(errorMessageTemplate, expectedHeaders.toString(), actualHeaders.toString())); } @Test public void ntlmNegotiateTest () throws Exception { - String expected[] = { + String[] expected = { "{null: HTTP/1.1 200 Ok}{Foo: bar}{Bar: foo}{WWW-Authenticate: NTLM sdsds}", "{null: HTTP/1.1 200 Ok}{Foo: bar}{Bar: foo}{WWW-Authenticate: }", "{null: HTTP/1.1 200 Ok}{Foo: bar}{Bar: foo}{WWW-Authenticate: NTLM sdsds}", @@ -90,8 +91,8 @@ public class MessageHeaderTest { boolean result = h.filterNTLMResponses("WWW-Authenticate"); String after = h.toString(); after = after.substring(after.indexOf('{')); - Assert.assertEquals(expected[i], after, i + " expected != after"); - Assert.assertEquals(result, expectedResult[i], i + " result != expectedResult"); + assertEquals(expected[i], after, i + " expected != after"); + assertEquals(expectedResult[i], result, i + " result != expectedResult"); } } } diff --git a/test/jdk/sun/net/www/http/KeepAliveStreamCleaner/KeepAliveStreamCleanerTestDriver.java b/test/jdk/sun/net/www/http/KeepAliveStreamCleaner/KeepAliveStreamCleanerTestDriver.java index 5f66aff365e..bf7553acf62 100644 --- a/test/jdk/sun/net/www/http/KeepAliveStreamCleaner/KeepAliveStreamCleanerTestDriver.java +++ b/test/jdk/sun/net/www/http/KeepAliveStreamCleaner/KeepAliveStreamCleanerTestDriver.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * 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,5 +26,5 @@ * @bug 8255124 * @summary Tests that KeepAliveStreamCleaner run does not throw an IllegalMonitorState Exception. * @modules java.base/sun.net.www.http - * @run testng java.base/sun.net.www.http.KeepAliveStreamCleanerTest + * @run junit java.base/sun.net.www.http.KeepAliveStreamCleanerTest */ diff --git a/test/jdk/sun/net/www/http/KeepAliveStreamCleaner/java.base/sun/net/www/http/KeepAliveStreamCleanerTest.java b/test/jdk/sun/net/www/http/KeepAliveStreamCleaner/java.base/sun/net/www/http/KeepAliveStreamCleanerTest.java index b4bc638099d..d927e0a8029 100644 --- a/test/jdk/sun/net/www/http/KeepAliveStreamCleaner/java.base/sun/net/www/http/KeepAliveStreamCleanerTest.java +++ b/test/jdk/sun/net/www/http/KeepAliveStreamCleaner/java.base/sun/net/www/http/KeepAliveStreamCleanerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * 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,9 +23,9 @@ package sun.net.www.http; -import org.testng.annotations.Test; -@Test +import org.junit.jupiter.api.Test; + public class KeepAliveStreamCleanerTest { /* diff --git a/test/jdk/sun/net/www/http/RequestMethodCheck/RequestMethodEquality.java b/test/jdk/sun/net/www/http/RequestMethodCheck/RequestMethodEquality.java index 290248989d8..364bafd0749 100644 --- a/test/jdk/sun/net/www/http/RequestMethodCheck/RequestMethodEquality.java +++ b/test/jdk/sun/net/www/http/RequestMethodCheck/RequestMethodEquality.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * 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,17 +30,16 @@ * @modules java.base/sun.net.www.http * java.base/sun.net.www.protocol.http * @build java.base/sun.net.www.http.HttpClientAccess - * @run testng/othervm RequestMethodEquality + * @run junit/othervm ${test.main.class} */ import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpHandler; import com.sun.net.httpserver.HttpServer; import jdk.test.lib.net.URIBuilder; -import org.testng.Assert; -import org.testng.annotations.AfterTest; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.Test; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; import sun.net.www.http.HttpClient; import sun.net.www.http.HttpClientAccess; import sun.net.www.http.KeepAliveCache; @@ -52,21 +51,23 @@ import java.net.InetSocketAddress; import java.net.Proxy; import java.net.URL; +import static org.junit.jupiter.api.Assertions.assertNotEquals; + public class RequestMethodEquality { private static final String TEST_CONTEXT = "/reqmethodtest"; - private HttpServer server; - private CustomHandler handler; - private HttpClientAccess httpClientAccess; + private static HttpServer server; + private static CustomHandler handler; + private static HttpClientAccess httpClientAccess; - @BeforeTest - public void setup() throws Exception { + @BeforeAll + public static void setup() throws Exception { handler = new CustomHandler(); server = createServer(handler); httpClientAccess = new HttpClientAccess(); } - @AfterTest - public void tearDown() throws Exception { + @AfterAll + public static void tearDown() throws Exception { if (server != null) { server.stop(0); } @@ -111,7 +112,7 @@ public class RequestMethodEquality { // If both connectTimeout values are equal, it means the test retrieved the same broken // HttpClient from the cache and is trying to re-use it. - Assert.assertNotEquals(originalConnectTimeout, cachedConnectTimeout, "Both connectTimeout values are equal.\nThis means the test is reusing a broken HttpClient rather than creating a new one."); + assertNotEquals(originalConnectTimeout, cachedConnectTimeout, "Both connectTimeout values are equal.\nThis means the test is reusing a broken HttpClient rather than creating a new one."); } finally { if (conn != null) { conn.disconnect(); diff --git a/test/jdk/sun/net/www/protocol/file/DirPermissionDenied.java b/test/jdk/sun/net/www/protocol/file/DirPermissionDenied.java index 0e3f9e86c4e..b6d8790bb5b 100644 --- a/test/jdk/sun/net/www/protocol/file/DirPermissionDenied.java +++ b/test/jdk/sun/net/www/protocol/file/DirPermissionDenied.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,7 @@ * @library /test/lib * @build DirPermissionDenied jdk.test.lib.process.* * jdk.test.lib.util.FileUtils - * @run testng DirPermissionDenied + * @run junit ${test.main.class} */ import java.io.IOException; @@ -41,9 +41,10 @@ import java.nio.file.Paths; import jdk.test.lib.process.ProcessTools; import jdk.test.lib.util.FileUtils; -import org.testng.annotations.AfterTest; -import org.testng.annotations.Test; -import org.testng.annotations.BeforeTest; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + public class DirPermissionDenied { private static final Path TEST_DIR = Paths.get( "DirPermissionDeniedDirectory"); @@ -79,8 +80,8 @@ public class DirPermissionDenied { } } - @BeforeTest - public void setup() throws Throwable { + @BeforeAll + public static void setup() throws Throwable { // mkdir and chmod "333" Files.createDirectories(TEST_DIR); ProcessTools.executeCommand("chmod", "333", TEST_DIR.toString()) @@ -89,8 +90,8 @@ public class DirPermissionDenied { .shouldHaveExitValue(0); } - @AfterTest - public void tearDown() throws Throwable { + @AfterAll + public static void tearDown() throws Throwable { // add read permission to ensure the dir removable ProcessTools.executeCommand("chmod", "733", TEST_DIR.toString()) .outputTo(System.out) diff --git a/test/jdk/sun/net/www/protocol/http/HttpHeaderParserTest.java b/test/jdk/sun/net/www/protocol/http/HttpHeaderParserTest.java index 245cd49d518..ad3b3fa3722 100644 --- a/test/jdk/sun/net/www/protocol/http/HttpHeaderParserTest.java +++ b/test/jdk/sun/net/www/protocol/http/HttpHeaderParserTest.java @@ -1,7 +1,7 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,13 +28,12 @@ * @library /test/lib * @summary Sanity check that HttpHeaderParser works same as MessageHeader * @modules java.base/sun.net.www java.base/sun.net.www.protocol.http:open - * @run testng/othervm HttpHeaderParserTest + * @run junit/othervm ${test.main.class} */ import java.io.ByteArrayInputStream; import java.io.IOException; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -45,20 +44,21 @@ import java.util.concurrent.atomic.AtomicInteger; import static java.lang.String.format; import static java.nio.charset.StandardCharsets.ISO_8859_1; import static java.nio.charset.StandardCharsets.US_ASCII; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + import jdk.test.lib.net.HttpHeaderParser; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; import sun.net.www.MessageHeader; public class HttpHeaderParserTest { - @DataProvider(name = "responses") - public Object[][] responses() { + public static List responses() { List responses = new ArrayList<>(); - - String[] basic = - { "HTTP/1.1 200 OK\r\n\r\n", + List basic = List.of( + "HTTP/1.1 200 OK\r\n\r\n", "HTTP/1.1 200 OK\r\n" + "Date: Mon, 15 Jan 2001 12:18:21 GMT\r\n" + @@ -142,11 +142,11 @@ public class HttpHeaderParserTest { "Vary: Host,Accept-Encoding,User-Agent\r\n" + "X-Mod-Pagespeed: 1.12.34.2-0\r\n" + "Connection: keep-alive\r\n\r\n" - }; - Arrays.stream(basic).forEach(responses::add); + ); + responses.addAll(basic); // add some tests where some of the CRLF are replaced // by a single LF - Arrays.stream(basic) + basic.stream() .map(HttpHeaderParserTest::mixedCRLF) .forEach(responses::add); @@ -211,8 +211,8 @@ public class HttpHeaderParserTest { responses.add(mixedCRLF(template).replace("$NEWLINE", newLineChar)); } - String[] bad = // much of this is to retain parity with legacy MessageHeaders - { "HTTP/1.1 200 OK\r\n" + + List bad = List.of( // much of this is to retain parity with legacy MessageHeaders + "HTTP/1.1 200 OK\r\n" + "Connection:\r\n\r\n", // empty value, no body "HTTP/1.1 200 OK\r\n" + @@ -258,12 +258,11 @@ public class HttpHeaderParserTest { "HTTP/1.0 404 Not Found\r\n" + "header-without-colon\r\n\r\n" + - "SOMEBODY", + "SOMEBODY" - }; - Arrays.stream(bad).forEach(responses::add); - - return responses.stream().map(p -> new Object[] { p }).toArray(Object[][]::new); + ); + responses.addAll(bad); + return responses; } static final AtomicInteger index = new AtomicInteger(); @@ -318,8 +317,8 @@ public class HttpHeaderParserTest { return res.toString(); } - - @Test(dataProvider = "responses") + @ParameterizedTest + @MethodSource("responses") public void verifyHeaders(String respString) throws Exception { System.out.println("\ntesting:\n\t" + respString .replace("\r\n", "") @@ -344,7 +343,7 @@ public class HttpHeaderParserTest { String statusLine1 = messageHeaderMap.get(null).get(0); String statusLine2 = decoder.getRequestDetails(); if (statusLine1.startsWith("HTTP")) {// skip the case where MH's messes up the status-line - assertEquals(statusLine2, statusLine1, "Status-line not equal"); + assertEquals(statusLine1, statusLine2, "Status-line not equal"); } else { assertTrue(statusLine2.startsWith("HTTP/1."), "Status-line not HTTP/1."); } @@ -366,91 +365,86 @@ public class HttpHeaderParserTest { availableBytes, headerStream.available())); } - @DataProvider(name = "errors") - public Object[][] errors() { - List responses = new ArrayList<>(); - + public static List errors() { // These responses are parsed, somewhat, by MessageHeaders but give // nonsensible results. They, correctly, fail with the Http1HeaderParser. - String[] bad = - {// "HTTP/1.1 402 Payment Required\r\n" + - // "Content-Length: 65\r\n\r", // missing trailing LF //TODO: incomplete + List responses = List.of( + // "HTTP/1.1 402 Payment Required\r\n" + + // "Content-Length: 65\r\n\r", // missing trailing LF //TODO: incomplete - "HTTP/1.1 402 Payment Required\r\n" + - "Content-Length: 65\r\n\rT\r\n\r\nGGGGGG", + "HTTP/1.1 402 Payment Required\r\n" + + "Content-Length: 65\r\n\rT\r\n\r\nGGGGGG", - "HTTP/1.1 200OK\r\n\rT", + "HTTP/1.1 200OK\r\n\rT", - "HTTP/1.1 200OK\rT", + "HTTP/1.1 200OK\rT", - "HTTP/1.0 FOO\r\n", + "HTTP/1.0 FOO\r\n", - "HTTP/1.1 BAR\r\n", + "HTTP/1.1 BAR\r\n", - "HTTP/1.1 +99\r\n", + "HTTP/1.1 +99\r\n", - "HTTP/1.1 -22\r\n", + "HTTP/1.1 -22\r\n", - "HTTP/1.1 -20 \r\n", + "HTTP/1.1 -20 \r\n", + "HTTP/1.1 200 OK\r\n" + + "X-fo\u00ffo: foo\r\n" + // invalid char in name + "Content-Length: 5\r\n" + + "Content-Type: text/html; charset=UTF-8\r\n\r\n" + + "XXXXX", + + "HTTP/1.1 200 OK\r\n" + "HTTP/1.1 200 OK\r\n" + - "X-fo\u00ffo: foo\r\n" + // invalid char in name - "Content-Length: 5\r\n" + - "Content-Type: text/html; charset=UTF-8\r\n\r\n" + - "XXXXX", + "X-foo : bar\r\n" + // trim space after name + "Content-Length: 5\r\n" + + "Content-Type: text/html; charset=UTF-8\r\n\r\n" + + "XXXXX", - "HTTP/1.1 200 OK\r\n" + - "HTTP/1.1 200 OK\r\n" + - "X-foo : bar\r\n" + // trim space after name - "Content-Length: 5\r\n" + - "Content-Type: text/html; charset=UTF-8\r\n\r\n" + - "XXXXX", + "HTTP/1.1 200 OK\r\n" + + " X-foo: bar\r\n" + // trim space before name + "Content-Length: 5\r\n" + + "Content-Type: text/html; charset=UTF-8\r\n\r\n" + + "XXXXX", - "HTTP/1.1 200 OK\r\n" + - " X-foo: bar\r\n" + // trim space before name - "Content-Length: 5\r\n" + - "Content-Type: text/html; charset=UTF-8\r\n\r\n" + - "XXXXX", + "HTTP/1.1 200 OK\r\n" + + "X foo: bar\r\n" + // invalid space in name + "Content-Length: 5\r\n" + + "Content-Type: text/html; charset=UTF-8\r\n\r\n" + + "XXXXX", - "HTTP/1.1 200 OK\r\n" + - "X foo: bar\r\n" + // invalid space in name - "Content-Length: 5\r\n" + - "Content-Type: text/html; charset=UTF-8\r\n\r\n" + - "XXXXX", + "HTTP/1.1 200 OK\r\n" + + "Content-Length: 5\r\n" + + "Content Type: text/html; charset=UTF-8\r\n\r\n" + // invalid space in name + "XXXXX", - "HTTP/1.1 200 OK\r\n" + - "Content-Length: 5\r\n" + - "Content Type: text/html; charset=UTF-8\r\n\r\n" + // invalid space in name - "XXXXX", + "HTTP/1.1 200 OK\r\n" + + "Conte\r" + + " nt-Length: 9\r\n" + // fold results in space in header name + "Content-Type: text/html; charset=UTF-8\r\n\r\n" + + "XXXXX", - "HTTP/1.1 200 OK\r\n" + - "Conte\r" + - " nt-Length: 9\r\n" + // fold results in space in header name - "Content-Type: text/html; charset=UTF-8\r\n\r\n" + - "XXXXX", + "HTTP/1.1 200 OK\r\n" + + " : no header\r\n" + // all blank header-name (not fold) + "Content-Length: 65\r\n\r\n" + + "XXXXX", - "HTTP/1.1 200 OK\r\n" + - " : no header\r\n" + // all blank header-name (not fold) - "Content-Length: 65\r\n\r\n" + - "XXXXX", + "HTTP/1.1 200 OK\r\n" + + " \t : no header\r\n" + // all blank header-name (not fold) + "Content-Length: 65\r\n\r\n" + + "XXXXX"); - "HTTP/1.1 200 OK\r\n" + - " \t : no header\r\n" + // all blank header-name (not fold) - "Content-Length: 65\r\n\r\n" + - "XXXXX", - - }; - Arrays.stream(bad).forEach(responses::add); - - return responses.stream().map(p -> new Object[] { p }).toArray(Object[][]::new); + return responses; } - @Test(dataProvider = "errors", expectedExceptions = IOException.class) + @ParameterizedTest + @MethodSource("errors") public void errors(String respString) throws IOException { byte[] bytes = respString.getBytes(US_ASCII); HttpHeaderParser decoder = new HttpHeaderParser(); ByteArrayInputStream bais = new ByteArrayInputStream(bytes); - decoder.parse(bais); + assertThrows(IOException.class, () -> decoder.parse(bais)); } void assertHeadersEqual(Map> expected, @@ -477,7 +471,7 @@ public class HttpHeaderParserTest { format("%s. Expected list size %d, actual size %s", msg, values.size(), otherValues.size())); if (!(values.containsAll(otherValues) && otherValues.containsAll(values))) - assertTrue(false, format("Lists are unequal [%s] [%s]", values, otherValues)); + fail(format("Lists are unequal [%s] [%s]", values, otherValues)); break; } } diff --git a/test/jdk/sun/net/www/protocol/http/TestTransparentNTLM.java b/test/jdk/sun/net/www/protocol/http/TestTransparentNTLM.java index 0df834765c8..1c2262ba8e2 100644 --- a/test/jdk/sun/net/www/protocol/http/TestTransparentNTLM.java +++ b/test/jdk/sun/net/www/protocol/http/TestTransparentNTLM.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,18 +28,18 @@ * and is used only when the relevant property is set. * @requires os.family == "windows" * @library /test/lib - * @run testng/othervm + * @run junit/othervm * -Dtest.auth.succeed=false * TestTransparentNTLM - * @run testng/othervm + * @run junit/othervm * -Djdk.http.ntlm.transparentAuth=allHosts * -Dtest.auth.succeed=true * TestTransparentNTLM - * @run testng/othervm + * @run junit/othervm * -Djdk.http.ntlm.transparentAuth=blahblah * -Dtest.auth.succeed=false * TestTransparentNTLM - * @run testng/othervm + * @run junit/othervm * -Djdk.http.ntlm.transparentAuth=trustedHosts * -Dtest.auth.succeed=false * TestTransparentNTLM @@ -57,21 +57,21 @@ import java.net.ServerSocket; import java.net.Socket; import java.net.URL; import jdk.test.lib.net.URIBuilder; -import org.testng.annotations.AfterTest; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.Test; -import org.testng.SkipException; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + import static java.lang.System.out; import static java.net.Proxy.NO_PROXY; import static java.nio.charset.StandardCharsets.UTF_8; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; public class TestTransparentNTLM { - boolean succeed; // true if authentication is expected to succeed - Server server; - URL url; + static boolean succeed; // true if authentication is expected to succeed + static Server server; + static URL url; @Test public void testNTLM() throws IOException { @@ -81,11 +81,11 @@ public class TestTransparentNTLM { out.println("received: " + respCode); if (succeed) { - assertEquals(respCode, HttpURLConnection.HTTP_OK); + assertEquals(HttpURLConnection.HTTP_OK, respCode); String body = new String(uc.getInputStream().readAllBytes(), UTF_8); out.println("received body: " + body); } else { - assertEquals(respCode, HttpURLConnection.HTTP_UNAUTHORIZED); + assertEquals(HttpURLConnection.HTTP_UNAUTHORIZED, respCode); } } @@ -169,8 +169,8 @@ public class TestTransparentNTLM { } } - @BeforeTest - public void setup() throws Exception { + @BeforeAll + public static void setup() throws Exception { succeed = System.getProperty("test.auth.succeed").equals("true"); if (succeed) out.println("Expect client to succeed, with 200 Ok"); @@ -187,8 +187,8 @@ public class TestTransparentNTLM { .toURL(); } - @AfterTest - public void teardown() throws Exception { + @AfterAll + public static void teardown() throws Exception { server.close(); server.join(); } diff --git a/test/jdk/sun/net/www/protocol/jar/MultiReleaseJarURLConnection.java b/test/jdk/sun/net/www/protocol/jar/MultiReleaseJarURLConnection.java index f113e7d3fcd..3be7dd5bd98 100644 --- a/test/jdk/sun/net/www/protocol/jar/MultiReleaseJarURLConnection.java +++ b/test/jdk/sun/net/www/protocol/jar/MultiReleaseJarURLConnection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,7 @@ * @build CreateMultiReleaseTestJars * jdk.test.lib.util.JarBuilder * jdk.test.lib.compiler.Compiler - * @run testng MultiReleaseJarURLConnection + * @run junit ${test.main.class} */ import java.io.IOException; @@ -59,22 +59,27 @@ import java.util.jar.JarFile; import com.sun.net.httpserver.HttpServer; import com.sun.net.httpserver.SimpleFileServer; import jdk.test.lib.net.URIBuilder; -import org.testng.Assert; -import org.testng.annotations.AfterClass; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; public class MultiReleaseJarURLConnection { - String userdir = System.getProperty("user.dir", "."); - String unversioned = userdir + "/unversioned.jar"; - String unsigned = userdir + "/multi-release.jar"; - String signed = userdir + "/signed-multi-release.jar"; - HttpServer server; - ExecutorService executor; + static String userdir = System.getProperty("user.dir", "."); + static String unversioned = userdir + "/unversioned.jar"; + static String unsigned = userdir + "/multi-release.jar"; + static String signed = userdir + "/signed-multi-release.jar"; + static HttpServer server; + static ExecutorService executor; - @BeforeClass - public void initialize() throws Exception { + @BeforeAll + public static void initialize() throws Exception { CreateMultiReleaseTestJars creator = new CreateMultiReleaseTestJars(); creator.compileEntries(); creator.buildUnversionedJar(); @@ -87,8 +92,8 @@ public class MultiReleaseJarURLConnection { server.start(); } - @AfterClass - public void close() throws IOException { + @AfterAll + public static void close() throws IOException { // Windows requires server to stop before file is deleted if (server != null) server.stop(0); @@ -99,8 +104,7 @@ public class MultiReleaseJarURLConnection { Files.delete(Paths.get(signed)); } - @DataProvider(name = "data") - public Object[][] createData() { + public static Object[][] createData() { return new Object[][]{ {"unversioned", unversioned}, {"unsigned", unsigned}, @@ -108,20 +112,21 @@ public class MultiReleaseJarURLConnection { }; } - @Test(dataProvider = "data") + @ParameterizedTest + @MethodSource("createData") public void testRuntimeVersioning(String style, String file) throws Exception { String urlFile = "jar:file:" + file + "!/"; String baseUrlEntry = urlFile + "version/Version.java"; String rtreturn = "return " + Runtime.version().major(); - Assert.assertTrue(readAndCompare(new URL(baseUrlEntry), "return 8")); + assertTrue(readAndCompare(new URL(baseUrlEntry), "return 8")); // #runtime is "magic" for a multi-release jar, but not for unversioned jar - Assert.assertTrue(readAndCompare(new URL(baseUrlEntry + "#runtime"), + assertTrue(readAndCompare(new URL(baseUrlEntry + "#runtime"), style.equals("unversioned") ? "return 8" : rtreturn)); // #fragment or any other fragment is not magic - Assert.assertTrue(readAndCompare(new URL(baseUrlEntry + "#fragment"), "return 8")); + assertTrue(readAndCompare(new URL(baseUrlEntry + "#fragment"), "return 8")); // cached entities not affected - Assert.assertTrue(readAndCompare(new URL(baseUrlEntry), "return 8")); + assertTrue(readAndCompare(new URL(baseUrlEntry), "return 8")); // the following tests will not work with unversioned jars if (style.equals("unversioned")) @@ -130,13 +135,14 @@ public class MultiReleaseJarURLConnection { // direct access to versioned entry String versUrlEntry = urlFile + "META-INF/versions/" + Runtime.version().major() + "/version/Version.java"; - Assert.assertTrue(readAndCompare(new URL(versUrlEntry), rtreturn)); + assertTrue(readAndCompare(new URL(versUrlEntry), rtreturn)); // adding any fragment does not change things - Assert.assertTrue(readAndCompare(new URL(versUrlEntry + "#runtime"), rtreturn)); - Assert.assertTrue(readAndCompare(new URL(versUrlEntry + "#fragment"), rtreturn)); + assertTrue(readAndCompare(new URL(versUrlEntry + "#runtime"), rtreturn)); + assertTrue(readAndCompare(new URL(versUrlEntry + "#fragment"), rtreturn)); } - @Test(dataProvider = "data") + @ParameterizedTest + @MethodSource("createData") public void testCachedJars(String style, String file) throws Exception { String urlFile = "jar:file:" + file + "!/"; @@ -150,28 +156,27 @@ public class MultiReleaseJarURLConnection { JarFile runtimeJar = juc.getJarFile(); Runtime.Version runtime = runtimeJar.getVersion(); if (style.equals("unversioned")) { - Assert.assertEquals(root, runtime); + assertEquals(root, runtime); } else { - Assert.assertNotEquals(root, runtime); + assertNotEquals(root, runtime); } juc = (JarURLConnection) rootUrl.openConnection(); JarFile jar = juc.getJarFile(); - Assert.assertEquals(jar.getVersion(), root); - Assert.assertEquals(jar, rootJar); + assertEquals(root, jar.getVersion()); + assertEquals(rootJar, jar); juc = (JarURLConnection) runtimeUrl.openConnection(); jar = juc.getJarFile(); - Assert.assertEquals(jar.getVersion(), runtime); - Assert.assertEquals(jar, runtimeJar); + assertEquals(runtime, jar.getVersion()); + assertEquals(runtimeJar, jar); rootJar.close(); runtimeJar.close(); jar.close(); // probably not needed } - @DataProvider(name = "resourcedata") - public Object[][] createResourceData() throws Exception { + public static Object[][] createResourceData() throws Exception { return new Object[][]{ {"unversioned", Paths.get(unversioned).toUri().toURL()}, {"unsigned", Paths.get(unsigned).toUri().toURL()}, @@ -189,7 +194,8 @@ public class MultiReleaseJarURLConnection { }; } - @Test(dataProvider = "resourcedata") + @ParameterizedTest + @MethodSource("createResourceData") public void testResources(String style, URL url) throws Throwable { // System.out.println(" testing " + style + " url: " + url); URL[] urls = {url}; @@ -199,30 +205,28 @@ public class MultiReleaseJarURLConnection { // verify we are loading a runtime versioned class MethodType mt = MethodType.methodType(int.class); MethodHandle mh = MethodHandles.lookup().findVirtual(vcls, "getVersion", mt); - Assert.assertEquals((int)mh.invoke(vcls.newInstance()), - style.equals("unversioned") ? 8 : Runtime.version().major()); - + assertEquals(style.equals("unversioned") ? 8 : Runtime.version().major(), (int)mh.invoke(vcls.newInstance())); // now get a resource and verify that we don't have a fragment attached Enumeration vclsUrlEnum = cldr.getResources("version/Version.class"); - Assert.assertTrue(vclsUrlEnum.hasMoreElements()); + assertTrue(vclsUrlEnum.hasMoreElements()); URL vclsUrls[] = new URL[] { vcls.getResource("/version/Version.class"), vcls.getResource("Version.class"), cldr.getResource("version/Version.class"), vclsUrlEnum.nextElement() }; - Assert.assertFalse(vclsUrlEnum.hasMoreElements()); + assertFalse(vclsUrlEnum.hasMoreElements()); for (URL vclsUrl : vclsUrls) { String fragment = vclsUrl.getRef(); - Assert.assertNull(fragment); + assertNull(fragment); // and verify that the url is a reified pointer to the runtime entry String rep = vclsUrl.toString(); //System.out.println(" getResource(\"/version/Version.class\") returned: " + rep); if (style.equals("http")) { - Assert.assertTrue(rep.startsWith("jar:http:")); + assertTrue(rep.startsWith("jar:http:")); } else { - Assert.assertTrue(rep.startsWith("jar:file:")); + assertTrue(rep.startsWith("jar:file:")); } String suffix; if (style.equals("unversioned")) { @@ -231,7 +235,7 @@ public class MultiReleaseJarURLConnection { suffix = ".jar!/META-INF/versions/" + Runtime.version().major() + "/version/Version.class"; } - Assert.assertTrue(rep.endsWith(suffix)); + assertTrue(rep.endsWith(suffix)); } cldr.close(); } diff --git a/test/jdk/sun/net/www/protocol/jrt/Basic.java b/test/jdk/sun/net/www/protocol/jrt/Basic.java index 785920b4a4d..272d82bd4d6 100644 --- a/test/jdk/sun/net/www/protocol/jrt/Basic.java +++ b/test/jdk/sun/net/www/protocol/jrt/Basic.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * 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,21 +24,25 @@ /** * @test * @summary Basic test of jimage protocol handler - * @run testng Basic + * @run junit ${test.main.class} */ +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + import java.io.IOException; import java.net.URL; import java.net.URLConnection; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + public class Basic { - @DataProvider(name = "urls") - public Object[][] urls() { + public static Object[][] urls() { Object[][] data = { {"jrt:/java.base/java/lang/Object.class", true}, // Valid resource with and without percent-encoding. @@ -67,7 +71,8 @@ public class Basic { return data; } - @Test(dataProvider = "urls") + @ParameterizedTest + @MethodSource("urls") public void testConnect(String urlString, boolean exists) throws Exception { URL url = new URL(urlString); URLConnection uc = url.openConnection(); @@ -79,32 +84,35 @@ public class Basic { } } - @Test(dataProvider = "urls") + @ParameterizedTest + @MethodSource("urls") public void testInputStream(String urlString, boolean exists) throws Exception { URL url = new URL(urlString); URLConnection uc = url.openConnection(); try { int b = uc.getInputStream().read(); - assertTrue(b != -1); + assertNotEquals(-1, b); if (!exists) fail("IOException expected"); } catch (IOException ioe) { if (exists) fail("IOException not expected"); } } - @Test(dataProvider = "urls") + @ParameterizedTest + @MethodSource("urls") public void testContentLength(String urlString, boolean exists) throws Exception { URL url = new URL(urlString); int len = url.openConnection().getContentLength(); assertTrue((exists && len > 0) || (!exists && len == -1)); } - @Test(dataProvider = "urls") + @ParameterizedTest + @MethodSource("urls") public void testGetContent(String urlString, boolean exists) throws Exception { URL url = new URL(urlString); try { Object obj = url.getContent(); - assertTrue(obj != null); + assertNotNull(obj); if (!exists) fail("IOException expected"); } catch (IOException ioe) { if (exists) fail("IOException not expected"); From 51cd741573330352fc7b7395b1c8aeca8a4bdcf5 Mon Sep 17 00:00:00 2001 From: Jaikiran Pai Date: Tue, 14 Apr 2026 04:45:15 +0000 Subject: [PATCH 268/359] 8381670: Revert the changes to GZIPInputStream related to InputStream.available() usage Reviewed-by: lancea, iris --- .../java/util/zip/GZIPInputStream.java | 76 +++++---------- .../zip/GZIP/GZIPInputStreamAvailable.java | 93 ------------------- 2 files changed, 21 insertions(+), 148 deletions(-) delete mode 100644 test/jdk/java/util/zip/GZIP/GZIPInputStreamAvailable.java diff --git a/src/java.base/share/classes/java/util/zip/GZIPInputStream.java b/src/java.base/share/classes/java/util/zip/GZIPInputStream.java index ebcb9e3204c..72fb8036f08 100644 --- a/src/java.base/share/classes/java/util/zip/GZIPInputStream.java +++ b/src/java.base/share/classes/java/util/zip/GZIPInputStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2026, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -79,11 +79,7 @@ public class GZIPInputStream extends InflaterInputStream { super(in, createInflater(in, size), size); usesDefaultInflater = true; try { - // we don't expect the stream to be at EOF - // and if it is, then we want readHeader to - // raise an exception, so we pass "true" for - // the "failOnEOF" param. - readHeader(in, true); + readHeader(in); } catch (IOException ioe) { this.inf.end(); throw ioe; @@ -194,40 +190,12 @@ public class GZIPInputStream extends InflaterInputStream { /* * Reads GZIP member header and returns the total byte number * of this member header. - * If failOnEOF is false and if the given InputStream has already - * reached EOF when this method was invoked, then this method returns - * -1 (indicating that there's no GZIP member header). - * In all other cases of malformed header or EOF being detected - * when reading the header, this method will throw an IOException. */ - private int readHeader(InputStream this_in, boolean failOnEOF) throws IOException { + private int readHeader(InputStream this_in) throws IOException { CheckedInputStream in = new CheckedInputStream(this_in, crc); crc.reset(); - - int magic; - if (!failOnEOF) { - // read an unsigned short value representing the GZIP magic header. - // this is the same as calling readUShort(in), except that here, - // when reading the first byte, we don't raise an EOFException - // if the stream has already reached EOF. - - // read unsigned byte - int b = in.read(); - if (b == -1) { // EOF - crc.reset(); - return -1; // represents no header bytes available - } - checkUnexpectedByte(b); - // read the next unsigned byte to form the unsigned - // short. we throw the usual EOFException/ZipException - // from this point on if there is no more data or - // the data doesn't represent a header. - magic = (readUByte(in) << 8) | b; - } else { - magic = readUShort(in); - } // Check header magic - if (magic != GZIP_MAGIC) { + if (readUShort(in) != GZIP_MAGIC) { throw new ZipException("Not in GZIP format"); } // Check compression method @@ -290,21 +258,23 @@ public class GZIPInputStream extends InflaterInputStream { (readUInt(in) != (inf.getBytesWritten() & 0xffffffffL))) throw new ZipException("Corrupt GZIP trailer"); + // If there are more bytes available in "in" or + // the leftover in the "inf" is > 26 bytes: + // this.trailer(8) + next.header.min(10) + next.trailer(8) // try concatenated case - int m = 8; // this.trailer - try { - int numNextHeaderBytes = readHeader(in, false); // next.header (if available) - if (numNextHeaderBytes == -1) { - return true; // end of stream reached + if (this.in.available() > 0 || n > 26) { + int m = 8; // this.trailer + try { + m += readHeader(in); // next.header + } catch (IOException ze) { + return true; // ignore any malformed, do nothing } - m += numNextHeaderBytes; - } catch (IOException ze) { - return true; // ignore any malformed, do nothing + inf.reset(); + if (n > m) + inf.setInput(buf, len - n + m, n - m); + return false; } - inf.reset(); - if (n > m) - inf.setInput(buf, len - n + m, n - m); - return false; + return true; } /* @@ -331,16 +301,12 @@ public class GZIPInputStream extends InflaterInputStream { if (b == -1) { throw new EOFException(); } - checkUnexpectedByte(b); - return b; - } - - private void checkUnexpectedByte(final int b) throws IOException { if (b < -1 || b > 255) { - // report the InputStream type which returned this unexpected byte + // Report on this.in, not argument in; see read{Header, Trailer}. throw new IOException(this.in.getClass().getName() - + ".read() returned value out of range -1..255: " + b); + + ".read() returned value out of range -1..255: " + b); } + return b; } private byte[] tmpbuf = new byte[128]; diff --git a/test/jdk/java/util/zip/GZIP/GZIPInputStreamAvailable.java b/test/jdk/java/util/zip/GZIP/GZIPInputStreamAvailable.java deleted file mode 100644 index f63015e0930..00000000000 --- a/test/jdk/java/util/zip/GZIP/GZIPInputStreamAvailable.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* @test - * @bug 7036144 - * @summary Test concatenated gz streams when available() returns zero - * @run junit GZIPInputStreamAvailable - */ - -import org.junit.jupiter.api.Test; - -import java.io.*; -import java.util.*; -import java.util.zip.*; - -import static org.junit.jupiter.api.Assertions.assertArrayEquals; - -public class GZIPInputStreamAvailable { - - public static final int NUM_COPIES = 100; - - @Test - public void testZeroAvailable() throws IOException { - - // Create some uncompressed data and then repeat it NUM_COPIES times - byte[] uncompressed1 = "this is a test".getBytes("ASCII"); - byte[] uncompressedN = repeat(uncompressed1, NUM_COPIES); - - // Compress the original data and then repeat that NUM_COPIES times - byte[] compressed1 = deflate(uncompressed1); - byte[] compressedN = repeat(compressed1, NUM_COPIES); - - // (a) Read back inflated data from a stream where available() is accurate and verify - byte[] readback1 = inflate(new ByteArrayInputStream(compressedN)); - assertArrayEquals(uncompressedN, readback1); - - // (b) Read back inflated data from a stream where available() always returns zero and verify - byte[] readback2 = inflate(new ZeroAvailableStream(new ByteArrayInputStream(compressedN))); - assertArrayEquals(uncompressedN, readback2); - } - - public static byte[] repeat(byte[] data, int count) { - byte[] repeat = new byte[data.length * count]; - int off = 0; - for (int i = 0; i < count; i++) { - System.arraycopy(data, 0, repeat, off, data.length); - off += data.length; - } - return repeat; - } - - public static byte[] deflate(byte[] data) throws IOException { - ByteArrayOutputStream buf = new ByteArrayOutputStream(); - try (GZIPOutputStream out = new GZIPOutputStream(buf)) { - out.write(data); - } - return buf.toByteArray(); - } - - public static byte[] inflate(InputStream in) throws IOException { - return new GZIPInputStream(in).readAllBytes(); - } - - public static class ZeroAvailableStream extends FilterInputStream { - public ZeroAvailableStream(InputStream in) { - super(in); - } - @Override - public int available() { - return 0; - } - } -} From da0ba897775531aed9a228b15e47628f9bd622fa Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Tue, 14 Apr 2026 07:04:35 +0000 Subject: [PATCH 269/359] 8381768: C2: GC barrier stubs miscalculate skipped instructions size Reviewed-by: kvn, phh --- src/hotspot/share/asm/codeBuffer.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/hotspot/share/asm/codeBuffer.cpp b/src/hotspot/share/asm/codeBuffer.cpp index 6a288e0dad0..854cf73049b 100644 --- a/src/hotspot/share/asm/codeBuffer.cpp +++ b/src/hotspot/share/asm/codeBuffer.cpp @@ -858,6 +858,13 @@ csize_t CodeBuffer::figure_expanded_capacities(CodeSection* which_cs, } void CodeBuffer::expand(CodeSection* which_cs, csize_t amount) { +#ifdef ASSERT + // The code below copies contents across temp buffers. The following + // sizes relate to buffer contents, and should not be changed by buffer + // expansion. + int old_total_skipped = total_skipped_instructions_size(); +#endif + #ifndef PRODUCT if (PrintNMethods && (WizardMode || Verbose)) { tty->print("expanding CodeBuffer:"); @@ -916,6 +923,7 @@ void CodeBuffer::expand(CodeSection* which_cs, csize_t amount) { assert(cb_sect->capacity() >= new_capacity[n], "big enough"); address cb_start = cb_sect->start(); cb_sect->set_end(cb_start + this_sect->size()); + cb_sect->register_skipped(this_sect->_skipped_instructions_size); if (this_sect->mark() == nullptr) { cb_sect->clear_mark(); } else { @@ -952,6 +960,9 @@ void CodeBuffer::expand(CodeSection* which_cs, csize_t amount) { this->print_on(tty); } #endif //PRODUCT + + assert(old_total_skipped == total_skipped_instructions_size(), + "Should match: %d == %d", old_total_skipped, total_skipped_instructions_size()); } void CodeBuffer::adjust_internal_address(address from, address to) { From f2f8828188f45d16344c82adfbf951f7409b8825 Mon Sep 17 00:00:00 2001 From: Kieran Farrell Date: Tue, 14 Apr 2026 07:36:55 +0000 Subject: [PATCH 270/359] 8364182: Add jcmd VM.security_properties command Reviewed-by: coffeys, kevinw, alanb --- src/hotspot/share/classfile/vmSymbols.hpp | 1 + .../share/services/diagnosticCommand.cpp | 44 +++++++------- .../share/services/diagnosticCommand.hpp | 9 +++ .../share/classes/java/security/Security.java | 4 ++ .../access/JavaSecurityPropertiesAccess.java | 1 + .../classes/jdk/internal/vm/VMSupport.java | 5 ++ .../dcmd/vm/SecurityPropertiesTest.java | 58 +++++++++++++++++++ 7 files changed, 99 insertions(+), 23 deletions(-) create mode 100644 test/hotspot/jtreg/serviceability/dcmd/vm/SecurityPropertiesTest.java diff --git a/src/hotspot/share/classfile/vmSymbols.hpp b/src/hotspot/share/classfile/vmSymbols.hpp index 2ae42bebcfd..33d00b93365 100644 --- a/src/hotspot/share/classfile/vmSymbols.hpp +++ b/src/hotspot/share/classfile/vmSymbols.hpp @@ -702,6 +702,7 @@ class SerializeClosure; template(appendToClassPathForInstrumentation_name, "appendToClassPathForInstrumentation") \ do_alias(appendToClassPathForInstrumentation_signature, string_void_signature) \ template(serializePropertiesToByteArray_name, "serializePropertiesToByteArray") \ + template(serializeSecurityPropertiesToByteArray_name, "serializeSecurityPropertiesToByteArray") \ template(serializeAgentPropertiesToByteArray_name, "serializeAgentPropertiesToByteArray") \ template(encodeThrowable_name, "encodeThrowable") \ template(encodeThrowable_signature, "(Ljava/lang/Throwable;JI)I") \ diff --git a/src/hotspot/share/services/diagnosticCommand.cpp b/src/hotspot/share/services/diagnosticCommand.cpp index 0846f339227..f2fa114133e 100644 --- a/src/hotspot/share/services/diagnosticCommand.cpp +++ b/src/hotspot/share/services/diagnosticCommand.cpp @@ -99,6 +99,7 @@ void DCmd::register_dcmds() { DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export)); @@ -334,8 +335,8 @@ void JVMTIAgentLoadDCmd::execute(DCmdSource source, TRAPS) { #endif // INCLUDE_JVMTI #endif // INCLUDE_SERVICES -void PrintSystemPropertiesDCmd::execute(DCmdSource source, TRAPS) { - // load VMSupport +// helper method for printing system and security properties +static void print_properties(Symbol* method_name, outputStream* out, TRAPS) { Symbol* klass = vmSymbols::jdk_internal_vm_VMSupport(); Klass* k = SystemDictionary::resolve_or_fail(klass, true, CHECK); InstanceKlass* ik = InstanceKlass::cast(k); @@ -343,39 +344,36 @@ void PrintSystemPropertiesDCmd::execute(DCmdSource source, TRAPS) { ik->initialize(THREAD); } if (HAS_PENDING_EXCEPTION) { - java_lang_Throwable::print(PENDING_EXCEPTION, output()); - output()->cr(); + java_lang_Throwable::print(PENDING_EXCEPTION, out); + out->cr(); CLEAR_PENDING_EXCEPTION; return; } - - // invoke the serializePropertiesToByteArray method JavaValue result(T_OBJECT); JavaCallArguments args; - Symbol* signature = vmSymbols::void_byte_array_signature(); - JavaCalls::call_static(&result, - ik, - vmSymbols::serializePropertiesToByteArray_name(), - signature, - &args, - THREAD); + JavaCalls::call_static(&result, ik, method_name, signature, &args, THREAD); + if (HAS_PENDING_EXCEPTION) { - java_lang_Throwable::print(PENDING_EXCEPTION, output()); - output()->cr(); + java_lang_Throwable::print(PENDING_EXCEPTION, out); + out->cr(); CLEAR_PENDING_EXCEPTION; return; } - - // The result should be a [B oop res = result.get_oop(); - assert(res->is_typeArray(), "just checking"); - assert(TypeArrayKlass::cast(res->klass())->element_type() == T_BYTE, "just checking"); - - // copy the bytes to the output stream + assert(res->is_typeArray(), "should be a byte array"); + assert(TypeArrayKlass::cast(res->klass())->element_type() == T_BYTE, "should be a byte array"); typeArrayOop ba = typeArrayOop(res); - jbyte* addr = typeArrayOop(res)->byte_at_addr(0); - output()->print_raw((const char*)addr, ba->length()); + jbyte* addr = ba->byte_at_addr(0); + out->print_raw((const char*)addr, ba->length()); +} + +void PrintSystemPropertiesDCmd::execute(DCmdSource source, TRAPS) { + print_properties(vmSymbols::serializePropertiesToByteArray_name(), output(), THREAD); +} + +void PrintSecurityPropertiesDCmd::execute(DCmdSource source, TRAPS) { + print_properties(vmSymbols::serializeSecurityPropertiesToByteArray_name(), output(), THREAD); } VMUptimeDCmd::VMUptimeDCmd(outputStream* output, bool heap) : diff --git a/src/hotspot/share/services/diagnosticCommand.hpp b/src/hotspot/share/services/diagnosticCommand.hpp index c41e7bf2e2e..97ceb19d0ad 100644 --- a/src/hotspot/share/services/diagnosticCommand.hpp +++ b/src/hotspot/share/services/diagnosticCommand.hpp @@ -94,6 +94,15 @@ public: virtual void execute(DCmdSource source, TRAPS); }; +class PrintSecurityPropertiesDCmd : public DCmd { +public: + PrintSecurityPropertiesDCmd(outputStream* output, bool heap) : DCmd(output, heap) { } + static const char* name() { return "VM.security_properties"; } + static const char* description() { return "Print java.security.Security properties."; } + static const char* impact() { return "Low"; } + virtual void execute(DCmdSource source, TRAPS); +}; + // See also: print_flag in attachListener.cpp class PrintVMFlagsDCmd : public DCmdWithParser { protected: diff --git a/src/java.base/share/classes/java/security/Security.java b/src/java.base/share/classes/java/security/Security.java index 30a22b05742..9faa172c8e7 100644 --- a/src/java.base/share/classes/java/security/Security.java +++ b/src/java.base/share/classes/java/security/Security.java @@ -330,6 +330,10 @@ public final class Security { public Properties getInitialProperties() { return initialSecurityProperties; } + @Override + public Properties getCurrentProperties() { + return props; + } }); } diff --git a/src/java.base/share/classes/jdk/internal/access/JavaSecurityPropertiesAccess.java b/src/java.base/share/classes/jdk/internal/access/JavaSecurityPropertiesAccess.java index a4875f357e3..2d9dbea052a 100644 --- a/src/java.base/share/classes/jdk/internal/access/JavaSecurityPropertiesAccess.java +++ b/src/java.base/share/classes/jdk/internal/access/JavaSecurityPropertiesAccess.java @@ -29,4 +29,5 @@ import java.util.Properties; public interface JavaSecurityPropertiesAccess { Properties getInitialProperties(); + Properties getCurrentProperties(); } 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 197da0d456c..32c358340af 100644 --- a/src/java.base/share/classes/jdk/internal/vm/VMSupport.java +++ b/src/java.base/share/classes/jdk/internal/vm/VMSupport.java @@ -98,6 +98,11 @@ public class VMSupport { return serializePropertiesToByteArray(onlyStrings(System.getProperties())); } + public static byte[] serializeSecurityPropertiesToByteArray() throws IOException { + Properties p = SharedSecrets.getJavaSecurityPropertiesAccess().getCurrentProperties(); + return serializePropertiesToByteArray(onlyStrings(p)); + } + public static byte[] serializeAgentPropertiesToByteArray() throws IOException { return serializePropertiesToByteArray(onlyStrings(getAgentProperties())); } diff --git a/test/hotspot/jtreg/serviceability/dcmd/vm/SecurityPropertiesTest.java b/test/hotspot/jtreg/serviceability/dcmd/vm/SecurityPropertiesTest.java new file mode 100644 index 00000000000..b5a6ead34c1 --- /dev/null +++ b/test/hotspot/jtreg/serviceability/dcmd/vm/SecurityPropertiesTest.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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.security.Security; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.dcmd.CommandExecutor; +import jdk.test.lib.dcmd.JMXExecutor; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + +/* + * @test + * @bug 8364182 + * @summary Test of diagnostic command VM.security_properties + * @library /test/lib + * @modules java.base/jdk.internal.misc + * java.compiler + * java.management + * jdk.internal.jvmstat/sun.jvmstat.monitor + * @run junit/othervm SecurityPropertiesTest + */ +public class SecurityPropertiesTest { + private static final String PROPERTY_NAME = "SecurityPropertiesTestPropertyName"; + private static final String PROPERTY_VALUE = "SecurityPropertiesTestPropertyValue"; + + private void run(CommandExecutor executor) { + Security.setProperty(PROPERTY_NAME, PROPERTY_VALUE); + OutputAnalyzer output = executor.execute("VM.security_properties"); + assertTrue(output.getOutput().contains(PROPERTY_NAME + "=" + PROPERTY_VALUE), + "Should contain the test security property"); + } + + @Test + public void jmx() { + run(new JMXExecutor()); + } +} \ No newline at end of file From e71fa9e806525a09e5bbacf37445b8e746333451 Mon Sep 17 00:00:00 2001 From: Christian Hagedorn Date: Tue, 14 Apr 2026 07:50:32 +0000 Subject: [PATCH 271/359] 8382057: C2: "assert((ptr->bottom_type() == Type::TOP) || ((base == Compile::current()->top()) == (ptr->bottom_type()->make_ptr()->isa_oopptr() == nullptr))) failed: base input only needed for heap addresses" with -XX:+CountCompiledCalls Reviewed-by: rcastanedalo, bmaillard, kvn --- src/hotspot/share/opto/doCall.cpp | 6 +-- .../debug/TestCountCompiledCalls.java | 38 +++++++++++++++++++ 2 files changed, 41 insertions(+), 3 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/debug/TestCountCompiledCalls.java diff --git a/src/hotspot/share/opto/doCall.cpp b/src/hotspot/share/opto/doCall.cpp index 9a1da726f00..d6e75f17f50 100644 --- a/src/hotspot/share/opto/doCall.cpp +++ b/src/hotspot/share/opto/doCall.cpp @@ -1081,13 +1081,13 @@ void Parse::catch_inline_exceptions(SafePointNode* ex_map) { #ifndef PRODUCT void Parse::count_compiled_calls(bool at_method_entry, bool is_inline) { - if( CountCompiledCalls ) { - if( at_method_entry ) { + if (CountCompiledCalls) { + if (at_method_entry) { // bump invocation counter if top method (for statistics) if (CountCompiledCalls && depth() == 1) { const TypePtr* addr_type = TypeMetadataPtr::make(method()); Node* adr1 = makecon(addr_type); - Node* adr2 = basic_plus_adr(adr1, adr1, in_bytes(Method::compiled_invocation_counter_offset())); + Node* adr2 = off_heap_plus_addr(adr1, in_bytes(Method::compiled_invocation_counter_offset())); increment_counter(adr2); } } else if (is_inline) { diff --git a/test/hotspot/jtreg/compiler/debug/TestCountCompiledCalls.java b/test/hotspot/jtreg/compiler/debug/TestCountCompiledCalls.java new file mode 100644 index 00000000000..1a3fdf6e9d6 --- /dev/null +++ b/test/hotspot/jtreg/compiler/debug/TestCountCompiledCalls.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8382057 + * @requires vm.debug == true + * + * @run main/othervm -Xbatch -XX:+CountCompiledCalls ${test.main.class} + */ + +package compiler.debug; + +public class TestCountCompiledCalls { + public static void main(String[] args) { + System.out.println("Hello World!"); + } +} From 6548fb80ac57098b2fe6fca6b403d3303ece91a0 Mon Sep 17 00:00:00 2001 From: Christian Hagedorn Date: Tue, 14 Apr 2026 07:50:54 +0000 Subject: [PATCH 272/359] 8382050: compiler/intrinsics/klass/CastNullCheckDroppingsTest.java fails with -XX:+StressUnstableIfTraps Reviewed-by: rcastanedalo, qamai --- .../intrinsics/klass/CastNullCheckDroppingsTest.java | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/test/hotspot/jtreg/compiler/intrinsics/klass/CastNullCheckDroppingsTest.java b/test/hotspot/jtreg/compiler/intrinsics/klass/CastNullCheckDroppingsTest.java index 31449eefb33..ff8358c3cd8 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/klass/CastNullCheckDroppingsTest.java +++ b/test/hotspot/jtreg/compiler/intrinsics/klass/CastNullCheckDroppingsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,8 +25,8 @@ * @test NullCheckDroppingsTest * @bug 8054492 * @summary Casting can result in redundant null checks in generated code - * @requires vm.hasJFR - * @requires vm.flavor == "server" & !vm.graal.enabled + * @requires vm.hasJFR & vm.flavor == "server" & !vm.graal.enabled & vm.flagless + * * @library /test/lib * @modules java.base/jdk.internal.misc * java.management @@ -35,9 +35,6 @@ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -Xmixed -XX:-BackgroundCompilation -XX:-TieredCompilation -XX:CompileThreshold=1000 - * -XX:+UnlockExperimentalVMOptions -XX:PerMethodTrapLimit=100 -XX:-StressReflectiveCode - * -XX:+UncommonNullCast -XX:-StressMethodHandleLinkerInlining -XX:TypeProfileLevel=0 - * -XX:-AlwaysIncrementalInline -XX:-StressIncrementalInlining * -XX:CompileCommand=exclude,compiler.intrinsics.klass.CastNullCheckDroppingsTest::runTest * compiler.intrinsics.klass.CastNullCheckDroppingsTest */ From c4199831b9df7341b020dba04f482a0910b76818 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Tue, 14 Apr 2026 08:08:18 +0000 Subject: [PATCH 273/359] 8381934: Wrong type passed to FREE_C_HEAP_ARRAY deallocating G1CardSetMemoryManager Reviewed-by: iwalulya --- src/hotspot/share/gc/g1/g1CardSetMemory.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/gc/g1/g1CardSetMemory.cpp b/src/hotspot/share/gc/g1/g1CardSetMemory.cpp index 60602ef942b..0da2f90da3f 100644 --- a/src/hotspot/share/gc/g1/g1CardSetMemory.cpp +++ b/src/hotspot/share/gc/g1/g1CardSetMemory.cpp @@ -90,7 +90,7 @@ G1CardSetMemoryManager::~G1CardSetMemoryManager() { for (uint i = 0; i < num_mem_object_types(); i++) { _allocators[i].~G1CardSetAllocator(); } - FREE_C_HEAP_ARRAY(G1CardSetAllocator, _allocators); + FREE_C_HEAP_ARRAY(G1CardSetAllocator, _allocators); } void G1CardSetMemoryManager::free(uint type, void* value) { From 64bbbe751b4d05ee79cb3c384cc3d399a093983f Mon Sep 17 00:00:00 2001 From: Severin Gehwolf Date: Tue, 14 Apr 2026 08:33:28 +0000 Subject: [PATCH 274/359] 8380636: Add static asserts for mirrored library constants Reviewed-by: cnorrbin, dholmes --- src/hotspot/os/linux/cgroupSubsystem_linux.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/hotspot/os/linux/cgroupSubsystem_linux.cpp b/src/hotspot/os/linux/cgroupSubsystem_linux.cpp index 13a005591fb..4a2d75ecdf3 100644 --- a/src/hotspot/os/linux/cgroupSubsystem_linux.cpp +++ b/src/hotspot/os/linux/cgroupSubsystem_linux.cpp @@ -40,6 +40,8 @@ // Inlined from for portability. #ifndef CGROUP2_SUPER_MAGIC # define CGROUP2_SUPER_MAGIC 0x63677270 +#else + STATIC_ASSERT(CGROUP2_SUPER_MAGIC == 0x63677270); #endif // controller names have to match the *_IDX indices From d5d8532ca2ca5cbdcb80af43fb1a192c20af9914 Mon Sep 17 00:00:00 2001 From: Jatin Bhateja Date: Tue, 14 Apr 2026 09:07:14 +0000 Subject: [PATCH 275/359] 8381579: C2: "fatal error: LROTATE: double" when using VectorAPI Reviewed-by: mhaessig, qamai --- src/hotspot/share/prims/vectorSupport.cpp | 74 +++++------ .../jdk/incubator/vector/VectorOperators.java | 10 +- .../TestShiftOpOnFloatingVector.java | 121 ++++++++++++++++++ 3 files changed, 163 insertions(+), 42 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/vectorapi/TestShiftOpOnFloatingVector.java diff --git a/src/hotspot/share/prims/vectorSupport.cpp b/src/hotspot/share/prims/vectorSupport.cpp index 7d80ed327fd..5c6010acdf1 100644 --- a/src/hotspot/share/prims/vectorSupport.cpp +++ b/src/hotspot/share/prims/vectorSupport.cpp @@ -226,7 +226,7 @@ int VectorSupport::vop2ideal(jint id, LaneType lt) { case LT_LONG: return Op_AddL; case LT_FLOAT: return Op_AddF; case LT_DOUBLE: return Op_AddD; - default: fatal("ADD: %s", lanetype2name(lt)); + default: return 0; } break; } @@ -238,7 +238,7 @@ int VectorSupport::vop2ideal(jint id, LaneType lt) { case LT_LONG: return Op_SubL; case LT_FLOAT: return Op_SubF; case LT_DOUBLE: return Op_SubD; - default: fatal("SUB: %s", lanetype2name(lt)); + default: return 0; } break; } @@ -250,7 +250,7 @@ int VectorSupport::vop2ideal(jint id, LaneType lt) { case LT_LONG: return Op_MulL; case LT_FLOAT: return Op_MulF; case LT_DOUBLE: return Op_MulD; - default: fatal("MUL: %s", lanetype2name(lt)); + default: return 0; } break; } @@ -262,7 +262,7 @@ int VectorSupport::vop2ideal(jint id, LaneType lt) { case LT_LONG: return Op_DivL; case LT_FLOAT: return Op_DivF; case LT_DOUBLE: return Op_DivD; - default: fatal("DIV: %s", lanetype2name(lt)); + default: return 0; } break; } @@ -274,7 +274,7 @@ int VectorSupport::vop2ideal(jint id, LaneType lt) { case LT_LONG: return Op_MinL; case LT_FLOAT: return Op_MinF; case LT_DOUBLE: return Op_MinD; - default: fatal("MIN: %s", lanetype2name(lt)); + default: return 0; } break; } @@ -286,7 +286,7 @@ int VectorSupport::vop2ideal(jint id, LaneType lt) { case LT_LONG: return Op_MaxL; case LT_FLOAT: return Op_MaxF; case LT_DOUBLE: return Op_MaxD; - default: fatal("MAX: %s", lanetype2name(lt)); + default: return 0; } break; } @@ -296,7 +296,7 @@ int VectorSupport::vop2ideal(jint id, LaneType lt) { case LT_SHORT: case LT_INT: case LT_LONG: return Op_UMinV; - default: fatal("MIN: %s", lanetype2name(lt)); + default: return 0; } break; } @@ -306,7 +306,7 @@ int VectorSupport::vop2ideal(jint id, LaneType lt) { case LT_SHORT: case LT_INT: case LT_LONG: return Op_UMaxV; - default: fatal("MAX: %s", lanetype2name(lt)); + default: return 0; } break; } @@ -318,7 +318,7 @@ int VectorSupport::vop2ideal(jint id, LaneType lt) { case LT_LONG: return Op_AbsL; case LT_FLOAT: return Op_AbsF; case LT_DOUBLE: return Op_AbsD; - default: fatal("ABS: %s", lanetype2name(lt)); + default: return 0; } break; } @@ -330,7 +330,7 @@ int VectorSupport::vop2ideal(jint id, LaneType lt) { case LT_LONG: return Op_NegL; case LT_FLOAT: return Op_NegF; case LT_DOUBLE: return Op_NegD; - default: fatal("NEG: %s", lanetype2name(lt)); + default: return 0; } break; } @@ -340,7 +340,7 @@ int VectorSupport::vop2ideal(jint id, LaneType lt) { case LT_SHORT: // fall-through case LT_INT: return Op_AndI; case LT_LONG: return Op_AndL; - default: fatal("AND: %s", lanetype2name(lt)); + default: return 0; } break; } @@ -350,7 +350,7 @@ int VectorSupport::vop2ideal(jint id, LaneType lt) { case LT_SHORT: // fall-through case LT_INT: return Op_OrI; case LT_LONG: return Op_OrL; - default: fatal("OR: %s", lanetype2name(lt)); + default: return 0; } break; } @@ -360,7 +360,7 @@ int VectorSupport::vop2ideal(jint id, LaneType lt) { case LT_SHORT: // fall-through case LT_INT: return Op_XorI; case LT_LONG: return Op_XorL; - default: fatal("XOR: %s", lanetype2name(lt)); + default: return 0; } break; } @@ -368,7 +368,7 @@ int VectorSupport::vop2ideal(jint id, LaneType lt) { switch (lt) { case LT_FLOAT: return Op_SqrtF; case LT_DOUBLE: return Op_SqrtD; - default: fatal("SQRT: %s", lanetype2name(lt)); + default: return 0; } break; } @@ -376,7 +376,7 @@ int VectorSupport::vop2ideal(jint id, LaneType lt) { switch (lt) { case LT_FLOAT: return Op_FmaF; case LT_DOUBLE: return Op_FmaD; - default: fatal("FMA: %s", lanetype2name(lt)); + default: return 0; } break; } @@ -386,7 +386,7 @@ int VectorSupport::vop2ideal(jint id, LaneType lt) { case LT_SHORT: // fall-through case LT_INT: return Op_LShiftI; case LT_LONG: return Op_LShiftL; - default: fatal("LSHIFT: %s", lanetype2name(lt)); + default: return 0; } break; } @@ -396,7 +396,7 @@ int VectorSupport::vop2ideal(jint id, LaneType lt) { case LT_SHORT: // fall-through case LT_INT: return Op_RShiftI; case LT_LONG: return Op_RShiftL; - default: fatal("RSHIFT: %s", lanetype2name(lt)); + default: return 0; } break; } @@ -406,7 +406,7 @@ int VectorSupport::vop2ideal(jint id, LaneType lt) { case LT_SHORT: return Op_URShiftS; case LT_INT: return Op_URShiftI; case LT_LONG: return Op_URShiftL; - default: fatal("URSHIFT: %s", lanetype2name(lt)); + default: return 0; } break; } @@ -416,7 +416,7 @@ int VectorSupport::vop2ideal(jint id, LaneType lt) { case LT_SHORT: // fall-through case LT_INT: // fall-through case LT_LONG: return Op_RotateLeft; - default: fatal("LROTATE: %s", lanetype2name(lt)); + default: return 0; } break; } @@ -426,7 +426,7 @@ int VectorSupport::vop2ideal(jint id, LaneType lt) { case LT_SHORT: // fall-through case LT_INT: // fall-through case LT_LONG: return Op_RotateRight; - default: fatal("RROTATE: %s", lanetype2name(lt)); + default: return 0; } break; } @@ -438,7 +438,7 @@ int VectorSupport::vop2ideal(jint id, LaneType lt) { case LT_LONG: // fall-through case LT_FLOAT: // fall-through case LT_DOUBLE: return Op_VectorMaskLastTrue; - default: fatal("MASK_LASTTRUE: %s", lanetype2name(lt)); + default: return 0; } break; } @@ -450,7 +450,7 @@ int VectorSupport::vop2ideal(jint id, LaneType lt) { case LT_LONG: // fall-through case LT_FLOAT: // fall-through case LT_DOUBLE: return Op_VectorMaskFirstTrue; - default: fatal("MASK_FIRSTTRUE: %s", lanetype2name(lt)); + default: return 0; } break; } @@ -462,7 +462,7 @@ int VectorSupport::vop2ideal(jint id, LaneType lt) { case LT_LONG: // fall-through case LT_FLOAT: // fall-through case LT_DOUBLE: return Op_VectorMaskTrueCount; - default: fatal("MASK_TRUECOUNT: %s", lanetype2name(lt)); + default: return 0; } break; } @@ -474,7 +474,7 @@ int VectorSupport::vop2ideal(jint id, LaneType lt) { case LT_LONG: // fall-through case LT_FLOAT: // fall-through case LT_DOUBLE: return Op_VectorMaskToLong; - default: fatal("MASK_TOLONG: %s", lanetype2name(lt)); + default: return 0; } break; } @@ -486,7 +486,7 @@ int VectorSupport::vop2ideal(jint id, LaneType lt) { case LT_LONG: // fall-through case LT_FLOAT: // fall-through case LT_DOUBLE: return Op_ExpandV; - default: fatal("EXPAND: %s", lanetype2name(lt)); + default: return 0; } break; } @@ -498,7 +498,7 @@ int VectorSupport::vop2ideal(jint id, LaneType lt) { case LT_LONG: // fall-through case LT_FLOAT: // fall-through case LT_DOUBLE: return Op_CompressV; - default: fatal("COMPRESS: %s", lanetype2name(lt)); + default: return 0; } break; } @@ -510,7 +510,7 @@ int VectorSupport::vop2ideal(jint id, LaneType lt) { case LT_LONG: // fall-through case LT_FLOAT: // fall-through case LT_DOUBLE: return Op_CompressM; - default: fatal("MASK_COMPRESS: %s", lanetype2name(lt)); + default: return 0; } break; } @@ -520,7 +520,7 @@ int VectorSupport::vop2ideal(jint id, LaneType lt) { case LT_SHORT: // for byte and short types temporarily case LT_INT: return Op_PopCountI; case LT_LONG: return Op_PopCountL; - default: fatal("BILT_COUNT: %s", lanetype2name(lt)); + default: return 0; } break; } @@ -530,7 +530,7 @@ int VectorSupport::vop2ideal(jint id, LaneType lt) { case LT_SHORT: case LT_INT: return Op_CountTrailingZerosI; case LT_LONG: return Op_CountTrailingZerosL; - default: fatal("TZ_COUNT: %s", lanetype2name(lt)); + default: return 0; } break; } @@ -540,7 +540,7 @@ int VectorSupport::vop2ideal(jint id, LaneType lt) { case LT_SHORT: case LT_INT: return Op_CountLeadingZerosI; case LT_LONG: return Op_CountLeadingZerosL; - default: fatal("LZ_COUNT: %s", lanetype2name(lt)); + default: return 0; } break; } @@ -550,7 +550,7 @@ int VectorSupport::vop2ideal(jint id, LaneType lt) { case LT_SHORT: // Op_ReverseI for byte and short case LT_INT: return Op_ReverseI; case LT_LONG: return Op_ReverseL; - default: fatal("REVERSE: %s", lanetype2name(lt)); + default: return 0; } break; } @@ -565,7 +565,7 @@ int VectorSupport::vop2ideal(jint id, LaneType lt) { case LT_BYTE: // Intentionally fall-through case LT_INT: return Op_ReverseBytesI; case LT_LONG: return Op_ReverseBytesL; - default: fatal("REVERSE_BYTES: %s", lanetype2name(lt)); + default: return 0; } break; } @@ -576,7 +576,7 @@ int VectorSupport::vop2ideal(jint id, LaneType lt) { case LT_SHORT: // fall-through case LT_INT: // fall-through case LT_LONG: return Op_SaturatingAddV; - default: fatal("S[U]ADD: %s", lanetype2name(lt)); + default: return 0; } break; } @@ -587,7 +587,7 @@ int VectorSupport::vop2ideal(jint id, LaneType lt) { case LT_SHORT: // fall-through case LT_INT: // fall-through case LT_LONG: return Op_SaturatingSubV; - default: fatal("S[U}SUB: %s", lanetype2name(lt)); + default: return 0; } break; } @@ -595,7 +595,7 @@ int VectorSupport::vop2ideal(jint id, LaneType lt) { switch (lt) { case LT_INT: case LT_LONG: return Op_CompressBits; - default: fatal("COMPRESS_BITS: %s", lanetype2name(lt)); + default: return 0; } break; } @@ -603,7 +603,7 @@ int VectorSupport::vop2ideal(jint id, LaneType lt) { switch (lt) { case LT_INT: case LT_LONG: return Op_ExpandBits; - default: fatal("EXPAND_BITS: %s", lanetype2name(lt)); + default: return 0; } break; } @@ -627,7 +627,7 @@ int VectorSupport::vop2ideal(jint id, LaneType lt) { case VECTOR_OP_EXPM1: // fall-through case VECTOR_OP_HYPOT: return 0; // not supported; should be handled in Java code - default: fatal("unknown op: %d", vop); + default: return 0; } return 0; // Unimplemented } diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorOperators.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorOperators.java index 2f2d33ab130..cc5a7ccbdef 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorOperators.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorOperators.java @@ -560,15 +560,15 @@ public final class VectorOperators { /** Produce {@code a<<(n&(ESIZE*8-1))}. Integral only. */ - public static final /*bitwise*/ Binary LSHL = binary("LSHL", "<<", VectorSupport.VECTOR_OP_LSHIFT, VO_SHIFT); + public static final /*bitwise*/ Binary LSHL = binary("LSHL", "<<", VectorSupport.VECTOR_OP_LSHIFT, VO_SHIFT+VO_NOFP); /** Produce {@code a>>(n&(ESIZE*8-1))}. Integral only. */ - public static final /*bitwise*/ Binary ASHR = binary("ASHR", ">>", VectorSupport.VECTOR_OP_RSHIFT, VO_SHIFT); + public static final /*bitwise*/ Binary ASHR = binary("ASHR", ">>", VectorSupport.VECTOR_OP_RSHIFT, VO_SHIFT+VO_NOFP); /** Produce {@code (a&EMASK)>>>(n&(ESIZE*8-1))}. Integral only. */ - public static final /*bitwise*/ Binary LSHR = binary("LSHR", ">>>", VectorSupport.VECTOR_OP_URSHIFT, VO_SHIFT); + public static final /*bitwise*/ Binary LSHR = binary("LSHR", ">>>", VectorSupport.VECTOR_OP_URSHIFT, VO_SHIFT+VO_NOFP); /** Produce {@code rotateLeft(a,n)}. Integral only. */ - public static final /*bitwise*/ Binary ROL = binary("ROL", "rotateLeft", VectorSupport.VECTOR_OP_LROTATE, VO_SHIFT); + public static final /*bitwise*/ Binary ROL = binary("ROL", "rotateLeft", VectorSupport.VECTOR_OP_LROTATE, VO_SHIFT+VO_NOFP); /** Produce {@code rotateRight(a,n)}. Integral only. */ - public static final /*bitwise*/ Binary ROR = binary("ROR", "rotateRight", VectorSupport.VECTOR_OP_RROTATE, VO_SHIFT); + public static final /*bitwise*/ Binary ROR = binary("ROR", "rotateRight", VectorSupport.VECTOR_OP_RROTATE, VO_SHIFT+VO_NOFP); /** Produce {@code compress(a,n)}. Integral, {@code int} and {@code long}, only. * @since 19 */ diff --git a/test/hotspot/jtreg/compiler/vectorapi/TestShiftOpOnFloatingVector.java b/test/hotspot/jtreg/compiler/vectorapi/TestShiftOpOnFloatingVector.java new file mode 100644 index 00000000000..ea1878bcb53 --- /dev/null +++ b/test/hotspot/jtreg/compiler/vectorapi/TestShiftOpOnFloatingVector.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.incubator.vector.*; + +/* + * @test + * @bug 8381579 + * @summary Verify shift operations on floating-point vectors throw UnsupportedOperationException. + * @modules jdk.incubator.vector + * @library /test/lib / + * @run main/othervm -Xbatch -XX:-TieredCompilation + * compiler.vectorapi.TestShiftOpOnFloatingVector + */ + +public class TestShiftOpOnFloatingVector { + + static final int ITERATIONS = 4_000; + static final int ARRAY_LEN = 100; + + static void testROL() { + double[] arr = new double[ARRAY_LEN]; + for (int i = 0; i < arr.length; i++) { + arr[i] = i * 1.5 + 7.89; + } + for (int i = 0; i < arr.length; i += DoubleVector.SPECIES_PREFERRED.length()) { + DoubleVector v = DoubleVector.fromArray(DoubleVector.SPECIES_PREFERRED, arr, i); + DoubleVector r = v.lanewise(VectorOperators.ROL, 7); + r.intoArray(arr, i); + } + } + + static void testROR() { + double[] arr = new double[ARRAY_LEN]; + for (int i = 0; i < arr.length; i++) { + arr[i] = i * 1.5 + 7.89; + } + for (int i = 0; i < arr.length; i += DoubleVector.SPECIES_PREFERRED.length()) { + DoubleVector v = DoubleVector.fromArray(DoubleVector.SPECIES_PREFERRED, arr, i); + DoubleVector r = v.lanewise(VectorOperators.ROR, 3); + r.intoArray(arr, i); + } + } + + static void testLSHL() { + float[] arr = new float[ARRAY_LEN]; + for (int i = 0; i < arr.length; i++) { + arr[i] = i * 0.5f + 1.0f; + } + for (int i = 0; i < arr.length; i += FloatVector.SPECIES_PREFERRED.length()) { + FloatVector v = FloatVector.fromArray(FloatVector.SPECIES_PREFERRED, arr, i); + FloatVector r = v.lanewise(VectorOperators.LSHL, 2); + r.intoArray(arr, i); + } + } + + static void testLSHR() { + float[] arr = new float[ARRAY_LEN]; + for (int i = 0; i < arr.length; i++) { + arr[i] = i * 0.3f + 2.0f; + } + for (int i = 0; i < arr.length; i += FloatVector.SPECIES_PREFERRED.length()) { + FloatVector v = FloatVector.fromArray(FloatVector.SPECIES_PREFERRED, arr, i); + FloatVector r = v.lanewise(VectorOperators.LSHR, 5); + r.intoArray(arr, i); + } + } + + static void testASHR() { + double[] arr = new double[ARRAY_LEN]; + for (int i = 0; i < arr.length; i++) { + arr[i] = i * 2.0 + 3.0; + } + for (int i = 0; i < arr.length; i += DoubleVector.SPECIES_PREFERRED.length()) { + DoubleVector v = DoubleVector.fromArray(DoubleVector.SPECIES_PREFERRED, arr, i); + DoubleVector r = v.lanewise(VectorOperators.ASHR, 4); + r.intoArray(arr, i); + } + } + + static void runTest(Runnable test, String name) { + for (int i = 0; i < ITERATIONS; i++) { + try { + test.run(); + throw new AssertionError(name + ": Expected UnsupportedOperationException was not thrown"); + } catch (UnsupportedOperationException e) { + // expected + } + } + } + + public static void main(String[] args) { + runTest(TestShiftOpOnFloatingVector::testROL, "ROL"); + runTest(TestShiftOpOnFloatingVector::testROR, "ROR"); + runTest(TestShiftOpOnFloatingVector::testLSHL, "LSHL"); + runTest(TestShiftOpOnFloatingVector::testLSHR, "LSHR"); + runTest(TestShiftOpOnFloatingVector::testASHR, "ASHR"); + } +} From 540c714eea7bd5f1f15b59eaa05819b12c948aac Mon Sep 17 00:00:00 2001 From: Ivan Walulya Date: Tue, 14 Apr 2026 10:51:58 +0000 Subject: [PATCH 276/359] 8382084: Use dynamic chunk sizes in PartialArraySplitter Co-authored-by: Thomas Schatzl Reviewed-by: ayang, tschatzl --- src/hotspot/share/gc/g1/g1ConcurrentMark.cpp | 7 +++--- src/hotspot/share/gc/g1/g1FullGCMarker.cpp | 4 ++-- .../share/gc/g1/g1ParScanThreadState.cpp | 4 ++-- .../share/gc/parallel/psCompactionManager.cpp | 6 ++--- .../share/gc/parallel/psPromotionManager.cpp | 6 ++--- .../share/gc/shared/partialArraySplitter.cpp | 7 +++--- .../share/gc/shared/partialArraySplitter.hpp | 10 ++++---- .../gc/shared/partialArraySplitter.inline.hpp | 13 ++++++---- .../share/gc/shared/partialArrayState.cpp | 7 ++++-- .../share/gc/shared/partialArrayState.hpp | 8 +++++-- .../gc/shared/partialArrayTaskStepper.cpp | 5 ++-- .../gc/shared/partialArrayTaskStepper.hpp | 19 ++++++--------- .../shared/partialArrayTaskStepper.inline.hpp | 24 ++++++++----------- .../shared/test_partialArrayTaskStepper.cpp | 14 ++++++----- 14 files changed, 68 insertions(+), 66 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp index a72d5fc5cf9..dbb5ba509a2 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp @@ -2173,8 +2173,7 @@ void G1CMTask::reset_for_restart() { void G1CMTask::register_partial_array_splitter() { ::new (&_partial_array_splitter) PartialArraySplitter(_cm->partial_array_state_manager(), - _cm->max_num_tasks(), - ObjArrayMarkingStride); + _cm->max_num_tasks()); } void G1CMTask::unregister_partial_array_splitter() { @@ -2359,7 +2358,7 @@ size_t G1CMTask::start_partial_array_processing(objArrayOop obj) { process_klass(obj->klass()); size_t array_length = obj->length(); - size_t initial_chunk_size = _partial_array_splitter.start(_task_queue, obj, nullptr, array_length); + size_t initial_chunk_size = _partial_array_splitter.start(_task_queue, obj, nullptr, array_length, ObjArrayMarkingStride); process_array_chunk(obj, 0, initial_chunk_size); @@ -2917,7 +2916,7 @@ G1CMTask::G1CMTask(uint worker_id, _cm(cm), _mark_bitmap(nullptr), _task_queue(task_queue), - _partial_array_splitter(_cm->partial_array_state_manager(), _cm->max_num_tasks(), ObjArrayMarkingStride), + _partial_array_splitter(_cm->partial_array_state_manager(), _cm->max_num_tasks()), _mark_stats_cache(mark_stats, G1RegionMarkStatsCache::RegionMarkStatsCacheSize), _calls(0), _time_target_ms(0.0), diff --git a/src/hotspot/share/gc/g1/g1FullGCMarker.cpp b/src/hotspot/share/gc/g1/g1FullGCMarker.cpp index 2b0b78ac1ce..5af1eae92c5 100644 --- a/src/hotspot/share/gc/g1/g1FullGCMarker.cpp +++ b/src/hotspot/share/gc/g1/g1FullGCMarker.cpp @@ -39,7 +39,7 @@ G1FullGCMarker::G1FullGCMarker(G1FullCollector* collector, _worker_id(worker_id), _bitmap(collector->mark_bitmap()), _task_queue(), - _partial_array_splitter(collector->partial_array_state_manager(), collector->workers(), ObjArrayMarkingStride), + _partial_array_splitter(collector->partial_array_state_manager(), collector->workers()), _mark_closure(worker_id, this, ClassLoaderData::_claim_stw_fullgc_mark, G1CollectedHeap::heap()->ref_processor_stw()), _stack_closure(this), _cld_closure(mark_closure(), ClassLoaderData::_claim_stw_fullgc_mark), @@ -65,7 +65,7 @@ void G1FullGCMarker::start_partial_array_processing(objArrayOop obj) { // Don't push empty arrays to avoid unnecessary work. size_t array_length = obj->length(); if (array_length > 0) { - size_t initial_chunk_size = _partial_array_splitter.start(task_queue(), obj, nullptr, array_length); + size_t initial_chunk_size = _partial_array_splitter.start(task_queue(), obj, nullptr, array_length, ObjArrayMarkingStride); process_array_chunk(obj, 0, initial_chunk_size); } } diff --git a/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp b/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp index 2b0e6ce9cf4..52c8d4d4389 100644 --- a/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp +++ b/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp @@ -78,7 +78,7 @@ G1ParScanThreadState::G1ParScanThreadState(G1CollectedHeap* g1h, _surviving_young_words(nullptr), _surviving_words_length(collection_set->young_region_length() + 1), _old_gen_is_full(false), - _partial_array_splitter(g1h->partial_array_state_manager(), num_workers, ParGCArrayScanChunk), + _partial_array_splitter(g1h->partial_array_state_manager(), num_workers), _string_dedup_requests(), _max_num_optional_regions(collection_set->num_optional_regions()), _numa(g1h->numa()), @@ -253,7 +253,7 @@ void G1ParScanThreadState::start_partial_objarray(oop from_obj, size_t array_length = to_array->length(); size_t initial_chunk_size = // The source array is unused when processing states. - _partial_array_splitter.start(_task_queue, nullptr, to_array, array_length); + _partial_array_splitter.start(_task_queue, nullptr, to_array, array_length, ParGCArrayScanChunk); assert(_scanner.skip_card_mark_set(), "must be"); // Process the initial chunk. No need to process the type in the diff --git a/src/hotspot/share/gc/parallel/psCompactionManager.cpp b/src/hotspot/share/gc/parallel/psCompactionManager.cpp index 0108f1a9762..048355bfad3 100644 --- a/src/hotspot/share/gc/parallel/psCompactionManager.cpp +++ b/src/hotspot/share/gc/parallel/psCompactionManager.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ PreservedMarksSet* ParCompactionManager::_preserved_marks_set = nullptr; ParCompactionManager::ParCompactionManager(PreservedMarks* preserved_marks, ReferenceProcessor* ref_processor, uint parallel_gc_threads) - :_partial_array_splitter(_partial_array_state_manager, parallel_gc_threads, ObjArrayMarkingStride), + :_partial_array_splitter(_partial_array_state_manager, parallel_gc_threads), _mark_and_push_closure(this, ref_processor) { ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); @@ -126,7 +126,7 @@ void ParCompactionManager::push_objArray(oop obj) { objArrayOop obj_array = objArrayOop(obj); size_t array_length = obj_array->length(); size_t initial_chunk_size = - _partial_array_splitter.start(&_marking_stack, obj_array, nullptr, array_length); + _partial_array_splitter.start(&_marking_stack, obj_array, nullptr, array_length, ObjArrayMarkingStride); follow_array(obj_array, 0, initial_chunk_size); } diff --git a/src/hotspot/share/gc/parallel/psPromotionManager.cpp b/src/hotspot/share/gc/parallel/psPromotionManager.cpp index 39fcc5556c6..ac22430aa4c 100644 --- a/src/hotspot/share/gc/parallel/psPromotionManager.cpp +++ b/src/hotspot/share/gc/parallel/psPromotionManager.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -158,7 +158,7 @@ PartialArrayTaskStats* PSPromotionManager::partial_array_task_stats() { // Most members are initialized either by initialize() or reset(). PSPromotionManager::PSPromotionManager() - : _partial_array_splitter(_partial_array_state_manager, ParallelGCThreads, ParGCArrayScanChunk) + : _partial_array_splitter(_partial_array_state_manager, ParallelGCThreads) { // We set the old lab's start array. _old_lab.set_start_array(old_gen()->start_array()); @@ -273,7 +273,7 @@ void PSPromotionManager::push_objArray(oop old_obj, oop new_obj) { size_t array_length = to_array->length(); size_t initial_chunk_size = // The source array is unused when processing states. - _partial_array_splitter.start(&_claimed_stack_depth, nullptr, to_array, array_length); + _partial_array_splitter.start(&_claimed_stack_depth, nullptr, to_array, array_length, ParGCArrayScanChunk); process_array_chunk(to_array, 0, initial_chunk_size); } diff --git a/src/hotspot/share/gc/shared/partialArraySplitter.cpp b/src/hotspot/share/gc/shared/partialArraySplitter.cpp index d1833872683..04884d5e666 100644 --- a/src/hotspot/share/gc/shared/partialArraySplitter.cpp +++ b/src/hotspot/share/gc/shared/partialArraySplitter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. * 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,10 +28,9 @@ #include "utilities/macros.hpp" PartialArraySplitter::PartialArraySplitter(PartialArrayStateManager* manager, - uint num_workers, - size_t chunk_size) + uint num_workers) : _allocator(manager), - _stepper(num_workers, chunk_size) + _stepper(num_workers) TASKQUEUE_STATS_ONLY(COMMA _stats()) {} diff --git a/src/hotspot/share/gc/shared/partialArraySplitter.hpp b/src/hotspot/share/gc/shared/partialArraySplitter.hpp index 87cc137e797..340f370d1d5 100644 --- a/src/hotspot/share/gc/shared/partialArraySplitter.hpp +++ b/src/hotspot/share/gc/shared/partialArraySplitter.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. * 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,8 +44,7 @@ class PartialArraySplitter { public: PartialArraySplitter(PartialArrayStateManager* manager, - uint num_workers, - size_t chunk_size); + uint num_workers); ~PartialArraySplitter() = default; NONCOPYABLE(PartialArraySplitter); @@ -60,6 +59,8 @@ public: // // length is their length in elements. // + // chunk_size the size of a single chunk. + // // If t is a ScannerTask, queue->push(t) must be a valid expression. The // result of that expression is ignored. // @@ -76,7 +77,8 @@ public: size_t start(Queue* queue, objArrayOop from_array, objArrayOop to_array, - size_t length); + size_t length, + size_t chunk_size); // Result type for claim(), carrying multiple values. Provides the claimed // chunk's start and end array indices. diff --git a/src/hotspot/share/gc/shared/partialArraySplitter.inline.hpp b/src/hotspot/share/gc/shared/partialArraySplitter.inline.hpp index abb0cf13101..7679358e218 100644 --- a/src/hotspot/share/gc/shared/partialArraySplitter.inline.hpp +++ b/src/hotspot/share/gc/shared/partialArraySplitter.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. * 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,16 @@ template size_t PartialArraySplitter::start(Queue* queue, objArrayOop source, objArrayOop destination, - size_t length) { - PartialArrayTaskStepper::Step step = _stepper.start(length); + size_t length, + size_t chunk_size) { + precond(chunk_size > 0); + PartialArrayTaskStepper::Step step = _stepper.start(length, chunk_size); // Push initial partial scan tasks. if (step._ncreate > 0) { TASKQUEUE_STATS_ONLY(_stats.inc_split();); TASKQUEUE_STATS_ONLY(_stats.inc_pushed(step._ncreate);) PartialArrayState* state = - _allocator.allocate(source, destination, step._index, length, step._ncreate); + _allocator.allocate(source, destination, step._index, length, chunk_size, step._ncreate); for (uint i = 0; i < step._ncreate; ++i) { queue->push(ScannerTask(state)); } @@ -75,9 +77,10 @@ PartialArraySplitter::claim(PartialArrayState* state, Queue* queue, bool stolen) queue->push(ScannerTask(state)); } } + size_t chunk_size = state->chunk_size(); // Release state, decrementing refcount, now that we're done with it. _allocator.release(state); - return Claim{step._index, step._index + _stepper.chunk_size()}; + return Claim{step._index, step._index + chunk_size}; } #endif // SHARE_GC_SHARED_PARTIALARRAYSPLITTER_INLINE_HPP diff --git a/src/hotspot/share/gc/shared/partialArrayState.cpp b/src/hotspot/share/gc/shared/partialArrayState.cpp index aadbc46b7c1..d3b21c2fdaa 100644 --- a/src/hotspot/share/gc/shared/partialArrayState.cpp +++ b/src/hotspot/share/gc/shared/partialArrayState.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,10 +35,12 @@ PartialArrayState::PartialArrayState(oop src, oop dst, size_t index, size_t length, + size_t chunk_size, size_t initial_refcount) : _source(src), _destination(dst), _length(length), + _chunk_size(chunk_size), _index(index), _refcount(initial_refcount) { @@ -77,6 +79,7 @@ PartialArrayStateAllocator::~PartialArrayStateAllocator() { PartialArrayState* PartialArrayStateAllocator::allocate(oop src, oop dst, size_t index, size_t length, + size_t chunk_size, size_t initial_refcount) { void* p; FreeListEntry* head = _free_list; @@ -87,7 +90,7 @@ PartialArrayState* PartialArrayStateAllocator::allocate(oop src, oop dst, head->~FreeListEntry(); p = head; } - return ::new (p) PartialArrayState(src, dst, index, length, initial_refcount); + return ::new (p) PartialArrayState(src, dst, index, length, chunk_size, initial_refcount); } void PartialArrayStateAllocator::release(PartialArrayState* state) { diff --git a/src/hotspot/share/gc/shared/partialArrayState.hpp b/src/hotspot/share/gc/shared/partialArrayState.hpp index 3dafeb0f14c..75e297526ae 100644 --- a/src/hotspot/share/gc/shared/partialArrayState.hpp +++ b/src/hotspot/share/gc/shared/partialArrayState.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -61,6 +61,7 @@ class PartialArrayState { oop _source; oop _destination; size_t _length; + size_t _chunk_size; Atomic _index; Atomic _refcount; @@ -68,7 +69,7 @@ class PartialArrayState { PartialArrayState(oop src, oop dst, size_t index, size_t length, - size_t initial_refcount); + size_t chunk_size, size_t initial_refcount); public: // Deleted to require management by allocator object. @@ -89,6 +90,8 @@ public: // The length of the array oop. size_t length() const { return _length; } + size_t chunk_size() const { return _chunk_size; } + // A pointer to the start index for the next segment to process, for atomic // update. Atomic* index_addr() { return &_index; } @@ -130,6 +133,7 @@ public: // from the associated manager. PartialArrayState* allocate(oop src, oop dst, size_t index, size_t length, + size_t chunk_size, size_t initial_refcount); // Decrement the state's refcount. If the new refcount is zero, add the diff --git a/src/hotspot/share/gc/shared/partialArrayTaskStepper.cpp b/src/hotspot/share/gc/shared/partialArrayTaskStepper.cpp index d91ba347d6c..f7d53c9348a 100644 --- a/src/hotspot/share/gc/shared/partialArrayTaskStepper.cpp +++ b/src/hotspot/share/gc/shared/partialArrayTaskStepper.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * 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,8 +48,7 @@ static uint compute_task_fanout(uint task_limit) { return result; } -PartialArrayTaskStepper::PartialArrayTaskStepper(uint n_workers, size_t chunk_size) : - _chunk_size(chunk_size), +PartialArrayTaskStepper::PartialArrayTaskStepper(uint n_workers) : _task_limit(compute_task_limit(n_workers)), _task_fanout(compute_task_fanout(_task_limit)) {} diff --git a/src/hotspot/share/gc/shared/partialArrayTaskStepper.hpp b/src/hotspot/share/gc/shared/partialArrayTaskStepper.hpp index 11499ca2ffe..594cc7b245a 100644 --- a/src/hotspot/share/gc/shared/partialArrayTaskStepper.hpp +++ b/src/hotspot/share/gc/shared/partialArrayTaskStepper.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * 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,19 +40,19 @@ class PartialArrayState; // substantially expand the task queues. class PartialArrayTaskStepper { public: - PartialArrayTaskStepper(uint n_workers, size_t chunk_size); + PartialArrayTaskStepper(uint n_workers); struct Step { size_t _index; // Array index for the step. uint _ncreate; // Number of new tasks to create. }; - // Called with the length of the array to be processed. Returns a Step with - // _index being the end of the initial chunk, which the caller should - // process. This is also the starting index for the next chunk to process. + // Called with the length of the array to be processed and chunk size. + // Returns a Step with _index being the end of the initial chunk, which the + // caller should process. This is also the starting index for the next chunk to process. // The _ncreate is the number of tasks to enqueue to continue processing the // array. If _ncreate is zero then _index will be length. - inline Step start(size_t length) const; + inline Step start(size_t length, size_t chunk_size) const; // Atomically increment state's index by chunk_size() to claim the next // chunk. Returns a Step with _index being the starting index of the @@ -60,21 +60,16 @@ public: // to enqueue. inline Step next(PartialArrayState* state) const; - // The size of chunks to claim for each task. - inline size_t chunk_size() const; - class TestSupport; // For unit tests private: - // Size (number of elements) of a chunk to process. - size_t _chunk_size; // Limit on the number of partial array tasks to create for a given array. uint _task_limit; // Maximum number of new tasks to create when processing an existing task. uint _task_fanout; // For unit tests. - inline Step next_impl(size_t length, Atomic* index_addr) const; + inline Step next_impl(size_t length, size_t chunk_size, Atomic* index_addr) const; }; #endif // SHARE_GC_SHARED_PARTIALARRAYTASKSTEPPER_HPP diff --git a/src/hotspot/share/gc/shared/partialArrayTaskStepper.inline.hpp b/src/hotspot/share/gc/shared/partialArrayTaskStepper.inline.hpp index 6946f7c69ff..538815698f2 100644 --- a/src/hotspot/share/gc/shared/partialArrayTaskStepper.inline.hpp +++ b/src/hotspot/share/gc/shared/partialArrayTaskStepper.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,13 +31,9 @@ #include "utilities/checkedCast.hpp" #include "utilities/debug.hpp" -size_t PartialArrayTaskStepper::chunk_size() const { - return _chunk_size; -} - PartialArrayTaskStepper::Step -PartialArrayTaskStepper::start(size_t length) const { - size_t end = length % _chunk_size; // End of initial chunk. +PartialArrayTaskStepper::start(size_t length, size_t chunk_size) const { + size_t end = length % chunk_size; // End of initial chunk. // If the initial chunk is the complete array, then don't need any partial // tasks. Otherwise, start with just one partial task; see new task // calculation in next(). @@ -45,24 +41,24 @@ PartialArrayTaskStepper::start(size_t length) const { } PartialArrayTaskStepper::Step -PartialArrayTaskStepper::next_impl(size_t length, Atomic* index_addr) const { +PartialArrayTaskStepper::next_impl(size_t length, size_t chunk_size, Atomic* index_addr) const { // The start of the next task is in the state's index. // Atomically increment by the chunk size to claim the associated chunk. // Because we limit the number of enqueued tasks to being no more than the // number of remaining chunks to process, we can use an atomic add for the // claim, rather than a CAS loop. - size_t start = index_addr->fetch_then_add(_chunk_size, memory_order_relaxed); + size_t start = index_addr->fetch_then_add(chunk_size, memory_order_relaxed); assert(start < length, "invariant: start %zu, length %zu", start, length); - assert(((length - start) % _chunk_size) == 0, + assert(((length - start) % chunk_size) == 0, "invariant: start %zu, length %zu, chunk size %zu", - start, length, _chunk_size); + start, length, chunk_size); // Determine the number of new tasks to create. // Zero-based index for this partial task. The initial task isn't counted. - uint task_num = checked_cast(start / _chunk_size); + uint task_num = checked_cast(start / chunk_size); // Number of tasks left to process, including this one. - uint remaining_tasks = checked_cast((length - start) / _chunk_size); + uint remaining_tasks = checked_cast((length - start) / chunk_size); assert(remaining_tasks > 0, "invariant"); // Compute number of pending tasks, including this one. The maximum number // of tasks is a function of task_num (N) and _task_fanout (F). @@ -89,7 +85,7 @@ PartialArrayTaskStepper::next_impl(size_t length, Atomic* index_addr) co PartialArrayTaskStepper::Step PartialArrayTaskStepper::next(PartialArrayState* state) const { - return next_impl(state->length(), state->index_addr()); + return next_impl(state->length(), state->chunk_size(), state->index_addr()); } #endif // SHARE_GC_SHARED_PARTIALARRAYTASKSTEPPER_INLINE_HPP diff --git a/test/hotspot/gtest/gc/shared/test_partialArrayTaskStepper.cpp b/test/hotspot/gtest/gc/shared/test_partialArrayTaskStepper.cpp index 977e7a9d949..3f5b6c0706c 100644 --- a/test/hotspot/gtest/gc/shared/test_partialArrayTaskStepper.cpp +++ b/test/hotspot/gtest/gc/shared/test_partialArrayTaskStepper.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,8 +34,9 @@ class PartialArrayTaskStepper::TestSupport : AllStatic { public: static Step next(const Stepper* stepper, size_t length, + size_t chunk_size, Atomic* to_length_addr) { - return stepper->next_impl(length, to_length_addr); + return stepper->next_impl(length, chunk_size, to_length_addr); } }; @@ -43,23 +44,24 @@ using StepperSupport = PartialArrayTaskStepper::TestSupport; static uint simulate(const Stepper* stepper, size_t length, + size_t chunk_size, Atomic* to_length_addr) { - Step init = stepper->start(length); + Step init = stepper->start(length, chunk_size); to_length_addr->store_relaxed(init._index); uint queue_count = init._ncreate; uint task = 0; for ( ; queue_count > 0; ++task) { --queue_count; - Step step = StepperSupport::next(stepper, length, to_length_addr); + Step step = StepperSupport::next(stepper, length, chunk_size, to_length_addr); queue_count += step._ncreate; } return task; } static void run_test(size_t length, size_t chunk_size, uint n_workers) { - const PartialArrayTaskStepper stepper(n_workers, chunk_size); + const PartialArrayTaskStepper stepper(n_workers); Atomic to_length; - uint tasks = simulate(&stepper, length, &to_length); + uint tasks = simulate(&stepper, length, chunk_size, &to_length); ASSERT_EQ(length, to_length.load_relaxed()); ASSERT_EQ(tasks, length / chunk_size); } From d4bb97c7d63bb9256027446ac5712c175052ab96 Mon Sep 17 00:00:00 2001 From: Ivan Walulya Date: Tue, 14 Apr 2026 14:17:21 +0000 Subject: [PATCH 277/359] 8379677: G1: Micros-System.gc benchmarks regress after moving to PartialArrayStates Co-authored-by: Thomas Schatzl Reviewed-by: tschatzl, ayang --- src/hotspot/share/gc/g1/g1FullGCMarker.cpp | 20 +++++++++++++++---- src/hotspot/share/gc/shared/gc_globals.hpp | 8 +++++++- .../share/gc/shared/jvmFlagConstraintsGC.cpp | 14 ++++++++++++- .../share/gc/shared/jvmFlagConstraintsGC.hpp | 5 +++-- 4 files changed, 39 insertions(+), 8 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1FullGCMarker.cpp b/src/hotspot/share/gc/g1/g1FullGCMarker.cpp index 5af1eae92c5..3be4ab8d839 100644 --- a/src/hotspot/share/gc/g1/g1FullGCMarker.cpp +++ b/src/hotspot/share/gc/g1/g1FullGCMarker.cpp @@ -60,14 +60,26 @@ void G1FullGCMarker::process_partial_array(PartialArrayState* state, bool stolen process_array_chunk(obj_array, claim._start, claim._end); } +static uintx calc_array_stride(uint array_len, uint num_threads) { + precond(num_threads > 0); + + const size_t stride = (array_len + num_threads - 1) / num_threads; + return clamp(stride, ArrayMarkingMinStride, ObjArrayMarkingStride); +} + void G1FullGCMarker::start_partial_array_processing(objArrayOop obj) { mark_closure()->do_klass(obj->klass()); // Don't push empty arrays to avoid unnecessary work. - size_t array_length = obj->length(); - if (array_length > 0) { - size_t initial_chunk_size = _partial_array_splitter.start(task_queue(), obj, nullptr, array_length, ObjArrayMarkingStride); - process_array_chunk(obj, 0, initial_chunk_size); + const int array_length = obj->length(); + + if (array_length == 0) { + return; } + + const uintx stride = calc_array_stride(array_length, _collector->workers()); + const size_t initial_chunk_size = _partial_array_splitter.start(task_queue(), obj, nullptr, array_length, stride); + + process_array_chunk(obj, 0, initial_chunk_size); } void G1FullGCMarker::complete_marking(G1ScannerTasksQueueSet* task_queues, diff --git a/src/hotspot/share/gc/shared/gc_globals.hpp b/src/hotspot/share/gc/shared/gc_globals.hpp index 66ca10f1fb6..c9102944197 100644 --- a/src/hotspot/share/gc/shared/gc_globals.hpp +++ b/src/hotspot/share/gc/shared/gc_globals.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -256,6 +256,12 @@ "before pushing a continuation entry") \ range(1, INT_MAX/2) \ \ + product(uintx, ArrayMarkingMinStride, 64, DIAGNOSTIC, \ + "Minimum chunk size for split array processing during marking; " \ + "the effective stride is clamped between this value " \ + "and ObjArrayMarkingStride.") \ + constraint(ArrayMarkingMinStrideConstraintFunc,AfterErgo) \ + \ product(bool, AggressiveHeap, false, \ "(Deprecated) Optimize heap options for long-running memory " \ "intensive apps") \ diff --git a/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.cpp b/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.cpp index ea3d644d105..4d7ffce3a5d 100644 --- a/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.cpp +++ b/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -414,3 +414,15 @@ JVMFlag::Error GCCardSizeInBytesConstraintFunc(uint value, bool verbose) { return JVMFlag::SUCCESS; } } + +JVMFlag::Error ArrayMarkingMinStrideConstraintFunc(uintx value, bool verbose) { + if (value > ObjArrayMarkingStride) { + JVMFlag::printError(verbose, + "ArrayMarkingMinStride (%zu) must be " + "less than or equal to ObjArrayMarkingStride (%zu)\n", + value, ObjArrayMarkingStride); + return JVMFlag::VIOLATES_CONSTRAINT; + } else { + return JVMFlag::SUCCESS; + } +} diff --git a/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.hpp b/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.hpp index a89f42959e1..1d2f45397aa 100644 --- a/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.hpp +++ b/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * 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,8 @@ f(uintx, SurvivorRatioConstraintFunc) \ f(size_t, MetaspaceSizeConstraintFunc) \ f(size_t, MaxMetaspaceSizeConstraintFunc) \ - f(uint, GCCardSizeInBytesConstraintFunc) + f(uint, GCCardSizeInBytesConstraintFunc) \ + f(uintx, ArrayMarkingMinStrideConstraintFunc) SHARED_GC_CONSTRAINTS(DECLARE_CONSTRAINT) From 49a15be918673ee49c3a02287aa268a87419147a Mon Sep 17 00:00:00 2001 From: Naoto Sato Date: Tue, 14 Apr 2026 16:35:31 +0000 Subject: [PATCH 278/359] 8382020: Time Zone Abbreviation Not Localized for Non-English Locales Reviewed-by: iris --- .../tools/cldrconverter/CLDRConverter.java | 38 +- .../resources/cldr/TimeZoneNamesTest.java | 368 ++++++++++-------- 2 files changed, 237 insertions(+), 169 deletions(-) diff --git a/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java b/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java index de496b3f606..9f42326ef09 100644 --- a/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java +++ b/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java @@ -801,10 +801,7 @@ public class CLDRConverter { String tzKey = Optional.ofNullable((String)handlerSupplMeta.get(tzid)) .orElse(tzid); // Follow link, if needed - String tzLink = null; - for (var k = tzKey; tzdbLinks.containsKey(k);) { - k = tzLink = tzdbLinks.get(k); - } + String tzLink = getTZDBLink(tzKey); if (tzLink == null && tzdbLinks.containsValue(tzKey)) { // reverse link search // this is needed as in tzdb, "America/Buenos_Aires" links to @@ -833,7 +830,7 @@ public class CLDRConverter { } else { // TZDB short names tznames = Arrays.copyOf(tznames, tznames.length); - fillTZDBShortNames(tzid, tznames); + fillTZDBShortNames(tzKey, tznames); names.put(tzid, tznames); } } else { @@ -846,11 +843,13 @@ public class CLDRConverter { String metaKey = METAZONE_ID_PREFIX + meta; data = map.get(metaKey); if (data instanceof String[] tznames) { - // TZDB short names - tznames = Arrays.copyOf((String[])names.getOrDefault(metaKey, tznames), 6); - fillTZDBShortNames(tzid, tznames); - // Keep the metazone prefix here. - names.putIfAbsent(metaKey, tznames); + if (isDefaultZone(meta, tzKey)) { + // Record the metazone names only from the default + // (001) zone, with short names filled from TZDB + tznames = Arrays.copyOf(tznames, tznames.length); + fillTZDBShortNames(tzKey, tznames); + names.put(metaKey, tznames); + } names.put(tzid, meta); if (tzLink != null && availableIds.contains(tzLink)) { names.put(tzLink, meta); @@ -1504,12 +1503,12 @@ public class CLDRConverter { * Fill the TZDB short names if there is no name provided by the CLDR */ private static void fillTZDBShortNames(String tzid, String[] names) { - var val = tzdbShortNamesMap.get(tzdbLinks.getOrDefault(tzid, tzid)); + var val = tzdbShortNamesMap.getOrDefault(tzid, tzdbShortNamesMap.get(getTZDBLink(tzid))); if (val != null) { var format = val.split(NBSP)[0]; var rule = val.split(NBSP)[1]; IntStream.of(1, 3, 5).forEach(i -> { - if (names[i] == null) { + if (names[i] == null || names[i].isEmpty()) { if (format.contains("%s")) { names[i] = switch (i) { case 1 -> format.formatted(tzdbSubstLetters.get(rule + NBSP + STD)); @@ -1531,6 +1530,21 @@ public class CLDRConverter { } } + private static boolean isDefaultZone(String meta, String tzid) { + String zone001 = handlerMetaZones.zidMap().get(meta); + var tzLink = getTZDBLink(tzid); + return canonicalTZMap.getOrDefault(tzid, tzid).equals(zone001) || + tzLink != null && canonicalTZMap.getOrDefault(tzLink, tzLink).equals(zone001); + } + + private static String getTZDBLink(String tzid) { + String tzLink = null; + for (var k = tzid; tzdbLinks.containsKey(k);) { + k = tzLink = tzdbLinks.get(k); + } + return tzLink; + } + /* * Convert TZDB offsets to JDK's offsets, eg, "-08" to "GMT-08:00". * If it cannot recognize the pattern, return the argument as is. diff --git a/test/jdk/sun/util/resources/cldr/TimeZoneNamesTest.java b/test/jdk/sun/util/resources/cldr/TimeZoneNamesTest.java index 4d9b7500d87..b02f988e7c0 100644 --- a/test/jdk/sun/util/resources/cldr/TimeZoneNamesTest.java +++ b/test/jdk/sun/util/resources/cldr/TimeZoneNamesTest.java @@ -24,7 +24,7 @@ /* * @test * @bug 8181157 8202537 8234347 8236548 8261279 8322647 8174269 8346948 - * 8354548 8381379 + * 8354548 8381379 8382020 * @modules jdk.localedata * @summary Checks CLDR time zone names are generated correctly at * either build or runtime @@ -62,164 +62,218 @@ public class TimeZoneNamesTest { // no "metazone" zones (some of them were assigned metazones // over time, thus they are not "generated" per se - {"Asia/Srednekolymsk", Locale.US, "Magadan Standard Time", - "GMT+11:00", - "Magadan Summer Time", - "GMT+12:00", - "Magadan Time", - "GMT+11:00"}, - {"Asia/Srednekolymsk", Locale.FRANCE, "heure normale de Magadan", - "UTC+11:00", - "heure d’été de Magadan", - "UTC+12:00", - "heure de Magadan", - "UTC+11:00"}, - {"America/Punta_Arenas", Locale.US, "Punta Arenas Standard Time", - "GMT-03:00", - "Punta Arenas Daylight Time", - "GMT-02:00", - "Punta Arenas Time", - "GMT-03:00"}, - {"America/Punta_Arenas", Locale.FRANCE, "Punta Arenas (heure standard)", - "UTC−03:00", - "Punta Arenas (heure d’été)", - "UTC−02:00", - "heure : Punta Arenas", - "UTC−03:00"}, - {"Asia/Famagusta", Locale.US, "Eastern European Standard Time", - "EET", - "Eastern European Summer Time", - "EEST", - "Eastern European Time", - "EET"}, - {"Asia/Famagusta", Locale.FRANCE, "heure normale d’Europe de l’Est", - "EET", - "heure d’été d’Europe de l’Est", - "EEST", - "heure d’Europe de l’Est", - "EET"}, - {"Europe/Astrakhan", Locale.US, "Samara Standard Time", - "GMT+04:00", - "Samara Summer Time", - "GMT+05:00", - "Samara Time", - "GMT+04:00"}, - {"Europe/Astrakhan", Locale.FRANCE, "heure normale de Samara", - "UTC+04:00", - "heure d’été de Samara", - "UTC+05:00", - "heure de Samara", - "UTC+04:00"}, - {"Europe/Saratov", Locale.US, "Samara Standard Time", - "GMT+04:00", - "Samara Summer Time", - "GMT+05:00", - "Samara Time", - "GMT+04:00"}, - {"Europe/Saratov", Locale.FRANCE, "heure normale de Samara", - "UTC+04:00", - "heure d’été de Samara", - "UTC+05:00", - "heure de Samara", - "UTC+04:00"}, - {"Europe/Ulyanovsk", Locale.US, "Samara Standard Time", - "GMT+04:00", - "Samara Summer Time", - "GMT+05:00", - "Samara Time", - "GMT+04:00"}, - {"Europe/Ulyanovsk", Locale.FRANCE, "heure normale de Samara", - "UTC+04:00", - "heure d’été de Samara", - "UTC+05:00", - "heure de Samara", - "UTC+04:00"}, - {"Pacific/Bougainville", Locale.US, "Bougainville Standard Time", - "GMT+11:00", - "Bougainville Daylight Time", - "GMT+11:00", - "Bougainville Time", - "GMT+11:00"}, - {"Pacific/Bougainville", Locale.FRANCE, "Bougainville (heure standard)", - "UTC+11:00", - "Bougainville (heure d’été)", - "UTC+11:00", - "heure : Bougainville", - "UTC+11:00"}, - {"Europe/Istanbul", Locale.US, "Türkiye Standard Time", - "GMT+03:00", - "Türkiye Summer Time", - "GMT+04:00", - "Türkiye Time", - "GMT+03:00"}, - {"Europe/Istanbul", Locale.FRANCE, "heure normale de Turquie", - "UTC+03:00", - "heure avancée de Turquie", - "UTC+04:00", - "heure de Turquie", - "UTC+03:00"}, - {"Asia/Istanbul", Locale.US, "Türkiye Standard Time", - "GMT+03:00", - "Türkiye Summer Time", - "GMT+04:00", - "Türkiye Time", - "GMT+03:00"}, - {"Asia/Istanbul", Locale.FRANCE, "heure normale de Turquie", - "UTC+03:00", - "heure avancée de Turquie", - "UTC+04:00", - "heure de Turquie", - "UTC+03:00"}, - {"Turkey", Locale.US, "Türkiye Standard Time", - "GMT+03:00", - "Türkiye Summer Time", - "GMT+04:00", - "Türkiye Time", - "GMT+03:00"}, - {"Turkey", Locale.FRANCE, "heure normale de Turquie", - "UTC+03:00", - "heure avancée de Turquie", - "UTC+04:00", - "heure de Turquie", - "UTC+03:00"}, + {"Asia/Srednekolymsk", Locale.US, + "Magadan Standard Time", + "GMT+11:00", + "Magadan Summer Time", + "GMT+12:00", + "Magadan Time", + "GMT+11:00"}, + {"Asia/Srednekolymsk", Locale.FRANCE, + "heure normale de Magadan", + "UTC+11:00", + "heure d’été de Magadan", + "UTC+12:00", + "heure de Magadan", + "UTC+11:00"}, + {"America/Punta_Arenas", Locale.US, + "Punta Arenas Standard Time", + "GMT-03:00", + "Punta Arenas Daylight Time", + "GMT-02:00", + "Punta Arenas Time", + "GMT-03:00"}, + {"America/Punta_Arenas", Locale.FRANCE, + "Punta Arenas (heure standard)", + "UTC−03:00", + "Punta Arenas (heure d’été)", + "UTC−02:00", + "heure : Punta Arenas", + "UTC−03:00"}, + {"Asia/Famagusta", Locale.US, + "Eastern European Standard Time", + "EET", + "Eastern European Summer Time", + "EEST", + "Eastern European Time", + "EET"}, + {"Asia/Famagusta", Locale.FRANCE, + "heure normale d’Europe de l’Est", + "EET", + "heure d’été d’Europe de l’Est", + "EEST", + "heure d’Europe de l’Est", + "EET"}, + {"Europe/Astrakhan", Locale.US, + "Samara Standard Time", + "GMT+04:00", + "Samara Summer Time", + "GMT+05:00", + "Samara Time", + "GMT+04:00"}, + {"Europe/Astrakhan", Locale.FRANCE, + "heure normale de Samara", + "UTC+04:00", + "heure d’été de Samara", + "UTC+05:00", + "heure de Samara", + "UTC+04:00"}, + {"Europe/Saratov", Locale.US, + "Samara Standard Time", + "GMT+04:00", + "Samara Summer Time", + "GMT+05:00", + "Samara Time", + "GMT+04:00"}, + {"Europe/Saratov", Locale.FRANCE, + "heure normale de Samara", + "UTC+04:00", + "heure d’été de Samara", + "UTC+05:00", + "heure de Samara", + "UTC+04:00"}, + {"Europe/Ulyanovsk", Locale.US, + "Samara Standard Time", + "GMT+04:00", + "Samara Summer Time", + "GMT+05:00", + "Samara Time", + "GMT+04:00"}, + {"Europe/Ulyanovsk", Locale.FRANCE, + "heure normale de Samara", + "UTC+04:00", + "heure d’été de Samara", + "UTC+05:00", + "heure de Samara", + "UTC+04:00"}, + {"Pacific/Bougainville", Locale.US, + "Bougainville Standard Time", + "GMT+11:00", + "Bougainville Daylight Time", + "GMT+11:00", + "Bougainville Time", + "GMT+11:00"}, + {"Pacific/Bougainville", Locale.FRANCE, + "Bougainville (heure standard)", + "UTC+11:00", + "Bougainville (heure d’été)", + "UTC+11:00", + "heure : Bougainville", + "UTC+11:00"}, + {"Europe/Istanbul", Locale.US, + "Türkiye Standard Time", + "GMT+03:00", + "Türkiye Summer Time", + "GMT+04:00", + "Türkiye Time", + "GMT+03:00"}, + {"Europe/Istanbul", Locale.FRANCE, + "heure normale de Turquie", + "UTC+03:00", + "heure avancée de Turquie", + "UTC+04:00", + "heure de Turquie", + "UTC+03:00"}, + {"Asia/Istanbul", Locale.US, + "Türkiye Standard Time", + "GMT+03:00", + "Türkiye Summer Time", + "GMT+04:00", + "Türkiye Time", + "GMT+03:00"}, + {"Asia/Istanbul", Locale.FRANCE, + "heure normale de Turquie", + "UTC+03:00", + "heure avancée de Turquie", + "UTC+04:00", + "heure de Turquie", + "UTC+03:00"}, + {"Turkey", Locale.US, + "Türkiye Standard Time", + "GMT+03:00", + "Türkiye Summer Time", + "GMT+04:00", + "Türkiye Time", + "GMT+03:00"}, + {"Turkey", Locale.FRANCE, + "heure normale de Turquie", + "UTC+03:00", + "heure avancée de Turquie", + "UTC+04:00", + "heure de Turquie", + "UTC+03:00"}, // Short names derived from TZDB at build time - {"Europe/Lisbon", Locale.US, "Western European Standard Time", - "WET", - "Western European Summer Time", - "WEST", - "Western European Time", - "WET"}, - {"Atlantic/Azores", Locale.US, "Azores Standard Time", - "GMT-01:00", - "Azores Summer Time", - "GMT", - "Azores Time", - "GMT-01:00"}, - {"Australia/Perth", Locale.US, "Australian Western Standard Time", - "AWST", - "Australian Western Daylight Time", - "AWDT", - "Australian Western Time", - "AWT"}, - {"Africa/Harare", Locale.US, "Central Africa Time", - "CAT", - "Harare Daylight Time", - "CAT", - "Harare Time", - "CAT"}, - {"Europe/Dublin", Locale.US, "Greenwich Mean Time", - "GMT", - "Irish Standard Time", - "IST", - "Dublin Time", - "GMT"}, - {"Pacific/Gambier", Locale.US, "Gambier Time", - "GMT-09:00", - "Gambier Daylight Time", - "GMT-09:00", - "Gambier Time", - "GMT-09:00"}, + {"Europe/Lisbon", Locale.US, + "Western European Standard Time", + "WET", + "Western European Summer Time", + "WEST", + "Western European Time", + "WET"}, + {"Atlantic/Azores", Locale.US, + "Azores Standard Time", + "GMT-01:00", + "Azores Summer Time", + "GMT", + "Azores Time", + "GMT-01:00"}, + {"Australia/Perth", Locale.US, + "Australian Western Standard Time", + "AWST", + "Australian Western Daylight Time", + "AWDT", + "Australian Western Time", + "AWT"}, + {"Africa/Harare", Locale.US, + "Central Africa Time", + "CAT", + "Harare Daylight Time", + "CAT", + "Harare Time", + "CAT"}, + {"Europe/Dublin", Locale.US, + "Greenwich Mean Time", + "GMT", + "Irish Standard Time", + "IST", + "Dublin Time", + "GMT"}, + {"Pacific/Gambier", Locale.US, + "Gambier Time", + "GMT-09:00", + "Gambier Daylight Time", + "GMT-09:00", + "Gambier Time", + "GMT-09:00"}, + {"America/New_York", Locale.US, + "Eastern Standard Time", + "EST", + "Eastern Daylight Time", + "EDT", + "Eastern Time", + "ET"}, + {"America/New_York", Locale.GERMAN, + "Nordamerikanische Ostküsten-Normalzeit", + "EST", + "Nordamerikanische Ostküsten-Sommerzeit", + "EDT", + "Nordamerikanische Ostküstenzeit", + "ET"}, + {"America/New_York", Locale.JAPANESE, + "米国東部標準時", + "EST", + "米国東部夏時間", + "EDT", + "米国東部時間", + "ET"}, + {"America/New_York", Locale.of("ru"), + "Восточная Америка, стандартное время", + "EST", + "Восточная Америка, летнее время", + "EDT", + "Восточная Америка", + "ET"}, }; } From 44c484c150e66d3be3e865d52601388133380063 Mon Sep 17 00:00:00 2001 From: Ashutosh Mehra Date: Tue, 14 Apr 2026 18:08:23 +0000 Subject: [PATCH 279/359] 8381677: Remove dependence of UseSHA on UseSHAIntrinsics Reviewed-by: kvn, adinn, mdoerr, fyang, amitkumar --- .../cpu/aarch64/vm_version_aarch64.cpp | 4 --- src/hotspot/cpu/ppc/vm_version_ppc.cpp | 5 ---- src/hotspot/cpu/riscv/vm_version_riscv.cpp | 5 ---- src/hotspot/cpu/s390/vm_version_s390.cpp | 4 --- src/hotspot/cpu/x86/vm_version_x86.cpp | 4 --- ...UseSHASpecificTestCaseForSupportedCPU.java | 27 +++---------------- 6 files changed, 3 insertions(+), 46 deletions(-) diff --git a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp index 15af2d5c4e2..441bd4859fe 100644 --- a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp @@ -437,10 +437,6 @@ void VM_Version::initialize() { FLAG_SET_DEFAULT(UseSHA512Intrinsics, false); } - if (!(UseSHA1Intrinsics || UseSHA256Intrinsics || UseSHA3Intrinsics || UseSHA512Intrinsics)) { - FLAG_SET_DEFAULT(UseSHA, false); - } - if (supports_pmull()) { if (FLAG_IS_DEFAULT(UseGHASHIntrinsics)) { FLAG_SET_DEFAULT(UseGHASHIntrinsics, true); diff --git a/src/hotspot/cpu/ppc/vm_version_ppc.cpp b/src/hotspot/cpu/ppc/vm_version_ppc.cpp index 0b69ef7d25a..3e3b1103c86 100644 --- a/src/hotspot/cpu/ppc/vm_version_ppc.cpp +++ b/src/hotspot/cpu/ppc/vm_version_ppc.cpp @@ -311,11 +311,6 @@ void VM_Version::initialize() { FLAG_SET_DEFAULT(UseSHA3Intrinsics, false); } - if (!(UseSHA1Intrinsics || UseSHA256Intrinsics || UseSHA512Intrinsics)) { - FLAG_SET_DEFAULT(UseSHA, false); - } - - #ifdef COMPILER2 if (FLAG_IS_DEFAULT(UseSquareToLenIntrinsic)) { UseSquareToLenIntrinsic = true; diff --git a/src/hotspot/cpu/riscv/vm_version_riscv.cpp b/src/hotspot/cpu/riscv/vm_version_riscv.cpp index 36f0864da0b..3a6415d52bd 100644 --- a/src/hotspot/cpu/riscv/vm_version_riscv.cpp +++ b/src/hotspot/cpu/riscv/vm_version_riscv.cpp @@ -420,11 +420,6 @@ void VM_Version::c2_initialize() { FLAG_SET_DEFAULT(UseSHA3Intrinsics, false); } - // UseSHA - if (!(UseSHA1Intrinsics || UseSHA256Intrinsics || UseSHA3Intrinsics || UseSHA512Intrinsics)) { - FLAG_SET_DEFAULT(UseSHA, false); - } - // AES if (UseZvkn) { UseAES = UseAES || FLAG_IS_DEFAULT(UseAES); diff --git a/src/hotspot/cpu/s390/vm_version_s390.cpp b/src/hotspot/cpu/s390/vm_version_s390.cpp index 7f5b4870aab..7e9000991ca 100644 --- a/src/hotspot/cpu/s390/vm_version_s390.cpp +++ b/src/hotspot/cpu/s390/vm_version_s390.cpp @@ -289,10 +289,6 @@ void VM_Version::initialize() { FLAG_SET_DEFAULT(UseSHA3Intrinsics, false); } - if (!(UseSHA1Intrinsics || UseSHA256Intrinsics || UseSHA512Intrinsics)) { - FLAG_SET_DEFAULT(UseSHA, false); - } - if (UseSecondarySupersTable && VM_Version::get_model_index() < 5 /* z196/z11 */) { if (!FLAG_IS_DEFAULT(UseSecondarySupersTable)) { warning("UseSecondarySupersTable requires z196 or later."); diff --git a/src/hotspot/cpu/x86/vm_version_x86.cpp b/src/hotspot/cpu/x86/vm_version_x86.cpp index 39a9c618350..a688d834e9b 100644 --- a/src/hotspot/cpu/x86/vm_version_x86.cpp +++ b/src/hotspot/cpu/x86/vm_version_x86.cpp @@ -1373,10 +1373,6 @@ void VM_Version::get_processor_features() { FLAG_SET_DEFAULT(UseSHA3Intrinsics, false); } - if (!(UseSHA1Intrinsics || UseSHA256Intrinsics || UseSHA512Intrinsics || UseSHA3Intrinsics)) { - FLAG_SET_DEFAULT(UseSHA, false); - } - #if COMPILER2_OR_JVMCI int max_vector_size = 0; if (UseAVX == 0 || !os_supports_avx_vectors()) { diff --git a/test/hotspot/jtreg/compiler/intrinsics/sha/cli/testcases/UseSHASpecificTestCaseForSupportedCPU.java b/test/hotspot/jtreg/compiler/intrinsics/sha/cli/testcases/UseSHASpecificTestCaseForSupportedCPU.java index ddcfc7c5f7b..65f3e9b9141 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/sha/cli/testcases/UseSHASpecificTestCaseForSupportedCPU.java +++ b/test/hotspot/jtreg/compiler/intrinsics/sha/cli/testcases/UseSHASpecificTestCaseForSupportedCPU.java @@ -73,10 +73,10 @@ public class UseSHASpecificTestCaseForSupportedCPU @Override protected void verifyOptionValues() throws Throwable { - // Verify that UseSHA is disabled when all UseSHA*Intrinsics are - // disabled. + // Verify that UseSHA is not affected and remains enabled when all UseSHA*Intrinsics + // are disabled. CommandLineOptionTest.verifyOptionValueForSameVM( - DigestOptionsBase.USE_SHA_OPTION, "false", String.format( + DigestOptionsBase.USE_SHA_OPTION, "true", String.format( "'%s' option should be disabled when all UseSHA*Intrinsics are" + " disabled", DigestOptionsBase.USE_SHA_OPTION), DigestOptionsBase.UNLOCK_DIAGNOSTIC_VM_OPTIONS, @@ -89,27 +89,6 @@ public class UseSHASpecificTestCaseForSupportedCPU CommandLineOptionTest.prepareBooleanFlag( DigestOptionsBase.USE_SHA3_INTRINSICS_OPTION, false)); - CommandLineOptionTest.verifyOptionValueForSameVM( - // Verify that UseSHA is disabled when all UseSHA*Intrinsics are - // disabled even if it was explicitly enabled. - DigestOptionsBase.USE_SHA_OPTION, "false", - String.format("'%s' option should be disabled when all " - + "UseSHA*Intrinsics are disabled even if %s flag set " - + "to JVM", DigestOptionsBase.USE_SHA_OPTION, - CommandLineOptionTest.prepareBooleanFlag( - DigestOptionsBase.USE_SHA_OPTION, true)), - DigestOptionsBase.UNLOCK_DIAGNOSTIC_VM_OPTIONS, - CommandLineOptionTest.prepareBooleanFlag( - DigestOptionsBase.USE_SHA_OPTION, true), - CommandLineOptionTest.prepareBooleanFlag( - DigestOptionsBase.USE_SHA1_INTRINSICS_OPTION, false), - CommandLineOptionTest.prepareBooleanFlag( - DigestOptionsBase.USE_SHA256_INTRINSICS_OPTION, false), - CommandLineOptionTest.prepareBooleanFlag( - DigestOptionsBase.USE_SHA512_INTRINSICS_OPTION, false), - CommandLineOptionTest.prepareBooleanFlag( - DigestOptionsBase.USE_SHA3_INTRINSICS_OPTION, false)); - // Verify that explicitly disabled UseSHA option remains disabled even // if all UseSHA*Intrinsics options were enabled. CommandLineOptionTest.verifyOptionValueForSameVM( From bf68776ebcdcbb97faf21517efb3a5e025b29269 Mon Sep 17 00:00:00 2001 From: Ashutosh Mehra Date: Tue, 14 Apr 2026 19:39:32 +0000 Subject: [PATCH 280/359] 8382167: Warning message should be displayed only when UseAESCTRIntrinsics is explicitly enabled by the user Reviewed-by: sviswanathan, kvn --- src/hotspot/cpu/x86/vm_version_x86.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/cpu/x86/vm_version_x86.cpp b/src/hotspot/cpu/x86/vm_version_x86.cpp index a688d834e9b..cf9de40a237 100644 --- a/src/hotspot/cpu/x86/vm_version_x86.cpp +++ b/src/hotspot/cpu/x86/vm_version_x86.cpp @@ -1187,7 +1187,7 @@ void VM_Version::get_processor_features() { } if (!UseAESIntrinsics) { if (UseAESCTRIntrinsics) { - if (FLAG_IS_DEFAULT(UseAESCTRIntrinsics)) { + if (!FLAG_IS_DEFAULT(UseAESCTRIntrinsics)) { warning("AES-CTR intrinsics require UseAESIntrinsics flag to be enabled. Intrinsics will be disabled."); } FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false); From 764fc09bed335173c2cb4180c946e8593f023ae8 Mon Sep 17 00:00:00 2001 From: William Kemper Date: Tue, 14 Apr 2026 20:23:46 +0000 Subject: [PATCH 281/359] 8381643: Shenandoah: Remove duplicate region filtering logic Reviewed-by: kdnilsen, ruili, xpeng --- .../shenandoahGenerationalHeuristics.cpp | 130 ++++-------------- .../shenandoahGenerationalHeuristics.hpp | 15 +- .../heuristics/shenandoahGlobalHeuristics.cpp | 6 +- .../heuristics/shenandoahGlobalHeuristics.hpp | 6 +- .../heuristics/shenandoahHeuristics.cpp | 12 +- .../heuristics/shenandoahSpaceInfo.hpp | 5 + .../heuristics/shenandoahYoungHeuristics.cpp | 6 +- .../heuristics/shenandoahYoungHeuristics.hpp | 6 +- .../gc/shenandoah/mode/shenandoahMode.cpp | 1 - .../gc/shenandoah/shenandoahGeneration.cpp | 1 + .../gc/shenandoah/shenandoahGeneration.hpp | 2 +- .../gc/shenandoah/shenandoahOldGeneration.hpp | 5 + .../share/gc/shenandoah/shenandoahTrace.cpp | 32 +++-- .../share/gc/shenandoah/shenandoahTrace.hpp | 11 +- src/hotspot/share/jfr/metadata/metadata.xml | 12 +- src/jdk.jfr/share/conf/jfr/default.jfc | 4 + src/jdk.jfr/share/conf/jfr/profile.jfc | 4 + ...tShenandoahEvacuationInformationEvent.java | 4 +- ...stShenandoahPromotionInformationEvent.java | 100 ++++++++++++++ test/lib/jdk/test/lib/jfr/EventNames.java | 1 + 20 files changed, 216 insertions(+), 147 deletions(-) create mode 100644 test/jdk/jdk/jfr/event/gc/detailed/TestShenandoahPromotionInformationEvent.java diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp index a12f48c0877..594367e2972 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp @@ -69,15 +69,27 @@ ShenandoahGenerationalHeuristics::ShenandoahGenerationalHeuristics(ShenandoahGen : ShenandoahAdaptiveHeuristics(generation), _generation(generation), _add_regions_to_old(0) { } -void ShenandoahGenerationalHeuristics::choose_collection_set(ShenandoahCollectionSet* collection_set) { +void ShenandoahGenerationalHeuristics::choose_collection_set_from_regiondata(ShenandoahCollectionSet* collection_set, + RegionData* data, size_t data_size, + size_t free) { ShenandoahGenerationalHeap* heap = ShenandoahGenerationalHeap::heap(); - assert(collection_set->is_empty(), "Collection set must be empty here"); - _add_regions_to_old = 0; - // Choose the collection set - filter_regions(collection_set); + // Find the amount that will be promoted, regions that will be promoted in + // place, and preselected older regions that will be promoted by evacuation. + ShenandoahInPlacePromotionPlanner in_place_promotions(heap); + compute_evacuation_budgets(in_place_promotions, heap); + + // Call the subclasses to add regions into the collection set. + select_collection_set_regions(collection_set, data, data_size, free); + + // Even if collection_set->is_empty(), we want to adjust budgets, making reserves available to mutator. + adjust_evacuation_budgets(heap, collection_set); + + if (collection_set->has_old_regions()) { + heap->shenandoah_policy()->record_mixed_cycle(); + } if (_generation->is_global()) { // We have just chosen a collection set for a global cycle. The mark bitmap covering old regions is complete, so @@ -91,6 +103,14 @@ void ShenandoahGenerationalHeuristics::choose_collection_set(ShenandoahCollectio // after a global cycle for old regions that were not included in this collection set. heap->old_generation()->transition_old_generation_after_global_gc(); } + + ShenandoahTracer::report_promotion_info(collection_set, + in_place_promotions.humongous_region_stats().count, + in_place_promotions.humongous_region_stats().garbage, + in_place_promotions.humongous_region_stats().free, + in_place_promotions.regular_region_stats().count, + in_place_promotions.regular_region_stats().garbage, + in_place_promotions.regular_region_stats().free); } void ShenandoahGenerationalHeuristics::compute_evacuation_budgets(ShenandoahInPlacePromotionPlanner& in_place_promotions, @@ -216,106 +236,6 @@ void ShenandoahGenerationalHeuristics::compute_evacuation_budgets(ShenandoahInPl // case of a GLOBAL gc. During choose_collection_set() of GLOBAL, old will be expanded on demand. } -void ShenandoahGenerationalHeuristics::filter_regions(ShenandoahCollectionSet* collection_set) { - auto heap = ShenandoahGenerationalHeap::heap(); - const size_t region_size_bytes = ShenandoahHeapRegion::region_size_bytes(); - - // Check all pinned regions have updated status before choosing the collection set. - heap->assert_pinned_region_status(_generation); - - // Step 1. Build up the region candidates we care about, rejecting losers and accepting winners right away. - - const size_t num_regions = heap->num_regions(); - - RegionData* candidates = _region_data; - - size_t cand_idx = 0; - - size_t total_garbage = 0; - - size_t immediate_garbage = 0; - size_t immediate_regions = 0; - - size_t free = 0; - size_t free_regions = 0; - - for (size_t i = 0; i < num_regions; i++) { - ShenandoahHeapRegion* region = heap->get_region(i); - if (!_generation->contains(region)) { - continue; - } - const size_t garbage = region->garbage(); - total_garbage += garbage; - if (region->is_empty()) { - free_regions++; - free += region_size_bytes; - } else if (region->is_regular()) { - if (!region->has_live()) { - // We can recycle it right away and put it in the free set. - immediate_regions++; - immediate_garbage += garbage; - region->make_trash_immediate(); - } else { - // This is our candidate for later consideration. Note that this region - // could still be promoted in place and may not necessarily end up in the - // collection set. - assert(region->get_top_before_promote() == nullptr, "Cannot add region %zu scheduled for in-place-promotion to the collection set", i); - candidates[cand_idx].set_region_and_garbage(region, garbage); - cand_idx++; - } - } else if (region->is_humongous_start()) { - // Reclaim humongous regions here, and count them as the immediate garbage - DEBUG_ONLY(assert_humongous_mark_consistency(region)); - if (!region->has_live()) { - heap->trash_humongous_region_at(region); - - // Count only the start. Continuations would be counted on "trash" path - immediate_regions++; - immediate_garbage += garbage; - } - } else if (region->is_trash()) { - // Count in just trashed humongous continuation regions - immediate_regions++; - immediate_garbage += garbage; - } - } - - // Step 2. Look back at garbage statistics, and decide if we want to collect anything, - // given the amount of immediately reclaimable garbage. If we do, figure out the collection set. - assert(immediate_garbage <= total_garbage, - "Cannot have more immediate garbage than total garbage: " PROPERFMT " vs " PROPERFMT, - PROPERFMTARGS(immediate_garbage), PROPERFMTARGS(total_garbage)); - - const size_t immediate_percent = (total_garbage == 0) ? 0 : (immediate_garbage * 100 / total_garbage); - ShenandoahInPlacePromotionPlanner in_place_promotions(heap); - if (immediate_percent <= ShenandoahImmediateThreshold) { - - // Find the amount that will be promoted, regions that will be promoted in - // place, and preselected older regions that will be promoted by evacuation. - compute_evacuation_budgets(in_place_promotions, heap); - - // Call the subclasses to add young-gen regions into the collection set. - choose_collection_set_from_regiondata(collection_set, candidates, cand_idx, immediate_garbage + free); - - // Even if collection_set->is_empty(), we want to adjust budgets, making reserves available to mutator. - adjust_evacuation_budgets(heap, collection_set); - - if (collection_set->has_old_regions()) { - heap->shenandoah_policy()->record_mixed_cycle(); - } - } - - collection_set->summarize(total_garbage, immediate_garbage, immediate_regions); - ShenandoahTracer::report_evacuation_info(collection_set, - free_regions, - in_place_promotions.humongous_region_stats().count, - in_place_promotions.regular_region_stats().count, - in_place_promotions.regular_region_stats().garbage, - in_place_promotions.regular_region_stats().free, - immediate_regions, - immediate_garbage); -} - void ShenandoahGenerationalHeuristics::add_tenured_regions_to_collection_set(const size_t old_promotion_reserve, ShenandoahGenerationalHeap *const heap, size_t candidates, AgedRegionData* sorted_regions) { diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.hpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.hpp index 1a47cb756f4..8ea5cdb36c8 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.hpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.hpp @@ -53,10 +53,13 @@ class ShenandoahGenerationalHeuristics : public ShenandoahAdaptiveHeuristics { public: explicit ShenandoahGenerationalHeuristics(ShenandoahGeneration* generation); - void choose_collection_set(ShenandoahCollectionSet* collection_set) override; - void post_initialize() override; + // Wraps budget computation, subclass region selection, budget adjustment, and tracing. + void choose_collection_set_from_regiondata(ShenandoahCollectionSet* set, + RegionData* data, size_t data_size, + size_t free) override; + private: // Compute evacuation budgets prior to choosing collection set. void compute_evacuation_budgets(ShenandoahInPlacePromotionPlanner& in_place_promotions, ShenandoahHeap* const heap); @@ -84,15 +87,17 @@ private: ShenandoahGenerationalHeap *const heap, size_t candidates, AgedRegionData* sorted_regions); - // Filter and sort remaining regions before adding to collection set. - void filter_regions(ShenandoahCollectionSet* collection_set); - // Adjust evacuation budgets after choosing collection set. On entry, the instance variable _regions_to_xfer // represents regions to be transferred to old based on decisions made in top_off_collection_set() void adjust_evacuation_budgets(ShenandoahHeap* const heap, ShenandoahCollectionSet* const collection_set); protected: + // Subclasses override this to perform generation-specific region selection. + virtual void select_collection_set_regions(ShenandoahCollectionSet* set, + RegionData* data, size_t data_size, + size_t free) = 0; + ShenandoahGeneration* _generation; size_t _add_regions_to_old; diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGlobalHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGlobalHeuristics.cpp index ed25cd2e1a9..9452e8b28cb 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGlobalHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGlobalHeuristics.cpp @@ -112,9 +112,9 @@ ShenandoahGlobalHeuristics::ShenandoahGlobalHeuristics(ShenandoahGlobalGeneratio : ShenandoahGenerationalHeuristics(generation) { } -void ShenandoahGlobalHeuristics::choose_collection_set_from_regiondata(ShenandoahCollectionSet* cset, - RegionData* data, size_t size, - size_t actual_free) { +void ShenandoahGlobalHeuristics::select_collection_set_regions(ShenandoahCollectionSet* cset, + RegionData* data, size_t size, + size_t actual_free) { QuickSort::sort(data, size, compare_by_garbage); choose_global_collection_set(cset, data, size, actual_free, 0); } diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGlobalHeuristics.hpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGlobalHeuristics.hpp index 8102fa24d14..1e96a665704 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGlobalHeuristics.hpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGlobalHeuristics.hpp @@ -161,9 +161,9 @@ class ShenandoahGlobalHeuristics : public ShenandoahGenerationalHeuristics { public: ShenandoahGlobalHeuristics(ShenandoahGlobalGeneration* generation); - void choose_collection_set_from_regiondata(ShenandoahCollectionSet* cset, - RegionData* data, size_t size, - size_t actual_free) override; + void select_collection_set_regions(ShenandoahCollectionSet* cset, + RegionData* data, size_t size, + size_t actual_free) override; private: void choose_global_collection_set(ShenandoahCollectionSet* cset, diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.cpp index 895088381ee..3091b19b600 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.cpp @@ -29,6 +29,7 @@ #include "gc/shenandoah/shenandoahCollectorPolicy.hpp" #include "gc/shenandoah/shenandoahHeapRegion.inline.hpp" #include "gc/shenandoah/shenandoahMarkingContext.inline.hpp" +#include "gc/shenandoah/shenandoahTrace.hpp" #include "logging/log.hpp" #include "logging/logTag.hpp" #include "runtime/globals_extension.hpp" @@ -79,10 +80,6 @@ void ShenandoahHeuristics::choose_collection_set(ShenandoahCollectionSet* collec ShenandoahHeap* heap = ShenandoahHeap::heap(); assert(collection_set->is_empty(), "Must be empty"); - assert(!heap->mode()->is_generational(), "Wrong heuristic for heap mode"); - - // Check all pinned regions have updated status before choosing the collection set. - heap->assert_pinned_region_status(); // Step 1. Build up the region candidates we care about, rejecting losers and accepting winners right away. @@ -103,6 +100,10 @@ void ShenandoahHeuristics::choose_collection_set(ShenandoahCollectionSet* collec for (size_t i = 0; i < num_regions; i++) { ShenandoahHeapRegion* region = heap->get_region(i); + if (!_space_info->contains(region)) { + continue; + } + size_t garbage = region->garbage(); total_garbage += garbage; @@ -117,6 +118,8 @@ void ShenandoahHeuristics::choose_collection_set(ShenandoahCollectionSet* collec region->make_trash_immediate(); } else { // This is our candidate for later consideration. + assert(region->get_top_before_promote() == nullptr, + "Cannot add region %zu scheduled for in-place-promotion to the collection set", i); candidates[cand_idx].set_region_and_garbage(region, garbage); cand_idx++; } @@ -149,6 +152,7 @@ void ShenandoahHeuristics::choose_collection_set(ShenandoahCollectionSet* collec choose_collection_set_from_regiondata(collection_set, candidates, cand_idx, immediate_garbage + free); } collection_set->summarize(total_garbage, immediate_garbage, immediate_regions); + ShenandoahTracer::report_evacuation_info(collection_set, free_regions, immediate_regions, immediate_garbage); } void ShenandoahHeuristics::start_idle_span() { diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahSpaceInfo.hpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahSpaceInfo.hpp index 6ed05abf0b1..765061a43ed 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahSpaceInfo.hpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahSpaceInfo.hpp @@ -27,6 +27,8 @@ #include "utilities/globalDefinitions.hpp" +class ShenandoahHeapRegion; + /* * The purpose of this interface is to decouple the heuristics from a * direct dependency on the ShenandoahHeap singleton instance. This is @@ -46,6 +48,9 @@ public: // in time within each GC cycle. For certain GC cycles, the value returned may include some bytes allocated before // the start of the current GC cycle. virtual size_t bytes_allocated_since_gc_start() const = 0; + + // Return true if this region belongs to this space. + virtual bool contains(ShenandoahHeapRegion* region) const = 0; }; #endif //SHARE_GC_SHENANDOAH_HEURISTICS_SHENANDOAHSPACEINFO_HPP diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahYoungHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahYoungHeuristics.cpp index 68ffb6592db..27aa9a47510 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahYoungHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahYoungHeuristics.cpp @@ -37,9 +37,9 @@ ShenandoahYoungHeuristics::ShenandoahYoungHeuristics(ShenandoahYoungGeneration* } -void ShenandoahYoungHeuristics::choose_collection_set_from_regiondata(ShenandoahCollectionSet* cset, - RegionData* data, size_t size, - size_t actual_free) { +void ShenandoahYoungHeuristics::select_collection_set_regions(ShenandoahCollectionSet* cset, + RegionData* data, size_t size, + size_t actual_free) { // See comments in ShenandoahAdaptiveHeuristics::choose_collection_set_from_regiondata(): // we do the same here, but with the following adjustments for generational mode: // diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahYoungHeuristics.hpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahYoungHeuristics.hpp index 806cef673d5..8fabc40693c 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahYoungHeuristics.hpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahYoungHeuristics.hpp @@ -38,9 +38,9 @@ public: explicit ShenandoahYoungHeuristics(ShenandoahYoungGeneration* generation); - void choose_collection_set_from_regiondata(ShenandoahCollectionSet* cset, - RegionData* data, size_t size, - size_t actual_free) override; + void select_collection_set_regions(ShenandoahCollectionSet* cset, + RegionData* data, size_t size, + size_t actual_free) override; bool should_start_gc() override; diff --git a/src/hotspot/share/gc/shenandoah/mode/shenandoahMode.cpp b/src/hotspot/share/gc/shenandoah/mode/shenandoahMode.cpp index 5ef21719ed4..1c2c15c40dc 100644 --- a/src/hotspot/share/gc/shenandoah/mode/shenandoahMode.cpp +++ b/src/hotspot/share/gc/shenandoah/mode/shenandoahMode.cpp @@ -26,7 +26,6 @@ #include "gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.hpp" #include "gc/shenandoah/heuristics/shenandoahAggressiveHeuristics.hpp" #include "gc/shenandoah/heuristics/shenandoahCompactHeuristics.hpp" -#include "gc/shenandoah/heuristics/shenandoahSpaceInfo.hpp" #include "gc/shenandoah/heuristics/shenandoahStaticHeuristics.hpp" #include "gc/shenandoah/mode/shenandoahMode.hpp" diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp index 3d592e9f9be..7d082e4a8b0 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp @@ -301,6 +301,7 @@ void ShenandoahGeneration::prepare_regions_and_collection_set(bool concurrent) { collection_set->clear(); ShenandoahHeapLocker locker(heap->lock()); + heap->assert_pinned_region_status(this); _heuristics->choose_collection_set(collection_set); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.hpp b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.hpp index 6f32d101152..9f8944127c0 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.hpp @@ -143,7 +143,7 @@ public: virtual bool contains(ShenandoahAffiliation affiliation) const = 0; // Return true if this region is affiliated with this generation. - virtual bool contains(ShenandoahHeapRegion* region) const = 0; + virtual bool contains(ShenandoahHeapRegion* region) const override = 0; // Return true if this object is affiliated with this generation. virtual bool contains(oop obj) const = 0; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.hpp b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.hpp index 630736190f0..0069d38a84e 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.hpp @@ -213,7 +213,12 @@ public: bool is_concurrent_mark_in_progress() override; bool entry_coalesce_and_fill(); + + // Global collections touch old regions, so the old generation needs to be informed of this. + // The old generation may decide to schedule additional mixed collections, or may decide to + // immediately coalesce-and-fill old objects in regions that were not collected. void transition_old_generation_after_global_gc(); + void prepare_gc() override; void prepare_regions_and_collection_set(bool concurrent) override; void record_success_concurrent(bool abbreviated) override; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahTrace.cpp b/src/hotspot/share/gc/shenandoah/shenandoahTrace.cpp index bbb44348355..c28e572dd6b 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahTrace.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahTrace.cpp @@ -27,9 +27,7 @@ #include "jfr/jfrEvents.hpp" void ShenandoahTracer::report_evacuation_info(const ShenandoahCollectionSet* cset, - size_t free_regions, size_t regions_promoted_humongous, size_t regions_promoted_regular, - size_t regular_promoted_garbage, size_t regular_promoted_free, size_t regions_immediate, - size_t immediate_size) { + size_t free_regions, size_t regions_immediate, size_t immediate_size) { EventShenandoahEvacuationInformation e; if (e.should_commit()) { @@ -37,13 +35,6 @@ void ShenandoahTracer::report_evacuation_info(const ShenandoahCollectionSet* cse e.set_cSetRegions(cset->count()); e.set_cSetUsedBefore(cset->used()); e.set_cSetUsedAfter(cset->live()); - e.set_collectedOld(cset->get_live_bytes_in_old_regions()); - e.set_collectedPromoted(cset->get_live_bytes_in_tenurable_regions()); - e.set_collectedYoung(cset->get_live_bytes_in_untenurable_regions()); - e.set_regionsPromotedHumongous(regions_promoted_humongous); - e.set_regionsPromotedRegular(regions_promoted_regular); - e.set_regularPromotedGarbage(regular_promoted_garbage); - e.set_regularPromotedFree(regular_promoted_free); e.set_freeRegions(free_regions); e.set_regionsImmediate(regions_immediate); e.set_immediateBytes(immediate_size); @@ -51,3 +42,24 @@ void ShenandoahTracer::report_evacuation_info(const ShenandoahCollectionSet* cse e.commit(); } } + +void ShenandoahTracer::report_promotion_info(const ShenandoahCollectionSet* cset, + size_t regions_promoted_humongous, size_t humongous_promoted_garbage, size_t humongous_promoted_free, + size_t regions_promoted_regular, size_t regular_promoted_garbage, size_t regular_promoted_free) { + + EventShenandoahPromotionInformation e; + if (e.should_commit()) { + e.set_gcId(GCId::current()); + e.set_collectedOld(cset->get_live_bytes_in_old_regions()); + e.set_collectedPromoted(cset->get_live_bytes_in_tenurable_regions()); + e.set_collectedYoung(cset->get_live_bytes_in_untenurable_regions()); + e.set_regionsPromotedHumongous(regions_promoted_humongous); + e.set_humongousPromotedGarbage(humongous_promoted_garbage); + e.set_humongousPromotedFree(humongous_promoted_free); + e.set_regionsPromotedRegular(regions_promoted_regular); + e.set_regularPromotedGarbage(regular_promoted_garbage); + e.set_regularPromotedFree(regular_promoted_free); + + e.commit(); + } +} diff --git a/src/hotspot/share/gc/shenandoah/shenandoahTrace.hpp b/src/hotspot/share/gc/shenandoah/shenandoahTrace.hpp index 116968103de..e5c80e0705f 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahTrace.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahTrace.hpp @@ -34,11 +34,14 @@ class ShenandoahTracer : public GCTracer, public CHeapObj { public: ShenandoahTracer() : GCTracer(Shenandoah) {} - // Sends a JFR event (if enabled) summarizing the composition of the collection set + // Sends a JFR event summarizing the composition of the collection set static void report_evacuation_info(const ShenandoahCollectionSet* cset, - size_t free_regions, size_t regions_promoted_humongous, size_t regions_promoted_regular, - size_t regular_promoted_garbage, size_t regular_promoted_free, size_t regions_immediate, - size_t immediate_size); + size_t free_regions, size_t regions_immediate, size_t immediate_size); + + // Sends a JFR event summarizing in-place promotion activity (generational mode only) + static void report_promotion_info(const ShenandoahCollectionSet* cset, + size_t regions_promoted_humongous, size_t humongous_promoted_garbage, size_t humongous_promoted_free, + size_t regions_promoted_regular, size_t regular_promoted_garbage, size_t regular_promoted_free); }; #endif diff --git a/src/hotspot/share/jfr/metadata/metadata.xml b/src/hotspot/share/jfr/metadata/metadata.xml index 2b082165005..09d9e0ccabf 100644 --- a/src/hotspot/share/jfr/metadata/metadata.xml +++ b/src/hotspot/share/jfr/metadata/metadata.xml @@ -1273,16 +1273,22 @@ + + + + + + + + + - - - diff --git a/src/jdk.jfr/share/conf/jfr/default.jfc b/src/jdk.jfr/share/conf/jfr/default.jfc index 554e09261d6..d077157d2a1 100644 --- a/src/jdk.jfr/share/conf/jfr/default.jfc +++ b/src/jdk.jfr/share/conf/jfr/default.jfc @@ -576,6 +576,10 @@ false + + false + + true false diff --git a/src/jdk.jfr/share/conf/jfr/profile.jfc b/src/jdk.jfr/share/conf/jfr/profile.jfc index 108886fb18d..126615af14b 100644 --- a/src/jdk.jfr/share/conf/jfr/profile.jfc +++ b/src/jdk.jfr/share/conf/jfr/profile.jfc @@ -576,6 +576,10 @@ false + + false + + true true diff --git a/test/jdk/jdk/jfr/event/gc/detailed/TestShenandoahEvacuationInformationEvent.java b/test/jdk/jdk/jfr/event/gc/detailed/TestShenandoahEvacuationInformationEvent.java index 5730f4d9ff4..888ff9eb17a 100644 --- a/test/jdk/jdk/jfr/event/gc/detailed/TestShenandoahEvacuationInformationEvent.java +++ b/test/jdk/jdk/jfr/event/gc/detailed/TestShenandoahEvacuationInformationEvent.java @@ -68,8 +68,8 @@ public class TestShenandoahEvacuationInformationEvent { long setUsedAfter = Events.assertField(event, "cSetUsedAfter").atLeast(0L).getValue(); long setUsedBefore = Events.assertField(event, "cSetUsedBefore").atLeast(setUsedAfter).getValue(); long freeRegions = Events.assertField(event, "freeRegions").atLeast(0L).getValue(); - Events.assertField(event, "collectedOld").atLeast(0L).getValue(); - Events.assertField(event, "collectedYoung").atLeast(0L).getValue(); + Events.assertField(event, "regionsImmediate").atLeast(0L).getValue(); + Events.assertField(event, "immediateBytes").atLeast(0L).getValue(); Asserts.assertGreaterThanOrEqual(shenandoahMaxHeapRegionCount, freeRegions + cSetRegions, "numRegions >= freeRegions + cSetRegions"); Asserts.assertGreaterThanOrEqual(shenandoahHeapRegionSize * cSetRegions, setUsedAfter, "ShenandoahHeapRegionSize * cSetRegions >= setUsedAfter"); diff --git a/test/jdk/jdk/jfr/event/gc/detailed/TestShenandoahPromotionInformationEvent.java b/test/jdk/jdk/jfr/event/gc/detailed/TestShenandoahPromotionInformationEvent.java new file mode 100644 index 00000000000..08a360e14fd --- /dev/null +++ b/test/jdk/jdk/jfr/event/gc/detailed/TestShenandoahPromotionInformationEvent.java @@ -0,0 +1,100 @@ +/* + * Copyright Amazon.com 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. + * + */ + +package jdk.jfr.event.gc.detailed; + +import java.time.Duration; +import java.util.List; +import java.util.Random; + +import jdk.jfr.Recording; +import jdk.jfr.consumer.RecordedEvent; +import jdk.test.lib.Asserts; +import jdk.test.lib.jfr.EventNames; +import jdk.test.lib.jfr.Events; + +/** + * @test + * @requires vm.hasJFR & vm.gc.Shenandoah + * @requires vm.flagless + * @library /test/lib /test/jdk + * @run main/othervm -Xmx64m -XX:+UnlockExperimentalVMOptions -XX:ShenandoahRegionSize=1m -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational jdk.jfr.event.gc.detailed.TestShenandoahPromotionInformationEvent + */ + +public class TestShenandoahPromotionInformationEvent { + private final static String EVENT_NAME = EventNames.ShenandoahPromotionInformation; + + public static void main(String[] args) throws Exception { + Recording recording = new Recording(); + recording.enable(EVENT_NAME).withThreshold(Duration.ofMillis(0)); + recording.start(); + allocate(); + recording.stop(); + + List events = Events.fromRecording(recording); + Asserts.assertFalse(events.isEmpty(), "No events found"); + for (RecordedEvent event : events) { + if (!Events.isEventType(event, EVENT_NAME)) { + continue; + } + System.out.println("Event: " + event); + + Events.assertField(event, "gcId").getValue(); + Events.assertField(event, "collectedOld").atLeast(0L).getValue(); + Events.assertField(event, "collectedPromoted").atLeast(0L).getValue(); + Events.assertField(event, "collectedYoung").atLeast(0L).getValue(); + Events.assertField(event, "regionsPromotedHumongous").atLeast(0L).getValue(); + Events.assertField(event, "humongousPromotedGarbage").atLeast(0L).getValue(); + Events.assertField(event, "humongousPromotedFree").atLeast(0L).getValue(); + Events.assertField(event, "regionsPromotedRegular").atLeast(0L).getValue(); + Events.assertField(event, "regularPromotedGarbage").atLeast(0L).getValue(); + Events.assertField(event, "regularPromotedFree").atLeast(0L).getValue(); + } + } + + private static void allocate() { + DummyObject[] dummys = new DummyObject[6000]; + + Random r = new Random(0); + long bytesToAllocate = 256 * 1024 * 1024; + int currPos = 0; + while (bytesToAllocate > 0) { + int allocSize = 1000 + (r.nextInt(4000)); + bytesToAllocate -= allocSize; + dummys[currPos] = new DummyObject(allocSize); + currPos = (currPos + r.nextInt(20)) % dummys.length; + } + for (int c = 0; c < dummys.length; c++) { + dummys[c] = null; + } + System.gc(); + } + + public static class DummyObject { + public byte[] payload; + DummyObject(int size) { + payload = new byte[size]; + } + } +} diff --git a/test/lib/jdk/test/lib/jfr/EventNames.java b/test/lib/jdk/test/lib/jfr/EventNames.java index 8b0113f75f4..06ee62a2f7c 100644 --- a/test/lib/jdk/test/lib/jfr/EventNames.java +++ b/test/lib/jdk/test/lib/jfr/EventNames.java @@ -115,6 +115,7 @@ public class EventNames { public static final String ShenandoahHeapRegionInformation = PREFIX + "ShenandoahHeapRegionInformation"; public static final String ShenandoahHeapRegionStateChange = PREFIX + "ShenandoahHeapRegionStateChange"; public static final String ShenandoahEvacuationInformation = PREFIX + "ShenandoahEvacuationInformation"; + public static final String ShenandoahPromotionInformation = PREFIX + "ShenandoahPromotionInformation"; public static final String TenuringDistribution = PREFIX + "TenuringDistribution"; public static final String GarbageCollection = PREFIX + "GarbageCollection"; public static final String ParallelOldGarbageCollection = PREFIX + "ParallelOldGarbageCollection"; From d57bbc026fe140578ee7c317af9738678f4534c6 Mon Sep 17 00:00:00 2001 From: Fei Yang Date: Wed, 15 Apr 2026 00:57:20 +0000 Subject: [PATCH 282/359] 8382087: aarch64: remove unused function declarations in macroAssembler_aarch64.hpp Reviewed-by: mhaessig, ayang, aph --- src/hotspot/cpu/aarch64/assembler_aarch64.hpp | 24 ------------------- .../cpu/aarch64/macroAssembler_aarch64.hpp | 4 ---- 2 files changed, 28 deletions(-) diff --git a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp b/src/hotspot/cpu/aarch64/assembler_aarch64.hpp index ebd8f3a9e03..4c1c8d9bbc8 100644 --- a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/assembler_aarch64.hpp @@ -1000,30 +1000,6 @@ public: f(0b0101010, 31, 25), f(0, 24), sf(offset, 23, 5), f(0, 4), f(cond, 3, 0); } -#define INSN(NAME, cond) \ - void NAME(address dest) { \ - br(cond, dest); \ - } - - INSN(beq, EQ); - INSN(bne, NE); - INSN(bhs, HS); - INSN(bcs, CS); - INSN(blo, LO); - INSN(bcc, CC); - INSN(bmi, MI); - INSN(bpl, PL); - INSN(bvs, VS); - INSN(bvc, VC); - INSN(bhi, HI); - INSN(bls, LS); - INSN(bge, GE); - INSN(blt, LT); - INSN(bgt, GT); - INSN(ble, LE); - INSN(bal, AL); - INSN(bnv, NV); - void br(Condition cc, Label &L); #undef INSN diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp index dfba2dcff46..a6cc862d05c 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp @@ -890,10 +890,6 @@ public: // thread in the default location (rthread) void reset_last_Java_frame(bool clear_fp); - // Stores - void store_check(Register obj); // store check for obj - register is destroyed afterwards - void store_check(Register obj, Address dst); // same as above, dst is exact store location (reg. is destroyed) - void resolve_jobject(Register value, Register tmp1, Register tmp2); void resolve_global_jobject(Register value, Register tmp1, Register tmp2); From 9ebee751e8ffa319c9ac6b8aababd3daa994b805 Mon Sep 17 00:00:00 2001 From: "lingjun.cg" Date: Wed, 15 Apr 2026 02:13:26 +0000 Subject: [PATCH 283/359] 8379981: Virtual thread: crash in stackChunkOopDesc::print_on when thawing frame Reviewed-by: pchilanomate --- src/hotspot/share/runtime/frame.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/runtime/frame.cpp b/src/hotspot/share/runtime/frame.cpp index 8f969600ba8..d691a3c8028 100644 --- a/src/hotspot/share/runtime/frame.cpp +++ b/src/hotspot/share/runtime/frame.cpp @@ -1286,7 +1286,7 @@ public: } bool is_good(oop* p) { - return *p == nullptr || (dbg_is_safe(*p, -1) && dbg_is_safe((*p)->klass(), -1) && oopDesc::is_oop_or_null(*p)); + return *p == nullptr || (dbg_is_safe(*p, -1) && dbg_is_safe((*p)->klass_without_asserts(), -1) && oopDesc::is_oop_or_null(*p)); } void describe(FrameValues& values, int frame_no) { for (int i = 0; i < _oops->length(); i++) { From 20e8ea0e0640bf8b0727cf30ced041a1def9c350 Mon Sep 17 00:00:00 2001 From: Jayathirth D V Date: Wed, 15 Apr 2026 04:22:28 +0000 Subject: [PATCH 284/359] 8382047: Update Libpng to 1.6.57 Reviewed-by: avu, azvegint, prr --- src/java.desktop/share/legal/libpng.md | 3 +- .../native/libsplashscreen/libpng/CHANGES | 11 ++++ .../native/libsplashscreen/libpng/README | 2 +- .../share/native/libsplashscreen/libpng/png.c | 4 +- .../share/native/libsplashscreen/libpng/png.h | 14 ++--- .../native/libsplashscreen/libpng/pngconf.h | 2 +- .../libsplashscreen/libpng/pnglibconf.h | 2 +- .../native/libsplashscreen/libpng/pngrtran.c | 28 +++++----- .../native/libsplashscreen/libpng/pngset.c | 54 +++++++++++++++++-- 9 files changed, 89 insertions(+), 31 deletions(-) diff --git a/src/java.desktop/share/legal/libpng.md b/src/java.desktop/share/legal/libpng.md index 034de22bf25..7783fc7ff03 100644 --- a/src/java.desktop/share/legal/libpng.md +++ b/src/java.desktop/share/legal/libpng.md @@ -1,4 +1,4 @@ -## libpng v1.6.56 +## libpng v1.6.57 ### libpng License
@@ -180,6 +180,7 @@ Authors, for copyright and licensing purposes.
  * Mans Rullgard
  * Matt Sarett
  * Mike Klein
+ * Mohammad Seet
  * Pascal Massimino
  * Paul Schmidt
  * Petr Simecek
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/CHANGES b/src/java.desktop/share/native/libsplashscreen/libpng/CHANGES
index 673d4d50420..ba81df0c0e6 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/CHANGES
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/CHANGES
@@ -6368,6 +6368,17 @@ Version 1.6.56 [March 25, 2026]
     (Contributed by Bob Friesenhahn and Philippe Antoine.)
   Performed various refactorings and cleanups.
 
+Version 1.6.57 [April 8, 2026]
+  Fixed CVE-2026-34757 (medium severity):
+    Use-after-free in `png_set_PLTE`, `png_set_tRNS` and `png_set_hIST`
+    leading to corrupted chunk data and potential heap information disclosure.
+    Also hardened the append-style setters (`png_set_text`, `png_set_sPLT`,
+    `png_set_unknown_chunks`) against a theoretical variant of the same
+    aliasing pattern.
+    (Reported by Iv4n .)
+  Fixed integer overflow in rowbytes computation in read transforms.
+    (Contributed by Mohammad Seet.)
+
 Send comments/corrections/commendations to png-mng-implement at lists.sf.net.
 Subscription is required; visit
 
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/README b/src/java.desktop/share/native/libsplashscreen/libpng/README
index d0b085f7933..179b8dc8cb4 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/README
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/README
@@ -1,4 +1,4 @@
-README for libpng version 1.6.56
+README for libpng version 1.6.57
 ================================
 
 See the note about version numbers near the top of `png.h`.
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/png.c b/src/java.desktop/share/native/libsplashscreen/libpng/png.c
index fd095b515b9..e4e13b0a684 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/png.c
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/png.c
@@ -42,7 +42,7 @@
 #include "pngpriv.h"
 
 /* Generate a compiler error if there is an old png.h in the search path. */
-typedef png_libpng_version_1_6_56 Your_png_h_is_not_version_1_6_56;
+typedef png_libpng_version_1_6_57 Your_png_h_is_not_version_1_6_57;
 
 /* Sanity check the chunks definitions - PNG_KNOWN_CHUNKS from pngpriv.h and the
  * corresponding macro definitions.  This causes a compile time failure if
@@ -849,7 +849,7 @@ png_get_copyright(png_const_structrp png_ptr)
    return PNG_STRING_COPYRIGHT
 #else
    return PNG_STRING_NEWLINE \
-      "libpng version 1.6.56" PNG_STRING_NEWLINE \
+      "libpng version 1.6.57" PNG_STRING_NEWLINE \
       "Copyright (c) 2018-2026 Cosmin Truta" PNG_STRING_NEWLINE \
       "Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson" \
       PNG_STRING_NEWLINE \
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/png.h b/src/java.desktop/share/native/libsplashscreen/libpng/png.h
index 56ec204cd1a..349e7d07383 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/png.h
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/png.h
@@ -29,7 +29,7 @@
  * However, the following notice accompanied the original version of this
  * file and, per its terms, should not be removed:
  *
- * libpng version 1.6.56
+ * libpng version 1.6.57
  *
  * Copyright (c) 2018-2026 Cosmin Truta
  * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
@@ -43,7 +43,7 @@
  *   libpng versions 0.89, June 1996, through 0.96, May 1997: Andreas Dilger
  *   libpng versions 0.97, January 1998, through 1.6.35, July 2018:
  *     Glenn Randers-Pehrson
- *   libpng versions 1.6.36, December 2018, through 1.6.56, March 2026:
+ *   libpng versions 1.6.36, December 2018, through 1.6.57, April 2026:
  *     Cosmin Truta
  *   See also "Contributing Authors", below.
  */
@@ -267,7 +267,7 @@
  *    ...
  *    1.5.30                  15    10530  15.so.15.30[.0]
  *    ...
- *    1.6.56                  16    10656  16.so.16.56[.0]
+ *    1.6.57                  16    10657  16.so.16.57[.0]
  *
  *    Henceforth the source version will match the shared-library major and
  *    minor numbers; the shared-library major version number will be used for
@@ -303,7 +303,7 @@
  */
 
 /* Version information for png.h - this should match the version in png.c */
-#define PNG_LIBPNG_VER_STRING "1.6.56"
+#define PNG_LIBPNG_VER_STRING "1.6.57"
 #define PNG_HEADER_VERSION_STRING " libpng version " PNG_LIBPNG_VER_STRING "\n"
 
 /* The versions of shared library builds should stay in sync, going forward */
@@ -314,7 +314,7 @@
 /* These should match the first 3 components of PNG_LIBPNG_VER_STRING: */
 #define PNG_LIBPNG_VER_MAJOR   1
 #define PNG_LIBPNG_VER_MINOR   6
-#define PNG_LIBPNG_VER_RELEASE 56
+#define PNG_LIBPNG_VER_RELEASE 57
 
 /* This should be zero for a public release, or non-zero for a
  * development version.
@@ -345,7 +345,7 @@
  * From version 1.0.1 it is:
  * XXYYZZ, where XX=major, YY=minor, ZZ=release
  */
-#define PNG_LIBPNG_VER 10656 /* 1.6.56 */
+#define PNG_LIBPNG_VER 10657 /* 1.6.57 */
 
 /* Library configuration: these options cannot be changed after
  * the library has been built.
@@ -455,7 +455,7 @@ extern "C" {
 /* This triggers a compiler error in png.c, if png.c and png.h
  * do not agree upon the version number.
  */
-typedef char *png_libpng_version_1_6_56;
+typedef char *png_libpng_version_1_6_57;
 
 /* Basic control structions.  Read libpng-manual.txt or libpng.3 for more info.
  *
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngconf.h b/src/java.desktop/share/native/libsplashscreen/libpng/pngconf.h
index 5772e6ebb1c..1a5bb7b60f8 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pngconf.h
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngconf.h
@@ -29,7 +29,7 @@
  * However, the following notice accompanied the original version of this
  * file and, per its terms, should not be removed:
  *
- * libpng version 1.6.56
+ * libpng version 1.6.57
  *
  * Copyright (c) 2018-2026 Cosmin Truta
  * Copyright (c) 1998-2002,2004,2006-2016,2018 Glenn Randers-Pehrson
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pnglibconf.h b/src/java.desktop/share/native/libsplashscreen/libpng/pnglibconf.h
index 4a7e51d112d..de63c998927 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pnglibconf.h
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pnglibconf.h
@@ -31,7 +31,7 @@
  * However, the following notice accompanied the original version of this
  * file and, per its terms, should not be removed:
  */
-/* libpng version 1.6.56 */
+/* libpng version 1.6.57 */
 
 /* Copyright (c) 2018-2026 Cosmin Truta */
 /* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson */
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngrtran.c b/src/java.desktop/share/native/libsplashscreen/libpng/pngrtran.c
index f0972ba9bef..838c8460f91 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pngrtran.c
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngrtran.c
@@ -2408,7 +2408,7 @@ png_do_unpack(png_row_infop row_info, png_bytep row)
       }
       row_info->bit_depth = 8;
       row_info->pixel_depth = (png_byte)(8 * row_info->channels);
-      row_info->rowbytes = row_width * row_info->channels;
+      row_info->rowbytes = (size_t)row_width * row_info->channels;
    }
 }
 #endif
@@ -2610,7 +2610,7 @@ png_do_scale_16_to_8(png_row_infop row_info, png_bytep row)
 
       row_info->bit_depth = 8;
       row_info->pixel_depth = (png_byte)(8 * row_info->channels);
-      row_info->rowbytes = row_info->width * row_info->channels;
+      row_info->rowbytes = (size_t)row_info->width * row_info->channels;
    }
 }
 #endif
@@ -2638,7 +2638,7 @@ png_do_chop(png_row_infop row_info, png_bytep row)
 
       row_info->bit_depth = 8;
       row_info->pixel_depth = (png_byte)(8 * row_info->channels);
-      row_info->rowbytes = row_info->width * row_info->channels;
+      row_info->rowbytes = (size_t)row_info->width * row_info->channels;
    }
 }
 #endif
@@ -2874,7 +2874,7 @@ png_do_read_filler(png_row_infop row_info, png_bytep row,
             *(--dp) = lo_filler;
             row_info->channels = 2;
             row_info->pixel_depth = 16;
-            row_info->rowbytes = row_width * 2;
+            row_info->rowbytes = (size_t)row_width * 2;
          }
 
          else
@@ -2889,7 +2889,7 @@ png_do_read_filler(png_row_infop row_info, png_bytep row,
             }
             row_info->channels = 2;
             row_info->pixel_depth = 16;
-            row_info->rowbytes = row_width * 2;
+            row_info->rowbytes = (size_t)row_width * 2;
          }
       }
 
@@ -2912,7 +2912,7 @@ png_do_read_filler(png_row_infop row_info, png_bytep row,
             *(--dp) = hi_filler;
             row_info->channels = 2;
             row_info->pixel_depth = 32;
-            row_info->rowbytes = row_width * 4;
+            row_info->rowbytes = (size_t)row_width * 4;
          }
 
          else
@@ -2929,7 +2929,7 @@ png_do_read_filler(png_row_infop row_info, png_bytep row,
             }
             row_info->channels = 2;
             row_info->pixel_depth = 32;
-            row_info->rowbytes = row_width * 4;
+            row_info->rowbytes = (size_t)row_width * 4;
          }
       }
 #endif
@@ -2953,7 +2953,7 @@ png_do_read_filler(png_row_infop row_info, png_bytep row,
             *(--dp) = lo_filler;
             row_info->channels = 4;
             row_info->pixel_depth = 32;
-            row_info->rowbytes = row_width * 4;
+            row_info->rowbytes = (size_t)row_width * 4;
          }
 
          else
@@ -2970,7 +2970,7 @@ png_do_read_filler(png_row_infop row_info, png_bytep row,
             }
             row_info->channels = 4;
             row_info->pixel_depth = 32;
-            row_info->rowbytes = row_width * 4;
+            row_info->rowbytes = (size_t)row_width * 4;
          }
       }
 
@@ -2997,7 +2997,7 @@ png_do_read_filler(png_row_infop row_info, png_bytep row,
             *(--dp) = hi_filler;
             row_info->channels = 4;
             row_info->pixel_depth = 64;
-            row_info->rowbytes = row_width * 8;
+            row_info->rowbytes = (size_t)row_width * 8;
          }
 
          else
@@ -3019,7 +3019,7 @@ png_do_read_filler(png_row_infop row_info, png_bytep row,
 
             row_info->channels = 4;
             row_info->pixel_depth = 64;
-            row_info->rowbytes = row_width * 8;
+            row_info->rowbytes = (size_t)row_width * 8;
          }
       }
 #endif
@@ -4513,7 +4513,7 @@ png_do_expand_palette(png_structrp png_ptr, png_row_infop row_info,
                }
                row_info->bit_depth = 8;
                row_info->pixel_depth = 32;
-               row_info->rowbytes = row_width * 4;
+               row_info->rowbytes = (size_t)row_width * 4;
                row_info->color_type = 6;
                row_info->channels = 4;
             }
@@ -4521,7 +4521,7 @@ png_do_expand_palette(png_structrp png_ptr, png_row_infop row_info,
             else
             {
                sp = row + (size_t)row_width - 1;
-               dp = row + (size_t)(row_width * 3) - 1;
+               dp = row + (size_t)row_width * 3 - 1;
                i = 0;
 #ifdef PNG_ARM_NEON_INTRINSICS_AVAILABLE
                i = png_do_expand_palette_rgb8_neon(png_ptr, row_info, row,
@@ -4540,7 +4540,7 @@ png_do_expand_palette(png_structrp png_ptr, png_row_infop row_info,
 
                row_info->bit_depth = 8;
                row_info->pixel_depth = 24;
-               row_info->rowbytes = row_width * 3;
+               row_info->rowbytes = (size_t)row_width * 3;
                row_info->color_type = 2;
                row_info->channels = 3;
             }
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngset.c b/src/java.desktop/share/native/libsplashscreen/libpng/pngset.c
index 05d18cd06b7..29082a6be08 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pngset.c
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngset.c
@@ -414,6 +414,7 @@ void PNGAPI
 png_set_hIST(png_const_structrp png_ptr, png_inforp info_ptr,
     png_const_uint_16p hist)
 {
+   png_uint_16 safe_hist[PNG_MAX_PALETTE_LENGTH];
    int i;
 
    png_debug1(1, "in %s storage function", "hIST");
@@ -430,6 +431,13 @@ png_set_hIST(png_const_structrp png_ptr, png_inforp info_ptr,
       return;
    }
 
+   /* Snapshot the caller's hist before freeing, in case it points to
+    * info_ptr->hist (getter-to-setter aliasing).
+    */
+   memcpy(safe_hist, hist, (unsigned int)info_ptr->num_palette *
+       (sizeof (png_uint_16)));
+   hist = safe_hist;
+
    png_free_data(png_ptr, info_ptr, PNG_FREE_HIST, 0);
 
    /* Changed from info->num_palette to PNG_MAX_PALETTE_LENGTH in
@@ -771,7 +779,7 @@ void PNGAPI
 png_set_PLTE(png_structrp png_ptr, png_inforp info_ptr,
     png_const_colorp palette, int num_palette)
 {
-
+   png_color safe_palette[PNG_MAX_PALETTE_LENGTH];
    png_uint_32 max_palette_length;
 
    png_debug1(1, "in %s storage function", "PLTE");
@@ -805,6 +813,15 @@ png_set_PLTE(png_structrp png_ptr, png_inforp info_ptr,
       png_error(png_ptr, "Invalid palette");
    }
 
+   /* Snapshot the caller's palette before freeing, in case it points to
+    * info_ptr->palette (getter-to-setter aliasing).
+    */
+   if (num_palette > 0)
+      memcpy(safe_palette, palette, (unsigned int)num_palette *
+          (sizeof (png_color)));
+
+   palette = safe_palette;
+
    png_free_data(png_ptr, info_ptr, PNG_FREE_PLTE, 0);
 
    /* Changed in libpng-1.2.1 to allocate PNG_MAX_PALETTE_LENGTH instead
@@ -966,6 +983,7 @@ png_set_text_2(png_const_structrp png_ptr, png_inforp info_ptr,
     png_const_textp text_ptr, int num_text)
 {
    int i;
+   png_textp old_text = NULL;
 
    png_debug1(1, "in text storage function, chunk typeid = 0x%lx",
       png_ptr == NULL ? 0xabadca11UL : (unsigned long)png_ptr->chunk_name);
@@ -1013,7 +1031,10 @@ png_set_text_2(png_const_structrp png_ptr, png_inforp info_ptr,
          return 1;
       }
 
-      png_free(png_ptr, info_ptr->text);
+      /* Defer freeing the old array until after the copy loop below,
+       * in case text_ptr aliases info_ptr->text (getter-to-setter).
+       */
+      old_text = info_ptr->text;
 
       info_ptr->text = new_text;
       info_ptr->free_me |= PNG_FREE_TEXT;
@@ -1098,6 +1119,7 @@ png_set_text_2(png_const_structrp png_ptr, png_inforp info_ptr,
       {
          png_chunk_report(png_ptr, "text chunk: out of memory",
              PNG_CHUNK_WRITE_ERROR);
+         png_free(png_ptr, old_text);
 
          return 1;
       }
@@ -1151,6 +1173,8 @@ png_set_text_2(png_const_structrp png_ptr, png_inforp info_ptr,
       png_debug1(3, "transferred text chunk %d", info_ptr->num_text);
    }
 
+   png_free(png_ptr, old_text);
+
    return 0;
 }
 #endif
@@ -1194,6 +1218,16 @@ png_set_tRNS(png_structrp png_ptr, png_inforp info_ptr,
 
    if (trans_alpha != NULL)
    {
+       /* Snapshot the caller's trans_alpha before freeing, in case it
+        * points to info_ptr->trans_alpha (getter-to-setter aliasing).
+        */
+       png_byte safe_trans[PNG_MAX_PALETTE_LENGTH];
+
+       if (num_trans > 0 && num_trans <= PNG_MAX_PALETTE_LENGTH)
+          memcpy(safe_trans, trans_alpha, (size_t)num_trans);
+
+       trans_alpha = safe_trans;
+
        png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, 0);
 
        if (num_trans > 0 && num_trans <= PNG_MAX_PALETTE_LENGTH)
@@ -1278,6 +1312,7 @@ png_set_sPLT(png_const_structrp png_ptr,
  */
 {
    png_sPLT_tp np;
+   png_sPLT_tp old_spalettes;
 
    png_debug1(1, "in %s storage function", "sPLT");
 
@@ -1298,7 +1333,10 @@ png_set_sPLT(png_const_structrp png_ptr,
       return;
    }
 
-   png_free(png_ptr, info_ptr->splt_palettes);
+   /* Defer freeing the old array until after the copy loop below,
+    * in case entries aliases info_ptr->splt_palettes (getter-to-setter).
+    */
+   old_spalettes = info_ptr->splt_palettes;
 
    info_ptr->splt_palettes = np;
    info_ptr->free_me |= PNG_FREE_SPLT;
@@ -1362,6 +1400,8 @@ png_set_sPLT(png_const_structrp png_ptr,
    }
    while (--nentries);
 
+   png_free(png_ptr, old_spalettes);
+
    if (nentries > 0)
       png_chunk_report(png_ptr, "sPLT out of memory", PNG_CHUNK_WRITE_ERROR);
 }
@@ -1410,6 +1450,7 @@ png_set_unknown_chunks(png_const_structrp png_ptr,
     png_inforp info_ptr, png_const_unknown_chunkp unknowns, int num_unknowns)
 {
    png_unknown_chunkp np;
+   png_unknown_chunkp old_unknowns;
 
    if (png_ptr == NULL || info_ptr == NULL || num_unknowns <= 0 ||
        unknowns == NULL)
@@ -1456,7 +1497,10 @@ png_set_unknown_chunks(png_const_structrp png_ptr,
       return;
    }
 
-   png_free(png_ptr, info_ptr->unknown_chunks);
+   /* Defer freeing the old array until after the copy loop below,
+    * in case unknowns aliases info_ptr->unknown_chunks (getter-to-setter).
+    */
+   old_unknowns = info_ptr->unknown_chunks;
 
    info_ptr->unknown_chunks = np; /* safe because it is initialized */
    info_ptr->free_me |= PNG_FREE_UNKN;
@@ -1502,6 +1546,8 @@ png_set_unknown_chunks(png_const_structrp png_ptr,
       ++np;
       ++(info_ptr->unknown_chunks_num);
    }
+
+   png_free(png_ptr, old_unknowns);
 }
 
 void PNGAPI

From 2930e2b5308a5d6dd68253727db51d0ce167ed83 Mon Sep 17 00:00:00 2001
From: Jatin Bhateja 
Date: Wed, 15 Apr 2026 04:31:53 +0000
Subject: [PATCH 285/359] 8372797: [VectorAPI] Missing Min/Max identity
 transforms

Reviewed-by: xgong, vlivanov
---
 src/hotspot/share/opto/vectornode.cpp         |   82 +-
 src/hotspot/share/opto/vectornode.hpp         |   40 +-
 .../compiler/lib/ir_framework/IRNode.java     |   20 +
 .../VectorCommutativeOperSharingTest.java     |    4 +-
 .../vectorapi/VectorMinMaxTransforms.java     | 2036 +++++++++++++++++
 .../VectorUnsignedMinMaxOperationsTest.java   | 1353 ++++++++++-
 6 files changed, 3477 insertions(+), 58 deletions(-)
 create mode 100644 test/hotspot/jtreg/compiler/vectorapi/VectorMinMaxTransforms.java

diff --git a/src/hotspot/share/opto/vectornode.cpp b/src/hotspot/share/opto/vectornode.cpp
index 6012bdef86e..b07f0234492 100644
--- a/src/hotspot/share/opto/vectornode.cpp
+++ b/src/hotspot/share/opto/vectornode.cpp
@@ -2432,67 +2432,68 @@ bool MulVLNode::has_uint_inputs() const {
          has_vector_elements_fit_uint(in(2));
 }
 
-static Node* UMinMaxV_Ideal(Node* n, PhaseGVN* phase, bool can_reshape) {
+static Node* MinMaxV_Common_Ideal(MinMaxVNode* n, PhaseGVN* phase, bool can_reshape) {
   int vopc = n->Opcode();
-  assert(vopc == Op_UMinV || vopc == Op_UMaxV, "Unexpected opcode");
+  int min_opcode = n->min_opcode();
+  int max_opcode = n->max_opcode();
 
-  Node* umin = nullptr;
-  Node* umax = nullptr;
+  Node* min_op = nullptr;
+  Node* max_op = nullptr;
   int lopc = n->in(1)->Opcode();
   int ropc = n->in(2)->Opcode();
 
-  if (lopc == Op_UMinV && ropc == Op_UMaxV) {
-    umin = n->in(1);
-    umax = n->in(2);
-  } else if (lopc == Op_UMaxV && ropc == Op_UMinV) {
-    umin = n->in(2);
-    umax = n->in(1);
+  if (lopc == min_opcode && ropc == max_opcode) {
+    min_op = n->in(1);
+    max_op = n->in(2);
+  } else if (lopc == max_opcode && ropc == min_opcode) {
+    min_op = n->in(2);
+    max_op = n->in(1);
   } else {
     return nullptr;
   }
 
-  // UMin (UMin(a, b), UMax(a, b))  => UMin(a, b)
-  // UMin (UMax(a, b), UMin(b, a))  => UMin(a, b)
-  // UMax (UMin(a, b), UMax(a, b))  => UMax(a, b)
-  // UMax (UMax(a, b), UMin(b, a))  => UMax(a, b)
-  if (umin != nullptr && umax != nullptr) {
-    if ((umin->in(1) == umax->in(1) && umin->in(2) == umax->in(2)) ||
-        (umin->in(2) == umax->in(1) && umin->in(1) == umax->in(2))) {
-      if (vopc == Op_UMinV) {
-        return new UMinVNode(umax->in(1), umax->in(2), n->bottom_type()->is_vect());
-      } else {
-        return new UMaxVNode(umax->in(1), umax->in(2), n->bottom_type()->is_vect());
+  // Min (Min(a, b), Max(a, b))  => Min(a, b)
+  // Min (Max(a, b), Min(b, a))  => Min(a, b)
+  // Max (Min(a, b), Max(a, b))  => Max(a, b)
+  // Max (Max(a, b), Min(b, a))  => Max(a, b)
+
+  if (min_op != nullptr && max_op != nullptr) {
+    // Skip if predication status is inconsistent across n, min_op, and max_op,
+    // or if predicated operands carry different masks.
+    if (n->is_predicated_vector() != min_op->is_predicated_vector() ||
+        min_op->is_predicated_vector() != max_op->is_predicated_vector()) {
+      return nullptr;
+    }
+    if (min_op->is_predicated_vector() &&
+        !(n->in(3) == min_op->in(3) && min_op->in(3) == max_op->in(3))) {
+      return nullptr;
+    }
+
+    if ((min_op->in(1) == max_op->in(1) && min_op->in(2) == max_op->in(2)) ||
+        (min_op->in(2) == max_op->in(1) && min_op->in(1) == max_op->in(2))) {
+      // Use n->in(1) inputs for the result to preserve correct merge-masking
+      // passthrough: inactive lanes use in(1), so result->in(1) must equal
+      // n->in(1)->in(1) to maintain the original passthrough semantics.
+      VectorNode* result = VectorNode::make(vopc, n->in(1)->in(1), n->in(1)->in(2), n->bottom_type()->is_vect());
+      if (n->is_predicated_vector()) {
+        result->add_req(n->in(3));
+        result->add_flag(Node::Flag_is_predicated_vector);
       }
+      return result;
     }
   }
 
   return nullptr;
 }
 
-Node* UMinVNode::Ideal(PhaseGVN* phase, bool can_reshape) {
-  Node* progress = UMinMaxV_Ideal(this, phase, can_reshape);
+Node* MinMaxVNode::Ideal(PhaseGVN* phase, bool can_reshape) {
+  Node* progress = MinMaxV_Common_Ideal(this, phase, can_reshape);
   if (progress != nullptr) return progress;
 
   return VectorNode::Ideal(phase, can_reshape);
 }
 
-Node* UMinVNode::Identity(PhaseGVN* phase) {
-  // UMin (a, a) => a
-  if (in(1) == in(2)) {
-    return in(1);
-  }
-  return this;
-}
-
-Node* UMaxVNode::Ideal(PhaseGVN* phase, bool can_reshape) {
-  Node* progress = UMinMaxV_Ideal(this, phase, can_reshape);
-  if (progress != nullptr) return progress;
-
-  return VectorNode::Ideal(phase, can_reshape);
-}
-
-Node* UMaxVNode::Identity(PhaseGVN* phase) {
-  // UMax (a, a) => a
+Node* MinMaxVNode::Identity(PhaseGVN* phase) {
   if (in(1) == in(2)) {
     return in(1);
   }
@@ -2502,4 +2503,5 @@ Node* UMaxVNode::Identity(PhaseGVN* phase) {
 void VectorBoxAllocateNode::dump_spec(outputStream *st) const {
   CallStaticJavaNode::dump_spec(st);
 }
+
 #endif // !PRODUCT
diff --git a/src/hotspot/share/opto/vectornode.hpp b/src/hotspot/share/opto/vectornode.hpp
index dce43f92905..c4fff06e771 100644
--- a/src/hotspot/share/opto/vectornode.hpp
+++ b/src/hotspot/share/opto/vectornode.hpp
@@ -662,10 +662,22 @@ public:
   virtual int Opcode() const;
 };
 
-// Vector Min
-class MinVNode : public VectorNode {
+// Common superclass for Min/Max vector nodes
+class MinMaxVNode : public VectorNode {
 public:
-  MinVNode(Node* in1, Node* in2, const TypeVect* vt) : VectorNode(in1, in2, vt) {}
+  MinMaxVNode(Node* in1, Node* in2, const TypeVect* vt) : VectorNode(in1, in2, vt) {}
+  virtual int min_opcode() const = 0;
+  virtual int max_opcode() const = 0;
+  virtual Node* Ideal(PhaseGVN* phase, bool can_reshape);
+  virtual Node* Identity(PhaseGVN* phase);
+};
+
+// Vector Min
+class MinVNode : public MinMaxVNode {
+public:
+  MinVNode(Node* in1, Node* in2, const TypeVect* vt) : MinMaxVNode(in1, in2, vt) {}
+  virtual int min_opcode() const { return Op_MinV; }
+  virtual int max_opcode() const { return Op_MaxV; }
   virtual int Opcode() const;
 };
 
@@ -684,31 +696,33 @@ public:
 };
 
 // Vector Unsigned Min
-class UMinVNode : public VectorNode {
+class UMinVNode : public MinMaxVNode {
  public:
-  UMinVNode(Node* in1, Node* in2, const TypeVect* vt) : VectorNode(in1, in2 ,vt) {
+  UMinVNode(Node* in1, Node* in2, const TypeVect* vt) : MinMaxVNode(in1, in2, vt) {
     assert(is_integral_type(vt->element_basic_type()), "");
   }
-  virtual Node* Ideal(PhaseGVN* phase, bool can_reshape);
-  virtual Node* Identity(PhaseGVN* phase);
+  virtual int min_opcode() const { return Op_UMinV; }
+  virtual int max_opcode() const { return Op_UMaxV; }
   virtual int Opcode() const;
 };
 
 // Vector Max
-class MaxVNode : public VectorNode {
+class MaxVNode : public MinMaxVNode {
  public:
-  MaxVNode(Node* in1, Node* in2, const TypeVect* vt) : VectorNode(in1, in2, vt) {}
+  MaxVNode(Node* in1, Node* in2, const TypeVect* vt) : MinMaxVNode(in1, in2, vt) {}
+  virtual int min_opcode() const { return Op_MinV; }
+  virtual int max_opcode() const { return Op_MaxV; }
   virtual int Opcode() const;
 };
 
 // Vector Unsigned Max
-class UMaxVNode : public VectorNode {
+class UMaxVNode : public MinMaxVNode {
  public:
-  UMaxVNode(Node* in1, Node* in2, const TypeVect* vt) : VectorNode(in1, in2, vt) {
+  UMaxVNode(Node* in1, Node* in2, const TypeVect* vt) : MinMaxVNode(in1, in2, vt) {
     assert(is_integral_type(vt->element_basic_type()), "");
   }
-  virtual Node* Ideal(PhaseGVN* phase, bool can_reshape);
-  virtual Node* Identity(PhaseGVN* phase);
+  virtual int min_opcode() const { return Op_UMinV; }
+  virtual int max_opcode() const { return Op_UMaxV; }
   virtual int Opcode() const;
 };
 
diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java
index 3f742a0ce62..f3fc4afb170 100644
--- a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java
+++ b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java
@@ -1223,6 +1223,16 @@ public class IRNode {
         vectorNode(MAX_VI, "MaxV", TYPE_INT);
     }
 
+    public static final String MAX_VB = VECTOR_PREFIX + "MAX_VB" + POSTFIX;
+    static {
+        vectorNode(MAX_VB, "MaxV", TYPE_BYTE);
+    }
+
+    public static final String MAX_VS = VECTOR_PREFIX + "MAX_VS" + POSTFIX;
+    static {
+        vectorNode(MAX_VS, "MaxV", TYPE_SHORT);
+    }
+
     public static final String MAX_VHF = VECTOR_PREFIX + "MAX_VHF" + POSTFIX;
     static {
         vectorNode(MAX_VHF, "MaxVHF", TYPE_SHORT);
@@ -1339,6 +1349,16 @@ public class IRNode {
         vectorNode(MIN_VI, "MinV", TYPE_INT);
     }
 
+    public static final String MIN_VB = VECTOR_PREFIX + "MIN_VB" + POSTFIX;
+    static {
+        vectorNode(MIN_VB, "MinV", TYPE_BYTE);
+    }
+
+    public static final String MIN_VS = VECTOR_PREFIX + "MIN_VS" + POSTFIX;
+    static {
+        vectorNode(MIN_VS, "MinV", TYPE_SHORT);
+    }
+
     public static final String MIN_VHF = VECTOR_PREFIX + "MIN_VHF" + POSTFIX;
     static {
         vectorNode(MIN_VHF, "MinVHF", TYPE_SHORT);
diff --git a/test/hotspot/jtreg/compiler/vectorapi/VectorCommutativeOperSharingTest.java b/test/hotspot/jtreg/compiler/vectorapi/VectorCommutativeOperSharingTest.java
index a51946dd698..2b43cf26421 100644
--- a/test/hotspot/jtreg/compiler/vectorapi/VectorCommutativeOperSharingTest.java
+++ b/test/hotspot/jtreg/compiler/vectorapi/VectorCommutativeOperSharingTest.java
@@ -74,8 +74,8 @@ public class VectorCommutativeOperSharingTest {
     @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 "},
+                  IRNode.MAX_VI, IRNode.VECTOR_SIZE_ANY, " 1 ",
+                  IRNode.MIN_VI, IRNode.VECTOR_SIZE_ANY, " 1 "},
         applyIfCPUFeatureOr = {"avx", "true", "rvv", "true"})
     public void testVectorIRSharing1(int index) {
         IntVector vec1 = IntVector.fromArray(I_SPECIES, ia, index);
diff --git a/test/hotspot/jtreg/compiler/vectorapi/VectorMinMaxTransforms.java b/test/hotspot/jtreg/compiler/vectorapi/VectorMinMaxTransforms.java
new file mode 100644
index 00000000000..acffe4d3257
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/vectorapi/VectorMinMaxTransforms.java
@@ -0,0 +1,2036 @@
+/*
+ * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this work; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please 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.generators.Generator;
+import compiler.lib.generators.Generators;
+import compiler.lib.ir_framework.*;
+import compiler.lib.verify.*;
+import jdk.incubator.vector.*;
+
+/**
+ * @test
+ * @bug 8372797
+ * @key randomness
+ * @library /test/lib /
+ * @summary IR verification for MinV/MaxV Identity and Ideal transforms
+ * @modules jdk.incubator.vector
+ *
+ * @run driver ${test.main.class}
+ */
+public class VectorMinMaxTransforms {
+    private static final int LENGTH = 256;
+    private static final Generators RD = Generators.G;
+
+    private static final VectorSpecies I_SPECIES = IntVector.SPECIES_PREFERRED;
+    private static int[] ia, ib, ir;
+
+    private static final VectorSpecies L_SPECIES = LongVector.SPECIES_PREFERRED;
+    private static long[] la, lb, lr;
+
+    private static final VectorSpecies F_SPECIES = FloatVector.SPECIES_PREFERRED;
+    private static float[] fa, fb, fr;
+
+    private static final VectorSpecies D_SPECIES = DoubleVector.SPECIES_PREFERRED;
+    private static double[] da, db, dr;
+
+    private static final VectorSpecies B_SPECIES = ByteVector.SPECIES_PREFERRED;
+    private static byte[] ba, bb, br;
+
+    private static final VectorSpecies S_SPECIES = ShortVector.SPECIES_PREFERRED;
+    private static short[] sa, sb, sr;
+
+    private static boolean[] m1arr, m2arr, m3arr;
+
+    static {
+        ia = new int[LENGTH];
+        ib = new int[LENGTH];
+        ir = new int[LENGTH];
+        la = new long[LENGTH];
+        lb = new long[LENGTH];
+        lr = new long[LENGTH];
+        fa = new float[LENGTH];
+        fb = new float[LENGTH];
+        fr = new float[LENGTH];
+        da = new double[LENGTH];
+        db = new double[LENGTH];
+        dr = new double[LENGTH];
+        ba = new byte[LENGTH];
+        bb = new byte[LENGTH];
+        br = new byte[LENGTH];
+        sa = new short[LENGTH];
+        sb = new short[LENGTH];
+        sr = new short[LENGTH];
+        m1arr = new boolean[LENGTH];
+        m2arr = new boolean[LENGTH];
+        m3arr = new boolean[LENGTH];
+
+        Generator iGen = RD.ints();
+        Generator lGen = RD.longs();
+        Generator fGen = RD.floats();
+        Generator dGen = RD.doubles();
+
+        RD.fill(iGen, ia);
+        RD.fill(iGen, ib);
+        RD.fill(lGen, la);
+        RD.fill(lGen, lb);
+        RD.fill(fGen, fa);
+        RD.fill(fGen, fb);
+        RD.fill(dGen, da);
+        RD.fill(dGen, db);
+
+        for (int i = 0; i < LENGTH; i++) {
+            ba[i] = iGen.next().byteValue();
+            bb[i] = iGen.next().byteValue();
+            sa[i] = iGen.next().shortValue();
+            sb[i] = iGen.next().shortValue();
+            m1arr[i] = (i % 2) == 0;
+            m2arr[i] = (i % 2) != 0;
+            m3arr[i] = (i % 3) == 0;
+        }
+    }
+
+    public static void main(String[] args) {
+        TestFramework testFramework = new TestFramework();
+        testFramework.setDefaultWarmup(10000)
+                     .addFlags("--add-modules=jdk.incubator.vector")
+                     .start();
+    }
+
+    // ---------- Int: Identity min(a,a)=>a ----------
+    @Test
+    @IR(counts = { IRNode.MIN_VI, IRNode.VECTOR_SIZE_ANY, " 0 " },
+        applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"})
+    public void testIntMinIdentity(int index) {
+        IntVector v = IntVector.fromArray(I_SPECIES, ia, index);
+        v.lanewise(VectorOperators.MIN, v).intoArray(ir, index);
+    }
+
+    @Run(test = "testIntMinIdentity")
+    public void runIntMinIdentity() {
+        for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i += I_SPECIES.length()) {
+            testIntMinIdentity(i);
+        }
+        for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i++) {
+            int expected = Math.min(ia[i], ia[i]);
+            Verify.checkEQ(ir[i], expected);
+        }
+    }
+
+    // ---------- Int: Identity max(a,a)=>a ----------
+    @Test
+    @IR(counts = { IRNode.MAX_VI, IRNode.VECTOR_SIZE_ANY, " 0 " },
+        applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"})
+    public void testIntMaxIdentity(int index) {
+        IntVector v = IntVector.fromArray(I_SPECIES, ia, index);
+        v.lanewise(VectorOperators.MAX, v).intoArray(ir, index);
+    }
+
+    @Run(test = "testIntMaxIdentity")
+    public void runIntMaxIdentity() {
+        for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i += I_SPECIES.length()) {
+            testIntMaxIdentity(i);
+        }
+        for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i++) {
+            int expected = Math.max(ia[i], ia[i]);
+            Verify.checkEQ(ir[i], expected);
+        }
+    }
+
+    // ---------- Int: Ideal min(min(a,b), max(a,b)) => min(a,b) ----------
+    @Test
+    @IR(counts = { IRNode.MIN_VI, IRNode.VECTOR_SIZE_ANY, " 1 ",
+                   IRNode.MAX_VI, IRNode.VECTOR_SIZE_ANY, " 0 " },
+        applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"})
+    public void testIntMinIdeal(int index) {
+        IntVector v1 = IntVector.fromArray(I_SPECIES, ia, index);
+        IntVector v2 = IntVector.fromArray(I_SPECIES, ib, index);
+        v1.lanewise(VectorOperators.MIN, v2)
+          .lanewise(VectorOperators.MIN, v1.lanewise(VectorOperators.MAX, v2))
+          .intoArray(ir, index);
+    }
+
+    @Run(test = "testIntMinIdeal")
+    public void runIntMinIdeal() {
+        for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i += I_SPECIES.length()) {
+            testIntMinIdeal(i);
+        }
+        for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i++) {
+            int expected = Math.min(Math.min(ia[i], ib[i]), Math.max(ia[i], ib[i]));
+            Verify.checkEQ(ir[i], expected);
+        }
+    }
+
+    // ---------- Int: Ideal max(min(a,b), max(a,b)) => max(a,b) ----------
+    @Test
+    @IR(counts = { IRNode.MIN_VI, IRNode.VECTOR_SIZE_ANY, " 0 ",
+                   IRNode.MAX_VI, IRNode.VECTOR_SIZE_ANY, " 1 " },
+        applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"})
+    public void testIntMaxIdeal(int index) {
+        IntVector v1 = IntVector.fromArray(I_SPECIES, ia, index);
+        IntVector v2 = IntVector.fromArray(I_SPECIES, ib, index);
+        v1.lanewise(VectorOperators.MIN, v2)
+          .lanewise(VectorOperators.MAX, v1.lanewise(VectorOperators.MAX, v2))
+          .intoArray(ir, index);
+    }
+
+    @Run(test = "testIntMaxIdeal")
+    public void runIntMaxIdeal() {
+        for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i += I_SPECIES.length()) {
+            testIntMaxIdeal(i);
+        }
+        for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i++) {
+            int expected = Math.max(Math.min(ia[i], ib[i]), Math.max(ia[i], ib[i]));
+            Verify.checkEQ(ir[i], expected);
+        }
+    }
+
+    // ---------- Long: Identity and Ideal ----------
+    @Test
+    @IR(counts = { IRNode.MIN_VL, IRNode.VECTOR_SIZE_ANY, " 0 " },
+        applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true", "rvv", "true"})
+    public void testLongMinIdentity(int index) {
+        LongVector v = LongVector.fromArray(L_SPECIES, la, index);
+        v.lanewise(VectorOperators.MIN, v).intoArray(lr, index);
+    }
+
+    @Run(test = "testLongMinIdentity")
+    public void runLongMinIdentity() {
+        for (int i = 0; i < L_SPECIES.loopBound(LENGTH); i += L_SPECIES.length()) {
+            testLongMinIdentity(i);
+        }
+        for (int i = 0; i < L_SPECIES.loopBound(LENGTH); i++) {
+            Verify.checkEQ(lr[i], la[i]);
+        }
+    }
+
+    // ---------- Long: Identity max(a,a)=>a ----------
+    @Test
+    @IR(counts = { IRNode.MAX_VL, IRNode.VECTOR_SIZE_ANY, " 0 " },
+        applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true", "rvv", "true"})
+    public void testLongMaxIdentity(int index) {
+        LongVector v = LongVector.fromArray(L_SPECIES, la, index);
+        v.lanewise(VectorOperators.MAX, v).intoArray(lr, index);
+    }
+
+    @Run(test = "testLongMaxIdentity")
+    public void runLongMaxIdentity() {
+        for (int i = 0; i < L_SPECIES.loopBound(LENGTH); i += L_SPECIES.length()) {
+            testLongMaxIdentity(i);
+        }
+        for (int i = 0; i < L_SPECIES.loopBound(LENGTH); i++) {
+            Verify.checkEQ(lr[i], la[i]);
+        }
+    }
+
+    // ---------- Long: Ideal min(min(a,b), max(a,b)) => min(a,b) ----------
+    @Test
+    @IR(counts = { IRNode.MIN_VL, IRNode.VECTOR_SIZE_ANY, " 1 ",
+                   IRNode.MAX_VL, IRNode.VECTOR_SIZE_ANY, " 0 " },
+        applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true", "rvv", "true"})
+    public void testLongMinIdeal(int index) {
+        LongVector v1 = LongVector.fromArray(L_SPECIES, la, index);
+        LongVector v2 = LongVector.fromArray(L_SPECIES, lb, index);
+        v1.lanewise(VectorOperators.MIN, v2)
+          .lanewise(VectorOperators.MIN, v1.lanewise(VectorOperators.MAX, v2))
+          .intoArray(lr, index);
+    }
+
+    @Run(test = "testLongMinIdeal")
+    public void runLongMinIdeal() {
+        for (int i = 0; i < L_SPECIES.loopBound(LENGTH); i += L_SPECIES.length()) {
+            testLongMinIdeal(i);
+        }
+        for (int i = 0; i < L_SPECIES.loopBound(LENGTH); i++) {
+            long expected = Math.min(Math.min(la[i], lb[i]), Math.max(la[i], lb[i]));
+            Verify.checkEQ(lr[i], expected);
+        }
+    }
+
+    // ---------- Long: Ideal max(min(a,b), max(a,b)) => max(a,b) ----------
+    @Test
+    @IR(counts = { IRNode.MIN_VL, IRNode.VECTOR_SIZE_ANY, " 0 ",
+                   IRNode.MAX_VL, IRNode.VECTOR_SIZE_ANY, " 1 " },
+        applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true", "rvv", "true"})
+    public void testLongMaxIdeal(int index) {
+        LongVector v1 = LongVector.fromArray(L_SPECIES, la, index);
+        LongVector v2 = LongVector.fromArray(L_SPECIES, lb, index);
+        v1.lanewise(VectorOperators.MIN, v2)
+          .lanewise(VectorOperators.MAX, v1.lanewise(VectorOperators.MAX, v2))
+          .intoArray(lr, index);
+    }
+
+    @Run(test = "testLongMaxIdeal")
+    public void runLongMaxIdeal() {
+        for (int i = 0; i < L_SPECIES.loopBound(LENGTH); i += L_SPECIES.length()) {
+            testLongMaxIdeal(i);
+        }
+        for (int i = 0; i < L_SPECIES.loopBound(LENGTH); i++) {
+            long expected = Math.max(Math.min(la[i], lb[i]), Math.max(la[i], lb[i]));
+            Verify.checkEQ(lr[i], expected);
+        }
+    }
+
+    // ---------- Float: Identity min(a,a)=>a ----------
+    @Test
+    @IR(counts = { IRNode.MIN_VF, IRNode.VECTOR_SIZE_ANY, " 0 " },
+        applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"})
+    public void testFloatMinIdentity(int index) {
+        FloatVector v = FloatVector.fromArray(F_SPECIES, fa, index);
+        v.lanewise(VectorOperators.MIN, v).intoArray(fr, index);
+    }
+
+    @Run(test = "testFloatMinIdentity")
+    public void runFloatMinIdentity() {
+        for (int i = 0; i < F_SPECIES.loopBound(LENGTH); i += F_SPECIES.length()) {
+            testFloatMinIdentity(i);
+        }
+        for (int i = 0; i < F_SPECIES.loopBound(LENGTH); i++) {
+            Verify.checkEQ(fr[i], fa[i]);
+        }
+    }
+
+    // ---------- Float: Identity max(a,a)=>a ----------
+    @Test
+    @IR(counts = { IRNode.MAX_VF, IRNode.VECTOR_SIZE_ANY, " 0 " },
+        applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"})
+    public void testFloatMaxIdentity(int index) {
+        FloatVector v = FloatVector.fromArray(F_SPECIES, fa, index);
+        v.lanewise(VectorOperators.MAX, v).intoArray(fr, index);
+    }
+
+    @Run(test = "testFloatMaxIdentity")
+    public void runFloatMaxIdentity() {
+        for (int i = 0; i < F_SPECIES.loopBound(LENGTH); i += F_SPECIES.length()) {
+            testFloatMaxIdentity(i);
+        }
+        for (int i = 0; i < F_SPECIES.loopBound(LENGTH); i++) {
+            Verify.checkEQ(fr[i], fa[i]);
+        }
+    }
+
+    // ---------- Float: Ideal min(min(a,b), max(a,b)) => min(a,b) ----------
+    @Test
+    @IR(counts = { IRNode.MIN_VF, IRNode.VECTOR_SIZE_ANY, " 1 ",
+                   IRNode.MAX_VF, IRNode.VECTOR_SIZE_ANY, " 0 " },
+        applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"})
+    public void testFloatMinIdeal(int index) {
+        FloatVector v1 = FloatVector.fromArray(F_SPECIES, fa, index);
+        FloatVector v2 = FloatVector.fromArray(F_SPECIES, fb, index);
+        v1.lanewise(VectorOperators.MIN, v2)
+          .lanewise(VectorOperators.MIN, v1.lanewise(VectorOperators.MAX, v2))
+          .intoArray(fr, index);
+    }
+
+    @Run(test = "testFloatMinIdeal")
+    public void runFloatMinIdeal() {
+        for (int i = 0; i < F_SPECIES.loopBound(LENGTH); i += F_SPECIES.length()) {
+            testFloatMinIdeal(i);
+        }
+        for (int i = 0; i < F_SPECIES.loopBound(LENGTH); i++) {
+            float expected = Math.min(Math.min(fa[i], fb[i]), Math.max(fa[i], fb[i]));
+            Verify.checkEQ(fr[i], expected);
+        }
+    }
+
+    // ---------- Float: Ideal max(min(a,b), max(a,b)) => max(a,b) ----------
+    @Test
+    @IR(counts = { IRNode.MIN_VF, IRNode.VECTOR_SIZE_ANY, " 0 ",
+                   IRNode.MAX_VF, IRNode.VECTOR_SIZE_ANY, " 1 " },
+        applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"})
+    public void testFloatMaxIdeal(int index) {
+        FloatVector v1 = FloatVector.fromArray(F_SPECIES, fa, index);
+        FloatVector v2 = FloatVector.fromArray(F_SPECIES, fb, index);
+        v1.lanewise(VectorOperators.MIN, v2)
+          .lanewise(VectorOperators.MAX, v1.lanewise(VectorOperators.MAX, v2))
+          .intoArray(fr, index);
+    }
+
+    @Run(test = "testFloatMaxIdeal")
+    public void runFloatMaxIdeal() {
+        for (int i = 0; i < F_SPECIES.loopBound(LENGTH); i += F_SPECIES.length()) {
+            testFloatMaxIdeal(i);
+        }
+        for (int i = 0; i < F_SPECIES.loopBound(LENGTH); i++) {
+            float expected = Math.max(Math.min(fa[i], fb[i]), Math.max(fa[i], fb[i]));
+            Verify.checkEQ(fr[i], expected);
+        }
+    }
+
+    // ---------- Double: Identity min(a,a)=>a ----------
+    @Test
+    @IR(counts = { IRNode.MIN_VD, IRNode.VECTOR_SIZE_ANY, " 0 " },
+        applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"})
+    public void testDoubleMinIdentity(int index) {
+        DoubleVector v = DoubleVector.fromArray(D_SPECIES, da, index);
+        v.lanewise(VectorOperators.MIN, v).intoArray(dr, index);
+    }
+
+    @Run(test = "testDoubleMinIdentity")
+    public void runDoubleMinIdentity() {
+        for (int i = 0; i < D_SPECIES.loopBound(LENGTH); i += D_SPECIES.length()) {
+            testDoubleMinIdentity(i);
+        }
+        for (int i = 0; i < D_SPECIES.loopBound(LENGTH); i++) {
+            Verify.checkEQ(dr[i], da[i]);
+        }
+    }
+
+    // ---------- Double: Identity max(a,a)=>a ----------
+    @Test
+    @IR(counts = { IRNode.MAX_VD, IRNode.VECTOR_SIZE_ANY, " 0 " },
+        applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"})
+    public void testDoubleMaxIdentity(int index) {
+        DoubleVector v = DoubleVector.fromArray(D_SPECIES, da, index);
+        v.lanewise(VectorOperators.MAX, v).intoArray(dr, index);
+    }
+
+    @Run(test = "testDoubleMaxIdentity")
+    public void runDoubleMaxIdentity() {
+        for (int i = 0; i < D_SPECIES.loopBound(LENGTH); i += D_SPECIES.length()) {
+            testDoubleMaxIdentity(i);
+        }
+        for (int i = 0; i < D_SPECIES.loopBound(LENGTH); i++) {
+            Verify.checkEQ(dr[i], da[i]);
+        }
+    }
+
+    // ---------- Double: Ideal min(min(a,b), max(a,b)) => min(a,b) ----------
+    @Test
+    @IR(counts = { IRNode.MIN_VD, IRNode.VECTOR_SIZE_ANY, " 1 ",
+                   IRNode.MAX_VD, IRNode.VECTOR_SIZE_ANY, " 0 " },
+        applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"})
+    public void testDoubleMinIdeal(int index) {
+        DoubleVector v1 = DoubleVector.fromArray(D_SPECIES, da, index);
+        DoubleVector v2 = DoubleVector.fromArray(D_SPECIES, db, index);
+        v1.lanewise(VectorOperators.MIN, v2)
+          .lanewise(VectorOperators.MIN, v1.lanewise(VectorOperators.MAX, v2))
+          .intoArray(dr, index);
+    }
+
+    @Run(test = "testDoubleMinIdeal")
+    public void runDoubleMinIdeal() {
+        for (int i = 0; i < D_SPECIES.loopBound(LENGTH); i += D_SPECIES.length()) {
+            testDoubleMinIdeal(i);
+        }
+        for (int i = 0; i < D_SPECIES.loopBound(LENGTH); i++) {
+            double expected = Math.min(Math.min(da[i], db[i]), Math.max(da[i], db[i]));
+            Verify.checkEQ(dr[i], expected);
+        }
+    }
+
+    // ---------- Double: Ideal max(min(a,b), max(a,b)) => max(a,b) ----------
+    @Test
+    @IR(counts = { IRNode.MIN_VD, IRNode.VECTOR_SIZE_ANY, " 0 ",
+                   IRNode.MAX_VD, IRNode.VECTOR_SIZE_ANY, " 1 " },
+        applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"})
+    public void testDoubleMaxIdeal(int index) {
+        DoubleVector v1 = DoubleVector.fromArray(D_SPECIES, da, index);
+        DoubleVector v2 = DoubleVector.fromArray(D_SPECIES, db, index);
+        v1.lanewise(VectorOperators.MIN, v2)
+          .lanewise(VectorOperators.MAX, v1.lanewise(VectorOperators.MAX, v2))
+          .intoArray(dr, index);
+    }
+
+    @Run(test = "testDoubleMaxIdeal")
+    public void runDoubleMaxIdeal() {
+        for (int i = 0; i < D_SPECIES.loopBound(LENGTH); i += D_SPECIES.length()) {
+            testDoubleMaxIdeal(i);
+        }
+        for (int i = 0; i < D_SPECIES.loopBound(LENGTH); i++) {
+            double expected = Math.max(Math.min(da[i], db[i]), Math.max(da[i], db[i]));
+            Verify.checkEQ(dr[i], expected);
+        }
+    }
+
+    // ---------- Byte: Identity min(a,a)=>a ----------
+    @Test
+    @IR(counts = { IRNode.MIN_VB, IRNode.VECTOR_SIZE_ANY, " 0 " },
+        applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"})
+    public void testByteMinIdentity(int index) {
+        ByteVector v = ByteVector.fromArray(B_SPECIES, ba, index);
+        v.lanewise(VectorOperators.MIN, v).intoArray(br, index);
+    }
+
+    @Run(test = "testByteMinIdentity")
+    public void runByteMinIdentity() {
+        for (int i = 0; i < B_SPECIES.loopBound(LENGTH); i += B_SPECIES.length()) {
+            testByteMinIdentity(i);
+        }
+        for (int i = 0; i < B_SPECIES.loopBound(LENGTH); i++) {
+            Verify.checkEQ(br[i], ba[i]);
+        }
+    }
+
+    // ---------- Byte: Identity max(a,a)=>a ----------
+    @Test
+    @IR(counts = { IRNode.MAX_VB, IRNode.VECTOR_SIZE_ANY, " 0 " },
+        applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"})
+    public void testByteMaxIdentity(int index) {
+        ByteVector v = ByteVector.fromArray(B_SPECIES, ba, index);
+        v.lanewise(VectorOperators.MAX, v).intoArray(br, index);
+    }
+
+    @Run(test = "testByteMaxIdentity")
+    public void runByteMaxIdentity() {
+        for (int i = 0; i < B_SPECIES.loopBound(LENGTH); i += B_SPECIES.length()) {
+            testByteMaxIdentity(i);
+        }
+        for (int i = 0; i < B_SPECIES.loopBound(LENGTH); i++) {
+            Verify.checkEQ(br[i], ba[i]);
+        }
+    }
+
+    // ---------- Byte: Ideal min(min(a,b), max(a,b)) => min(a,b) ----------
+    @Test
+    @IR(counts = { IRNode.MIN_VB, IRNode.VECTOR_SIZE_ANY, " 1 ",
+                   IRNode.MAX_VB, IRNode.VECTOR_SIZE_ANY, " 0 " },
+        applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"})
+    public void testByteMinIdeal(int index) {
+        ByteVector v1 = ByteVector.fromArray(B_SPECIES, ba, index);
+        ByteVector v2 = ByteVector.fromArray(B_SPECIES, bb, index);
+        v1.lanewise(VectorOperators.MIN, v2)
+          .lanewise(VectorOperators.MIN, v1.lanewise(VectorOperators.MAX, v2))
+          .intoArray(br, index);
+    }
+
+    @Run(test = "testByteMinIdeal")
+    public void runByteMinIdeal() {
+        for (int i = 0; i < B_SPECIES.loopBound(LENGTH); i += B_SPECIES.length()) {
+            testByteMinIdeal(i);
+        }
+        for (int i = 0; i < B_SPECIES.loopBound(LENGTH); i++) {
+            byte expected = (byte) Math.min(Math.min(ba[i], bb[i]), Math.max(ba[i], bb[i]));
+            Verify.checkEQ(br[i], expected);
+        }
+    }
+
+    // ---------- Byte: Ideal max(min(a,b), max(a,b)) => max(a,b) ----------
+    @Test
+    @IR(counts = { IRNode.MIN_VB, IRNode.VECTOR_SIZE_ANY, " 0 ",
+                   IRNode.MAX_VB, IRNode.VECTOR_SIZE_ANY, " 1 " },
+        applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"})
+    public void testByteMaxIdeal(int index) {
+        ByteVector v1 = ByteVector.fromArray(B_SPECIES, ba, index);
+        ByteVector v2 = ByteVector.fromArray(B_SPECIES, bb, index);
+        v1.lanewise(VectorOperators.MIN, v2)
+          .lanewise(VectorOperators.MAX, v1.lanewise(VectorOperators.MAX, v2))
+          .intoArray(br, index);
+    }
+
+    @Run(test = "testByteMaxIdeal")
+    public void runByteMaxIdeal() {
+        for (int i = 0; i < B_SPECIES.loopBound(LENGTH); i += B_SPECIES.length()) {
+            testByteMaxIdeal(i);
+        }
+        for (int i = 0; i < B_SPECIES.loopBound(LENGTH); i++) {
+            byte expected = (byte) Math.max(Math.min(ba[i], bb[i]), Math.max(ba[i], bb[i]));
+            Verify.checkEQ(br[i], expected);
+        }
+    }
+
+    // ---------- Short: Identity min(a,a)=>a ----------
+    @Test
+    @IR(counts = { IRNode.MIN_VS, IRNode.VECTOR_SIZE_ANY, " 0 " },
+        applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"})
+    public void testShortMinIdentity(int index) {
+        ShortVector v = ShortVector.fromArray(S_SPECIES, sa, index);
+        v.lanewise(VectorOperators.MIN, v).intoArray(sr, index);
+    }
+
+    @Run(test = "testShortMinIdentity")
+    public void runShortMinIdentity() {
+        for (int i = 0; i < S_SPECIES.loopBound(LENGTH); i += S_SPECIES.length()) {
+            testShortMinIdentity(i);
+        }
+        for (int i = 0; i < S_SPECIES.loopBound(LENGTH); i++) {
+            Verify.checkEQ(sr[i], sa[i]);
+        }
+    }
+
+    // ---------- Short: Identity max(a,a)=>a ----------
+    @Test
+    @IR(counts = { IRNode.MAX_VS, IRNode.VECTOR_SIZE_ANY, " 0 " },
+        applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"})
+    public void testShortMaxIdentity(int index) {
+        ShortVector v = ShortVector.fromArray(S_SPECIES, sa, index);
+        v.lanewise(VectorOperators.MAX, v).intoArray(sr, index);
+    }
+
+    @Run(test = "testShortMaxIdentity")
+    public void runShortMaxIdentity() {
+        for (int i = 0; i < S_SPECIES.loopBound(LENGTH); i += S_SPECIES.length()) {
+            testShortMaxIdentity(i);
+        }
+        for (int i = 0; i < S_SPECIES.loopBound(LENGTH); i++) {
+            Verify.checkEQ(sr[i], sa[i]);
+        }
+    }
+
+    // ---------- Short: Ideal min(min(a,b), max(a,b)) => min(a,b) ----------
+    @Test
+    @IR(counts = { IRNode.MIN_VS, IRNode.VECTOR_SIZE_ANY, " 1 ",
+                   IRNode.MAX_VS, IRNode.VECTOR_SIZE_ANY, " 0 " },
+        applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"})
+    public void testShortMinIdeal(int index) {
+        ShortVector v1 = ShortVector.fromArray(S_SPECIES, sa, index);
+        ShortVector v2 = ShortVector.fromArray(S_SPECIES, sb, index);
+        v1.lanewise(VectorOperators.MIN, v2)
+          .lanewise(VectorOperators.MIN, v1.lanewise(VectorOperators.MAX, v2))
+          .intoArray(sr, index);
+    }
+
+    @Run(test = "testShortMinIdeal")
+    public void runShortMinIdeal() {
+        for (int i = 0; i < S_SPECIES.loopBound(LENGTH); i += S_SPECIES.length()) {
+            testShortMinIdeal(i);
+        }
+        for (int i = 0; i < S_SPECIES.loopBound(LENGTH); i++) {
+            short expected = (short) Math.min(Math.min(sa[i], sb[i]), Math.max(sa[i], sb[i]));
+            Verify.checkEQ(sr[i], expected);
+        }
+    }
+
+    // ---------- Short: Ideal max(min(a,b), max(a,b)) => max(a,b) ----------
+    @Test
+    @IR(counts = { IRNode.MIN_VS, IRNode.VECTOR_SIZE_ANY, " 0 ",
+                   IRNode.MAX_VS, IRNode.VECTOR_SIZE_ANY, " 1 " },
+        applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"})
+    public void testShortMaxIdeal(int index) {
+        ShortVector v1 = ShortVector.fromArray(S_SPECIES, sa, index);
+        ShortVector v2 = ShortVector.fromArray(S_SPECIES, sb, index);
+        v1.lanewise(VectorOperators.MIN, v2)
+          .lanewise(VectorOperators.MAX, v1.lanewise(VectorOperators.MAX, v2))
+          .intoArray(sr, index);
+    }
+
+    @Run(test = "testShortMaxIdeal")
+    public void runShortMaxIdeal() {
+        for (int i = 0; i < S_SPECIES.loopBound(LENGTH); i += S_SPECIES.length()) {
+            testShortMaxIdeal(i);
+        }
+        for (int i = 0; i < S_SPECIES.loopBound(LENGTH); i++) {
+            short expected = (short) Math.max(Math.min(sa[i], sb[i]), Math.max(sa[i], sb[i]));
+            Verify.checkEQ(sr[i], expected);
+        }
+    }
+
+    // Predicated Int: min(min(a,b,m), max(a,b,m), m) => min(a,b,m)
+    @Test
+    @IR(counts = { IRNode.MIN_VI, IRNode.VECTOR_SIZE_ANY, " 1 ",
+                   IRNode.MAX_VI, IRNode.VECTOR_SIZE_ANY, " 0 " },
+        applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true"})
+    public void testIntMaskedMinIdealSameMask(int index) {
+        IntVector v1 = IntVector.fromArray(I_SPECIES, ia, index);
+        IntVector v2 = IntVector.fromArray(I_SPECIES, ib, index);
+        VectorMask m = VectorMask.fromArray(I_SPECIES, m1arr, index);
+        v1.lanewise(VectorOperators.MIN, v2, m)
+          .lanewise(VectorOperators.MIN, v1.lanewise(VectorOperators.MAX, v2, m), m)
+          .intoArray(ir, index);
+    }
+
+    @Run(test = "testIntMaskedMinIdealSameMask")
+    public void runIntMaskedMinIdealSameMask() {
+        for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i += I_SPECIES.length()) {
+            testIntMaskedMinIdealSameMask(i);
+        }
+        for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i++) {
+            int a = ia[i], b = ib[i];
+            boolean mask = m1arr[i];
+            int minAB = mask ? Math.min(a, b) : a;
+            int maxAB = mask ? Math.max(a, b) : a;
+            int expected = mask ? Math.min(minAB, maxAB) : minAB;
+            Verify.checkEQ(ir[i], expected);
+        }
+    }
+
+    // Predicated Int: max(min(a,b,m), max(a,b,m), m) => max(a,b,m)
+    @Test
+    @IR(counts = { IRNode.MIN_VI, IRNode.VECTOR_SIZE_ANY, " 0 ",
+                   IRNode.MAX_VI, IRNode.VECTOR_SIZE_ANY, " 1 " },
+        applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true"})
+    public void testIntMaskedMaxIdealSameMask(int index) {
+        IntVector v1 = IntVector.fromArray(I_SPECIES, ia, index);
+        IntVector v2 = IntVector.fromArray(I_SPECIES, ib, index);
+        VectorMask m = VectorMask.fromArray(I_SPECIES, m1arr, index);
+        v1.lanewise(VectorOperators.MIN, v2, m)
+          .lanewise(VectorOperators.MAX, v1.lanewise(VectorOperators.MAX, v2, m), m)
+          .intoArray(ir, index);
+    }
+
+    @Run(test = "testIntMaskedMaxIdealSameMask")
+    public void runIntMaskedMaxIdealSameMask() {
+        for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i += I_SPECIES.length()) {
+            testIntMaskedMaxIdealSameMask(i);
+        }
+        for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i++) {
+            int a = ia[i], b = ib[i];
+            boolean mask = m1arr[i];
+            int minAB = mask ? Math.min(a, b) : a;
+            int maxAB = mask ? Math.max(a, b) : a;
+            int expected = mask ? Math.max(minAB, maxAB) : minAB;
+            Verify.checkEQ(ir[i], expected);
+        }
+    }
+
+    // Predicated Int: max(min(a,b,m), max(b,a,m), m) => max(a,b,m)
+    @Test
+    @IR(counts = { IRNode.MIN_VI, IRNode.VECTOR_SIZE_ANY, " 0 ",
+                   IRNode.MAX_VI, IRNode.VECTOR_SIZE_ANY, " 1 " },
+        applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true"})
+    public void testIntMaskedMaxIdealFlippedInputs(int index) {
+        IntVector v1 = IntVector.fromArray(I_SPECIES, ia, index);
+        IntVector v2 = IntVector.fromArray(I_SPECIES, ib, index);
+        VectorMask m = VectorMask.fromArray(I_SPECIES, m1arr, index);
+        v1.lanewise(VectorOperators.MIN, v2, m)
+          .lanewise(VectorOperators.MAX, v2.lanewise(VectorOperators.MAX, v1, m), m)
+          .intoArray(ir, index);
+    }
+
+    @Run(test = "testIntMaskedMaxIdealFlippedInputs")
+    public void runIntMaskedMaxIdealFlippedInputs() {
+        for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i += I_SPECIES.length()) {
+            testIntMaskedMaxIdealFlippedInputs(i);
+        }
+        for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i++) {
+            int a = ia[i], b = ib[i];
+            boolean mask = m1arr[i];
+            int minAB = mask ? Math.min(a, b) : a;
+            int maxBA = mask ? Math.max(b, a) : b;
+            int expected = mask ? Math.max(minAB, maxBA) : minAB;
+            Verify.checkEQ(ir[i], expected);
+        }
+    }
+
+    // Predicated Int: min(min(a,b,m), max(b,a,m), m) => min(a,b,m)
+    @Test
+    @IR(counts = { IRNode.MIN_VI, IRNode.VECTOR_SIZE_ANY, " 1 ",
+                   IRNode.MAX_VI, IRNode.VECTOR_SIZE_ANY, " 0 " },
+        applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true"})
+    public void testIntMaskedMinIdealFlippedInputs(int index) {
+        IntVector v1 = IntVector.fromArray(I_SPECIES, ia, index);
+        IntVector v2 = IntVector.fromArray(I_SPECIES, ib, index);
+        VectorMask m = VectorMask.fromArray(I_SPECIES, m1arr, index);
+        v1.lanewise(VectorOperators.MIN, v2, m)
+          .lanewise(VectorOperators.MIN, v2.lanewise(VectorOperators.MAX, v1, m), m)
+          .intoArray(ir, index);
+    }
+
+    @Run(test = "testIntMaskedMinIdealFlippedInputs")
+    public void runIntMaskedMinIdealFlippedInputs() {
+        for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i += I_SPECIES.length()) {
+            testIntMaskedMinIdealFlippedInputs(i);
+        }
+        for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i++) {
+            int a = ia[i], b = ib[i];
+            boolean mask = m1arr[i];
+            int minAB = mask ? Math.min(a, b) : a;
+            int maxBA = mask ? Math.max(b, a) : b;
+            int expected = mask ? Math.min(minAB, maxBA) : minAB;
+            Verify.checkEQ(ir[i], expected);
+        }
+    }
+
+    // Predicated Int: min(min(a,b,m1), max(a,b,m2), m1) => NO transform
+    @Test
+    @IR(counts = { IRNode.MIN_VI, IRNode.VECTOR_SIZE_ANY, " 2 ",
+                   IRNode.MAX_VI, IRNode.VECTOR_SIZE_ANY, " 1 " },
+        applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true"})
+    public void testIntMaskedMinIdealDiffMaskMinMax(int index) {
+        IntVector v1 = IntVector.fromArray(I_SPECIES, ia, index);
+        IntVector v2 = IntVector.fromArray(I_SPECIES, ib, index);
+        VectorMask mask1 = VectorMask.fromArray(I_SPECIES, m1arr, index);
+        VectorMask mask2 = VectorMask.fromArray(I_SPECIES, m2arr, index);
+        v1.lanewise(VectorOperators.MIN, v2, mask1)
+          .lanewise(VectorOperators.MIN, v1.lanewise(VectorOperators.MAX, v2, mask2), mask1)
+          .intoArray(ir, index);
+    }
+
+    @Run(test = "testIntMaskedMinIdealDiffMaskMinMax")
+    public void runIntMaskedMinIdealDiffMaskMinMax() {
+        for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i += I_SPECIES.length()) {
+            testIntMaskedMinIdealDiffMaskMinMax(i);
+        }
+        for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i++) {
+            int a = ia[i], b = ib[i];
+            int minAB = m1arr[i] ? Math.min(a, b) : a;
+            int maxAB = m2arr[i] ? Math.max(a, b) : a;
+            int expected = m1arr[i] ? Math.min(minAB, maxAB) : minAB;
+            Verify.checkEQ(ir[i], expected);
+        }
+    }
+
+
+    // Predicated Int: min(min(a,b,m2), max(a,b,m1), m1) => NO transform
+    @Test
+    @IR(counts = { IRNode.MIN_VI, IRNode.VECTOR_SIZE_ANY, " 2 ",
+                   IRNode.MAX_VI, IRNode.VECTOR_SIZE_ANY, " 1 " },
+        applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true"})
+    public void testIntMaskedMinIdealDiffMaskMinMaxSwapped(int index) {
+        IntVector v1 = IntVector.fromArray(I_SPECIES, ia, index);
+        IntVector v2 = IntVector.fromArray(I_SPECIES, ib, index);
+        VectorMask mask1 = VectorMask.fromArray(I_SPECIES, m1arr, index);
+        VectorMask mask2 = VectorMask.fromArray(I_SPECIES, m2arr, index);
+        v1.lanewise(VectorOperators.MIN, v2, mask2)
+          .lanewise(VectorOperators.MIN, v1.lanewise(VectorOperators.MAX, v2, mask1), mask1)
+          .intoArray(ir, index);
+    }
+
+    @Run(test = "testIntMaskedMinIdealDiffMaskMinMaxSwapped")
+    public void runIntMaskedMinIdealDiffMaskMinMaxSwapped() {
+        for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i += I_SPECIES.length()) {
+            testIntMaskedMinIdealDiffMaskMinMaxSwapped(i);
+        }
+        for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i++) {
+            int a = ia[i], b = ib[i];
+            int minAB = m2arr[i] ? Math.min(a, b) : a;
+            int maxAB = m1arr[i] ? Math.max(a, b) : a;
+            int expected = m1arr[i] ? Math.min(minAB, maxAB) : minAB;
+            Verify.checkEQ(ir[i], expected);
+        }
+    }
+    // Predicated Int: min(min(a,b,m1), max(a,b,m1), m2) => NO transform
+    @Test
+    @IR(counts = { IRNode.MIN_VI, IRNode.VECTOR_SIZE_ANY, " 2 ",
+                   IRNode.MAX_VI, IRNode.VECTOR_SIZE_ANY, " 1 " },
+        applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true"})
+    public void testIntMaskedMinIdealDiffMaskOuter(int index) {
+        IntVector v1 = IntVector.fromArray(I_SPECIES, ia, index);
+        IntVector v2 = IntVector.fromArray(I_SPECIES, ib, index);
+        VectorMask mask1 = VectorMask.fromArray(I_SPECIES, m1arr, index);
+        VectorMask mask2 = VectorMask.fromArray(I_SPECIES, m2arr, index);
+        v1.lanewise(VectorOperators.MIN, v2, mask1)
+          .lanewise(VectorOperators.MIN, v1.lanewise(VectorOperators.MAX, v2, mask1), mask2)
+          .intoArray(ir, index);
+    }
+
+    @Run(test = "testIntMaskedMinIdealDiffMaskOuter")
+    public void runIntMaskedMinIdealDiffMaskOuter() {
+        for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i += I_SPECIES.length()) {
+            testIntMaskedMinIdealDiffMaskOuter(i);
+        }
+        for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i++) {
+            int a = ia[i], b = ib[i];
+            int minAB = m1arr[i] ? Math.min(a, b) : a;
+            int maxAB = m1arr[i] ? Math.max(a, b) : a;
+            int expected = m2arr[i] ? Math.min(minAB, maxAB) : minAB;
+            Verify.checkEQ(ir[i], expected);
+        }
+    }
+
+    // Predicated Int: min(min(a,b,m1), max(a,b,m2), m3) => NO transform
+    @Test
+    @IR(counts = { IRNode.MIN_VI, IRNode.VECTOR_SIZE_ANY, " 2 ",
+                   IRNode.MAX_VI, IRNode.VECTOR_SIZE_ANY, " 1 " },
+        applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true"})
+    public void testIntMaskedMinIdealAllDiffMask(int index) {
+        IntVector v1 = IntVector.fromArray(I_SPECIES, ia, index);
+        IntVector v2 = IntVector.fromArray(I_SPECIES, ib, index);
+        VectorMask mask1 = VectorMask.fromArray(I_SPECIES, m1arr, index);
+        VectorMask mask2 = VectorMask.fromArray(I_SPECIES, m2arr, index);
+        VectorMask mask3 = VectorMask.fromArray(I_SPECIES, m3arr, index);
+        v1.lanewise(VectorOperators.MIN, v2, mask1)
+          .lanewise(VectorOperators.MIN, v1.lanewise(VectorOperators.MAX, v2, mask2), mask3)
+          .intoArray(ir, index);
+    }
+
+    @Run(test = "testIntMaskedMinIdealAllDiffMask")
+    public void runIntMaskedMinIdealAllDiffMask() {
+        for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i += I_SPECIES.length()) {
+            testIntMaskedMinIdealAllDiffMask(i);
+        }
+        for (int i = 0; i < I_SPECIES.loopBound(LENGTH); i++) {
+            int a = ia[i], b = ib[i];
+            int minAB = m1arr[i] ? Math.min(a, b) : a;
+            int maxAB = m2arr[i] ? Math.max(a, b) : a;
+            int expected = m3arr[i] ? Math.min(minAB, maxAB) : minAB;
+            Verify.checkEQ(ir[i], expected);
+        }
+    }
+
+    // Predicated Byte: min(min(a,b,m), max(a,b,m), m) => min(a,b,m)
+    @Test
+    @IR(counts = { IRNode.MIN_VB, IRNode.VECTOR_SIZE_ANY, " 1 ",
+                   IRNode.MAX_VB, IRNode.VECTOR_SIZE_ANY, " 0 " },
+        applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true"})
+    public void testByteMaskedMinIdealSameMask(int index) {
+        ByteVector v1 = ByteVector.fromArray(B_SPECIES, ba, index);
+        ByteVector v2 = ByteVector.fromArray(B_SPECIES, bb, index);
+        VectorMask m = VectorMask.fromArray(B_SPECIES, m1arr, index);
+        v1.lanewise(VectorOperators.MIN, v2, m)
+          .lanewise(VectorOperators.MIN, v1.lanewise(VectorOperators.MAX, v2, m), m)
+          .intoArray(br, index);
+    }
+
+    @Run(test = "testByteMaskedMinIdealSameMask")
+    public void runByteMaskedMinIdealSameMask() {
+        for (int i = 0; i < B_SPECIES.loopBound(LENGTH); i += B_SPECIES.length()) {
+            testByteMaskedMinIdealSameMask(i);
+        }
+        for (int i = 0; i < B_SPECIES.loopBound(LENGTH); i++) {
+            byte a = ba[i], b = bb[i];
+            boolean mask = m1arr[i];
+            byte minAB = (byte)(mask ? Math.min(a, b) : a);
+            byte maxAB = (byte)(mask ? Math.max(a, b) : a);
+            byte expected = (byte)(mask ? Math.min(minAB, maxAB) : minAB);
+            Verify.checkEQ(br[i], expected);
+        }
+    }
+
+    // Predicated Byte: max(min(a,b,m), max(a,b,m), m) => max(a,b,m)
+    @Test
+    @IR(counts = { IRNode.MIN_VB, IRNode.VECTOR_SIZE_ANY, " 0 ",
+                   IRNode.MAX_VB, IRNode.VECTOR_SIZE_ANY, " 1 " },
+        applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true"})
+    public void testByteMaskedMaxIdealSameMask(int index) {
+        ByteVector v1 = ByteVector.fromArray(B_SPECIES, ba, index);
+        ByteVector v2 = ByteVector.fromArray(B_SPECIES, bb, index);
+        VectorMask m = VectorMask.fromArray(B_SPECIES, m1arr, index);
+        v1.lanewise(VectorOperators.MIN, v2, m)
+          .lanewise(VectorOperators.MAX, v1.lanewise(VectorOperators.MAX, v2, m), m)
+          .intoArray(br, index);
+    }
+
+    @Run(test = "testByteMaskedMaxIdealSameMask")
+    public void runByteMaskedMaxIdealSameMask() {
+        for (int i = 0; i < B_SPECIES.loopBound(LENGTH); i += B_SPECIES.length()) {
+            testByteMaskedMaxIdealSameMask(i);
+        }
+        for (int i = 0; i < B_SPECIES.loopBound(LENGTH); i++) {
+            byte a = ba[i], b = bb[i];
+            boolean mask = m1arr[i];
+            byte minAB = (byte)(mask ? Math.min(a, b) : a);
+            byte maxAB = (byte)(mask ? Math.max(a, b) : a);
+            byte expected = (byte)(mask ? Math.max(minAB, maxAB) : minAB);
+            Verify.checkEQ(br[i], expected);
+        }
+    }
+
+    // Predicated Byte: max(min(a,b,m), max(b,a,m), m) => max(a,b,m)
+    @Test
+    @IR(counts = { IRNode.MIN_VB, IRNode.VECTOR_SIZE_ANY, " 0 ",
+                   IRNode.MAX_VB, IRNode.VECTOR_SIZE_ANY, " 1 " },
+        applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true"})
+    public void testByteMaskedMaxIdealFlippedInputs(int index) {
+        ByteVector v1 = ByteVector.fromArray(B_SPECIES, ba, index);
+        ByteVector v2 = ByteVector.fromArray(B_SPECIES, bb, index);
+        VectorMask m = VectorMask.fromArray(B_SPECIES, m1arr, index);
+        v1.lanewise(VectorOperators.MIN, v2, m)
+          .lanewise(VectorOperators.MAX, v2.lanewise(VectorOperators.MAX, v1, m), m)
+          .intoArray(br, index);
+    }
+
+    @Run(test = "testByteMaskedMaxIdealFlippedInputs")
+    public void runByteMaskedMaxIdealFlippedInputs() {
+        for (int i = 0; i < B_SPECIES.loopBound(LENGTH); i += B_SPECIES.length()) {
+            testByteMaskedMaxIdealFlippedInputs(i);
+        }
+        for (int i = 0; i < B_SPECIES.loopBound(LENGTH); i++) {
+            byte a = ba[i], b = bb[i];
+            boolean mask = m1arr[i];
+            byte minAB = (byte)(mask ? Math.min(a, b) : a);
+            byte maxBA = (byte)(mask ? Math.max(b, a) : b);
+            byte expected = (byte)(mask ? Math.max(minAB, maxBA) : minAB);
+            Verify.checkEQ(br[i], expected);
+        }
+    }
+
+    // Predicated Byte: min(min(a,b,m), max(b,a,m), m) => min(a,b,m)
+    @Test
+    @IR(counts = { IRNode.MIN_VB, IRNode.VECTOR_SIZE_ANY, " 1 ",
+                   IRNode.MAX_VB, IRNode.VECTOR_SIZE_ANY, " 0 " },
+        applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true"})
+    public void testByteMaskedMinIdealFlippedInputs(int index) {
+        ByteVector v1 = ByteVector.fromArray(B_SPECIES, ba, index);
+        ByteVector v2 = ByteVector.fromArray(B_SPECIES, bb, index);
+        VectorMask m = VectorMask.fromArray(B_SPECIES, m1arr, index);
+        v1.lanewise(VectorOperators.MIN, v2, m)
+          .lanewise(VectorOperators.MIN, v2.lanewise(VectorOperators.MAX, v1, m), m)
+          .intoArray(br, index);
+    }
+
+    @Run(test = "testByteMaskedMinIdealFlippedInputs")
+    public void runByteMaskedMinIdealFlippedInputs() {
+        for (int i = 0; i < B_SPECIES.loopBound(LENGTH); i += B_SPECIES.length()) {
+            testByteMaskedMinIdealFlippedInputs(i);
+        }
+        for (int i = 0; i < B_SPECIES.loopBound(LENGTH); i++) {
+            byte a = ba[i], b = bb[i];
+            boolean mask = m1arr[i];
+            byte minAB = (byte)(mask ? Math.min(a, b) : a);
+            byte maxBA = (byte)(mask ? Math.max(b, a) : b);
+            byte expected = (byte)(mask ? Math.min(minAB, maxBA) : minAB);
+            Verify.checkEQ(br[i], expected);
+        }
+    }
+
+    // Predicated Byte: min(min(a,b,m1), max(a,b,m2), m1) => NO transform
+    @Test
+    @IR(counts = { IRNode.MIN_VB, IRNode.VECTOR_SIZE_ANY, " 2 ",
+                   IRNode.MAX_VB, IRNode.VECTOR_SIZE_ANY, " 1 " },
+        applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true"})
+    public void testByteMaskedMinIdealDiffMaskMinMax(int index) {
+        ByteVector v1 = ByteVector.fromArray(B_SPECIES, ba, index);
+        ByteVector v2 = ByteVector.fromArray(B_SPECIES, bb, index);
+        VectorMask mask1 = VectorMask.fromArray(B_SPECIES, m1arr, index);
+        VectorMask mask2 = VectorMask.fromArray(B_SPECIES, m2arr, index);
+        v1.lanewise(VectorOperators.MIN, v2, mask1)
+          .lanewise(VectorOperators.MIN, v1.lanewise(VectorOperators.MAX, v2, mask2), mask1)
+          .intoArray(br, index);
+    }
+
+    @Run(test = "testByteMaskedMinIdealDiffMaskMinMax")
+    public void runByteMaskedMinIdealDiffMaskMinMax() {
+        for (int i = 0; i < B_SPECIES.loopBound(LENGTH); i += B_SPECIES.length()) {
+            testByteMaskedMinIdealDiffMaskMinMax(i);
+        }
+        for (int i = 0; i < B_SPECIES.loopBound(LENGTH); i++) {
+            byte a = ba[i], b = bb[i];
+            byte minAB = (byte)(m1arr[i] ? Math.min(a, b) : a);
+            byte maxAB = (byte)(m2arr[i] ? Math.max(a, b) : a);
+            byte expected = (byte)(m1arr[i] ? Math.min(minAB, maxAB) : minAB);
+            Verify.checkEQ(br[i], expected);
+        }
+    }
+
+    // Predicated Byte: min(min(a,b,m2), max(a,b,m1), m1) => NO transform
+    @Test
+    @IR(counts = { IRNode.MIN_VB, IRNode.VECTOR_SIZE_ANY, " 2 ",
+                   IRNode.MAX_VB, IRNode.VECTOR_SIZE_ANY, " 1 " },
+        applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true"})
+    public void testByteMaskedMinIdealDiffMaskMinMaxSwapped(int index) {
+        ByteVector v1 = ByteVector.fromArray(B_SPECIES, ba, index);
+        ByteVector v2 = ByteVector.fromArray(B_SPECIES, bb, index);
+        VectorMask mask1 = VectorMask.fromArray(B_SPECIES, m1arr, index);
+        VectorMask mask2 = VectorMask.fromArray(B_SPECIES, m2arr, index);
+        v1.lanewise(VectorOperators.MIN, v2, mask2)
+          .lanewise(VectorOperators.MIN, v1.lanewise(VectorOperators.MAX, v2, mask1), mask1)
+          .intoArray(br, index);
+    }
+
+    @Run(test = "testByteMaskedMinIdealDiffMaskMinMaxSwapped")
+    public void runByteMaskedMinIdealDiffMaskMinMaxSwapped() {
+        for (int i = 0; i < B_SPECIES.loopBound(LENGTH); i += B_SPECIES.length()) {
+            testByteMaskedMinIdealDiffMaskMinMaxSwapped(i);
+        }
+        for (int i = 0; i < B_SPECIES.loopBound(LENGTH); i++) {
+            byte a = ba[i], b = bb[i];
+            byte minAB = (byte)(m2arr[i] ? Math.min(a, b) : a);
+            byte maxAB = (byte)(m1arr[i] ? Math.max(a, b) : a);
+            byte expected = (byte)(m1arr[i] ? Math.min(minAB, maxAB) : minAB);
+            Verify.checkEQ(br[i], expected);
+        }
+    }
+
+    // Predicated Byte: min(min(a,b,m1), max(a,b,m1), m2) => NO transform
+    @Test
+    @IR(counts = { IRNode.MIN_VB, IRNode.VECTOR_SIZE_ANY, " 2 ",
+                   IRNode.MAX_VB, IRNode.VECTOR_SIZE_ANY, " 1 " },
+        applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true"})
+    public void testByteMaskedMinIdealDiffMaskOuter(int index) {
+        ByteVector v1 = ByteVector.fromArray(B_SPECIES, ba, index);
+        ByteVector v2 = ByteVector.fromArray(B_SPECIES, bb, index);
+        VectorMask mask1 = VectorMask.fromArray(B_SPECIES, m1arr, index);
+        VectorMask mask2 = VectorMask.fromArray(B_SPECIES, m2arr, index);
+        v1.lanewise(VectorOperators.MIN, v2, mask1)
+          .lanewise(VectorOperators.MIN, v1.lanewise(VectorOperators.MAX, v2, mask1), mask2)
+          .intoArray(br, index);
+    }
+
+    @Run(test = "testByteMaskedMinIdealDiffMaskOuter")
+    public void runByteMaskedMinIdealDiffMaskOuter() {
+        for (int i = 0; i < B_SPECIES.loopBound(LENGTH); i += B_SPECIES.length()) {
+            testByteMaskedMinIdealDiffMaskOuter(i);
+        }
+        for (int i = 0; i < B_SPECIES.loopBound(LENGTH); i++) {
+            byte a = ba[i], b = bb[i];
+            byte minAB = (byte)(m1arr[i] ? Math.min(a, b) : a);
+            byte maxAB = (byte)(m1arr[i] ? Math.max(a, b) : a);
+            byte expected = (byte)(m2arr[i] ? Math.min(minAB, maxAB) : minAB);
+            Verify.checkEQ(br[i], expected);
+        }
+    }
+
+    // Predicated Byte: min(min(a,b,m1), max(a,b,m2), m3) => NO transform
+    @Test
+    @IR(counts = { IRNode.MIN_VB, IRNode.VECTOR_SIZE_ANY, " 2 ",
+                   IRNode.MAX_VB, IRNode.VECTOR_SIZE_ANY, " 1 " },
+        applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true"})
+    public void testByteMaskedMinIdealAllDiffMask(int index) {
+        ByteVector v1 = ByteVector.fromArray(B_SPECIES, ba, index);
+        ByteVector v2 = ByteVector.fromArray(B_SPECIES, bb, index);
+        VectorMask mask1 = VectorMask.fromArray(B_SPECIES, m1arr, index);
+        VectorMask mask2 = VectorMask.fromArray(B_SPECIES, m2arr, index);
+        VectorMask mask3 = VectorMask.fromArray(B_SPECIES, m3arr, index);
+        v1.lanewise(VectorOperators.MIN, v2, mask1)
+          .lanewise(VectorOperators.MIN, v1.lanewise(VectorOperators.MAX, v2, mask2), mask3)
+          .intoArray(br, index);
+    }
+
+    @Run(test = "testByteMaskedMinIdealAllDiffMask")
+    public void runByteMaskedMinIdealAllDiffMask() {
+        for (int i = 0; i < B_SPECIES.loopBound(LENGTH); i += B_SPECIES.length()) {
+            testByteMaskedMinIdealAllDiffMask(i);
+        }
+        for (int i = 0; i < B_SPECIES.loopBound(LENGTH); i++) {
+            byte a = ba[i], b = bb[i];
+            byte minAB = (byte)(m1arr[i] ? Math.min(a, b) : a);
+            byte maxAB = (byte)(m2arr[i] ? Math.max(a, b) : a);
+            byte expected = (byte)(m3arr[i] ? Math.min(minAB, maxAB) : minAB);
+            Verify.checkEQ(br[i], expected);
+        }
+    }
+
+    // Predicated Short: min(min(a,b,m), max(a,b,m), m) => min(a,b,m)
+    @Test
+    @IR(counts = { IRNode.MIN_VS, IRNode.VECTOR_SIZE_ANY, " 1 ",
+                   IRNode.MAX_VS, IRNode.VECTOR_SIZE_ANY, " 0 " },
+        applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true"})
+    public void testShortMaskedMinIdealSameMask(int index) {
+        ShortVector v1 = ShortVector.fromArray(S_SPECIES, sa, index);
+        ShortVector v2 = ShortVector.fromArray(S_SPECIES, sb, index);
+        VectorMask m = VectorMask.fromArray(S_SPECIES, m1arr, index);
+        v1.lanewise(VectorOperators.MIN, v2, m)
+          .lanewise(VectorOperators.MIN, v1.lanewise(VectorOperators.MAX, v2, m), m)
+          .intoArray(sr, index);
+    }
+
+    @Run(test = "testShortMaskedMinIdealSameMask")
+    public void runShortMaskedMinIdealSameMask() {
+        for (int i = 0; i < S_SPECIES.loopBound(LENGTH); i += S_SPECIES.length()) {
+            testShortMaskedMinIdealSameMask(i);
+        }
+        for (int i = 0; i < S_SPECIES.loopBound(LENGTH); i++) {
+            short a = sa[i], b = sb[i];
+            boolean mask = m1arr[i];
+            short minAB = (short)(mask ? Math.min(a, b) : a);
+            short maxAB = (short)(mask ? Math.max(a, b) : a);
+            short expected = (short)(mask ? Math.min(minAB, maxAB) : minAB);
+            Verify.checkEQ(sr[i], expected);
+        }
+    }
+
+    // Predicated Short: max(min(a,b,m), max(a,b,m), m) => max(a,b,m)
+    @Test
+    @IR(counts = { IRNode.MIN_VS, IRNode.VECTOR_SIZE_ANY, " 0 ",
+                   IRNode.MAX_VS, IRNode.VECTOR_SIZE_ANY, " 1 " },
+        applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true"})
+    public void testShortMaskedMaxIdealSameMask(int index) {
+        ShortVector v1 = ShortVector.fromArray(S_SPECIES, sa, index);
+        ShortVector v2 = ShortVector.fromArray(S_SPECIES, sb, index);
+        VectorMask m = VectorMask.fromArray(S_SPECIES, m1arr, index);
+        v1.lanewise(VectorOperators.MIN, v2, m)
+          .lanewise(VectorOperators.MAX, v1.lanewise(VectorOperators.MAX, v2, m), m)
+          .intoArray(sr, index);
+    }
+
+    @Run(test = "testShortMaskedMaxIdealSameMask")
+    public void runShortMaskedMaxIdealSameMask() {
+        for (int i = 0; i < S_SPECIES.loopBound(LENGTH); i += S_SPECIES.length()) {
+            testShortMaskedMaxIdealSameMask(i);
+        }
+        for (int i = 0; i < S_SPECIES.loopBound(LENGTH); i++) {
+            short a = sa[i], b = sb[i];
+            boolean mask = m1arr[i];
+            short minAB = (short)(mask ? Math.min(a, b) : a);
+            short maxAB = (short)(mask ? Math.max(a, b) : a);
+            short expected = (short)(mask ? Math.max(minAB, maxAB) : minAB);
+            Verify.checkEQ(sr[i], expected);
+        }
+    }
+
+    // Predicated Short: max(min(a,b,m), max(b,a,m), m) => max(a,b,m)
+    @Test
+    @IR(counts = { IRNode.MIN_VS, IRNode.VECTOR_SIZE_ANY, " 0 ",
+                   IRNode.MAX_VS, IRNode.VECTOR_SIZE_ANY, " 1 " },
+        applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true"})
+    public void testShortMaskedMaxIdealFlippedInputs(int index) {
+        ShortVector v1 = ShortVector.fromArray(S_SPECIES, sa, index);
+        ShortVector v2 = ShortVector.fromArray(S_SPECIES, sb, index);
+        VectorMask m = VectorMask.fromArray(S_SPECIES, m1arr, index);
+        v1.lanewise(VectorOperators.MIN, v2, m)
+          .lanewise(VectorOperators.MAX, v2.lanewise(VectorOperators.MAX, v1, m), m)
+          .intoArray(sr, index);
+    }
+
+    @Run(test = "testShortMaskedMaxIdealFlippedInputs")
+    public void runShortMaskedMaxIdealFlippedInputs() {
+        for (int i = 0; i < S_SPECIES.loopBound(LENGTH); i += S_SPECIES.length()) {
+            testShortMaskedMaxIdealFlippedInputs(i);
+        }
+        for (int i = 0; i < S_SPECIES.loopBound(LENGTH); i++) {
+            short a = sa[i], b = sb[i];
+            boolean mask = m1arr[i];
+            short minAB = (short)(mask ? Math.min(a, b) : a);
+            short maxBA = (short)(mask ? Math.max(b, a) : b);
+            short expected = (short)(mask ? Math.max(minAB, maxBA) : minAB);
+            Verify.checkEQ(sr[i], expected);
+        }
+    }
+
+    // Predicated Short: min(min(a,b,m), max(b,a,m), m) => min(a,b,m)
+    @Test
+    @IR(counts = { IRNode.MIN_VS, IRNode.VECTOR_SIZE_ANY, " 1 ",
+                   IRNode.MAX_VS, IRNode.VECTOR_SIZE_ANY, " 0 " },
+        applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true"})
+    public void testShortMaskedMinIdealFlippedInputs(int index) {
+        ShortVector v1 = ShortVector.fromArray(S_SPECIES, sa, index);
+        ShortVector v2 = ShortVector.fromArray(S_SPECIES, sb, index);
+        VectorMask m = VectorMask.fromArray(S_SPECIES, m1arr, index);
+        v1.lanewise(VectorOperators.MIN, v2, m)
+          .lanewise(VectorOperators.MIN, v2.lanewise(VectorOperators.MAX, v1, m), m)
+          .intoArray(sr, index);
+    }
+
+    @Run(test = "testShortMaskedMinIdealFlippedInputs")
+    public void runShortMaskedMinIdealFlippedInputs() {
+        for (int i = 0; i < S_SPECIES.loopBound(LENGTH); i += S_SPECIES.length()) {
+            testShortMaskedMinIdealFlippedInputs(i);
+        }
+        for (int i = 0; i < S_SPECIES.loopBound(LENGTH); i++) {
+            short a = sa[i], b = sb[i];
+            boolean mask = m1arr[i];
+            short minAB = (short)(mask ? Math.min(a, b) : a);
+            short maxBA = (short)(mask ? Math.max(b, a) : b);
+            short expected = (short)(mask ? Math.min(minAB, maxBA) : minAB);
+            Verify.checkEQ(sr[i], expected);
+        }
+    }
+
+    // Predicated Short: min(min(a,b,m1), max(a,b,m2), m1) => NO transform
+    @Test
+    @IR(counts = { IRNode.MIN_VS, IRNode.VECTOR_SIZE_ANY, " 2 ",
+                   IRNode.MAX_VS, IRNode.VECTOR_SIZE_ANY, " 1 " },
+        applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true"})
+    public void testShortMaskedMinIdealDiffMaskMinMax(int index) {
+        ShortVector v1 = ShortVector.fromArray(S_SPECIES, sa, index);
+        ShortVector v2 = ShortVector.fromArray(S_SPECIES, sb, index);
+        VectorMask mask1 = VectorMask.fromArray(S_SPECIES, m1arr, index);
+        VectorMask mask2 = VectorMask.fromArray(S_SPECIES, m2arr, index);
+        v1.lanewise(VectorOperators.MIN, v2, mask1)
+          .lanewise(VectorOperators.MIN, v1.lanewise(VectorOperators.MAX, v2, mask2), mask1)
+          .intoArray(sr, index);
+    }
+
+    @Run(test = "testShortMaskedMinIdealDiffMaskMinMax")
+    public void runShortMaskedMinIdealDiffMaskMinMax() {
+        for (int i = 0; i < S_SPECIES.loopBound(LENGTH); i += S_SPECIES.length()) {
+            testShortMaskedMinIdealDiffMaskMinMax(i);
+        }
+        for (int i = 0; i < S_SPECIES.loopBound(LENGTH); i++) {
+            short a = sa[i], b = sb[i];
+            short minAB = (short)(m1arr[i] ? Math.min(a, b) : a);
+            short maxAB = (short)(m2arr[i] ? Math.max(a, b) : a);
+            short expected = (short)(m1arr[i] ? Math.min(minAB, maxAB) : minAB);
+            Verify.checkEQ(sr[i], expected);
+        }
+    }
+
+    // Predicated Short: min(min(a,b,m2), max(a,b,m1), m1) => NO transform
+    @Test
+    @IR(counts = { IRNode.MIN_VS, IRNode.VECTOR_SIZE_ANY, " 2 ",
+                   IRNode.MAX_VS, IRNode.VECTOR_SIZE_ANY, " 1 " },
+        applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true"})
+    public void testShortMaskedMinIdealDiffMaskMinMaxSwapped(int index) {
+        ShortVector v1 = ShortVector.fromArray(S_SPECIES, sa, index);
+        ShortVector v2 = ShortVector.fromArray(S_SPECIES, sb, index);
+        VectorMask mask1 = VectorMask.fromArray(S_SPECIES, m1arr, index);
+        VectorMask mask2 = VectorMask.fromArray(S_SPECIES, m2arr, index);
+        v1.lanewise(VectorOperators.MIN, v2, mask2)
+          .lanewise(VectorOperators.MIN, v1.lanewise(VectorOperators.MAX, v2, mask1), mask1)
+          .intoArray(sr, index);
+    }
+
+    @Run(test = "testShortMaskedMinIdealDiffMaskMinMaxSwapped")
+    public void runShortMaskedMinIdealDiffMaskMinMaxSwapped() {
+        for (int i = 0; i < S_SPECIES.loopBound(LENGTH); i += S_SPECIES.length()) {
+            testShortMaskedMinIdealDiffMaskMinMaxSwapped(i);
+        }
+        for (int i = 0; i < S_SPECIES.loopBound(LENGTH); i++) {
+            short a = sa[i], b = sb[i];
+            short minAB = (short)(m2arr[i] ? Math.min(a, b) : a);
+            short maxAB = (short)(m1arr[i] ? Math.max(a, b) : a);
+            short expected = (short)(m1arr[i] ? Math.min(minAB, maxAB) : minAB);
+            Verify.checkEQ(sr[i], expected);
+        }
+    }
+
+    // Predicated Short: min(min(a,b,m1), max(a,b,m1), m2) => NO transform
+    @Test
+    @IR(counts = { IRNode.MIN_VS, IRNode.VECTOR_SIZE_ANY, " 2 ",
+                   IRNode.MAX_VS, IRNode.VECTOR_SIZE_ANY, " 1 " },
+        applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true"})
+    public void testShortMaskedMinIdealDiffMaskOuter(int index) {
+        ShortVector v1 = ShortVector.fromArray(S_SPECIES, sa, index);
+        ShortVector v2 = ShortVector.fromArray(S_SPECIES, sb, index);
+        VectorMask mask1 = VectorMask.fromArray(S_SPECIES, m1arr, index);
+        VectorMask mask2 = VectorMask.fromArray(S_SPECIES, m2arr, index);
+        v1.lanewise(VectorOperators.MIN, v2, mask1)
+          .lanewise(VectorOperators.MIN, v1.lanewise(VectorOperators.MAX, v2, mask1), mask2)
+          .intoArray(sr, index);
+    }
+
+    @Run(test = "testShortMaskedMinIdealDiffMaskOuter")
+    public void runShortMaskedMinIdealDiffMaskOuter() {
+        for (int i = 0; i < S_SPECIES.loopBound(LENGTH); i += S_SPECIES.length()) {
+            testShortMaskedMinIdealDiffMaskOuter(i);
+        }
+        for (int i = 0; i < S_SPECIES.loopBound(LENGTH); i++) {
+            short a = sa[i], b = sb[i];
+            short minAB = (short)(m1arr[i] ? Math.min(a, b) : a);
+            short maxAB = (short)(m1arr[i] ? Math.max(a, b) : a);
+            short expected = (short)(m2arr[i] ? Math.min(minAB, maxAB) : minAB);
+            Verify.checkEQ(sr[i], expected);
+        }
+    }
+
+    // Predicated Short: min(min(a,b,m1), max(a,b,m2), m3) => NO transform
+    @Test
+    @IR(counts = { IRNode.MIN_VS, IRNode.VECTOR_SIZE_ANY, " 2 ",
+                   IRNode.MAX_VS, IRNode.VECTOR_SIZE_ANY, " 1 " },
+        applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true"})
+    public void testShortMaskedMinIdealAllDiffMask(int index) {
+        ShortVector v1 = ShortVector.fromArray(S_SPECIES, sa, index);
+        ShortVector v2 = ShortVector.fromArray(S_SPECIES, sb, index);
+        VectorMask mask1 = VectorMask.fromArray(S_SPECIES, m1arr, index);
+        VectorMask mask2 = VectorMask.fromArray(S_SPECIES, m2arr, index);
+        VectorMask mask3 = VectorMask.fromArray(S_SPECIES, m3arr, index);
+        v1.lanewise(VectorOperators.MIN, v2, mask1)
+          .lanewise(VectorOperators.MIN, v1.lanewise(VectorOperators.MAX, v2, mask2), mask3)
+          .intoArray(sr, index);
+    }
+
+    @Run(test = "testShortMaskedMinIdealAllDiffMask")
+    public void runShortMaskedMinIdealAllDiffMask() {
+        for (int i = 0; i < S_SPECIES.loopBound(LENGTH); i += S_SPECIES.length()) {
+            testShortMaskedMinIdealAllDiffMask(i);
+        }
+        for (int i = 0; i < S_SPECIES.loopBound(LENGTH); i++) {
+            short a = sa[i], b = sb[i];
+            short minAB = (short)(m1arr[i] ? Math.min(a, b) : a);
+            short maxAB = (short)(m2arr[i] ? Math.max(a, b) : a);
+            short expected = (short)(m3arr[i] ? Math.min(minAB, maxAB) : minAB);
+            Verify.checkEQ(sr[i], expected);
+        }
+    }
+
+    // Predicated Long: min(min(a,b,m), max(a,b,m), m) => min(a,b,m)
+    @Test
+    @IR(counts = { IRNode.MIN_VL, IRNode.VECTOR_SIZE_ANY, " 1 ",
+                   IRNode.MAX_VL, IRNode.VECTOR_SIZE_ANY, " 0 " },
+        applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true"})
+    public void testLongMaskedMinIdealSameMask(int index) {
+        LongVector v1 = LongVector.fromArray(L_SPECIES, la, index);
+        LongVector v2 = LongVector.fromArray(L_SPECIES, lb, index);
+        VectorMask m = VectorMask.fromArray(L_SPECIES, m1arr, index);
+        v1.lanewise(VectorOperators.MIN, v2, m)
+          .lanewise(VectorOperators.MIN, v1.lanewise(VectorOperators.MAX, v2, m), m)
+          .intoArray(lr, index);
+    }
+
+    @Run(test = "testLongMaskedMinIdealSameMask")
+    public void runLongMaskedMinIdealSameMask() {
+        for (int i = 0; i < L_SPECIES.loopBound(LENGTH); i += L_SPECIES.length()) {
+            testLongMaskedMinIdealSameMask(i);
+        }
+        for (int i = 0; i < L_SPECIES.loopBound(LENGTH); i++) {
+            long a = la[i], b = lb[i];
+            boolean mask = m1arr[i];
+            long minAB = mask ? Math.min(a, b) : a;
+            long maxAB = mask ? Math.max(a, b) : a;
+            long expected = mask ? Math.min(minAB, maxAB) : minAB;
+            Verify.checkEQ(lr[i], expected);
+        }
+    }
+
+    // Predicated Long: max(min(a,b,m), max(a,b,m), m) => max(a,b,m)
+    @Test
+    @IR(counts = { IRNode.MIN_VL, IRNode.VECTOR_SIZE_ANY, " 0 ",
+                   IRNode.MAX_VL, IRNode.VECTOR_SIZE_ANY, " 1 " },
+        applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true"})
+    public void testLongMaskedMaxIdealSameMask(int index) {
+        LongVector v1 = LongVector.fromArray(L_SPECIES, la, index);
+        LongVector v2 = LongVector.fromArray(L_SPECIES, lb, index);
+        VectorMask m = VectorMask.fromArray(L_SPECIES, m1arr, index);
+        v1.lanewise(VectorOperators.MIN, v2, m)
+          .lanewise(VectorOperators.MAX, v1.lanewise(VectorOperators.MAX, v2, m), m)
+          .intoArray(lr, index);
+    }
+
+    @Run(test = "testLongMaskedMaxIdealSameMask")
+    public void runLongMaskedMaxIdealSameMask() {
+        for (int i = 0; i < L_SPECIES.loopBound(LENGTH); i += L_SPECIES.length()) {
+            testLongMaskedMaxIdealSameMask(i);
+        }
+        for (int i = 0; i < L_SPECIES.loopBound(LENGTH); i++) {
+            long a = la[i], b = lb[i];
+            boolean mask = m1arr[i];
+            long minAB = mask ? Math.min(a, b) : a;
+            long maxAB = mask ? Math.max(a, b) : a;
+            long expected = mask ? Math.max(minAB, maxAB) : minAB;
+            Verify.checkEQ(lr[i], expected);
+        }
+    }
+
+    // Predicated Long: max(min(a,b,m), max(b,a,m), m) => max(a,b,m)
+    @Test
+    @IR(counts = { IRNode.MIN_VL, IRNode.VECTOR_SIZE_ANY, " 0 ",
+                   IRNode.MAX_VL, IRNode.VECTOR_SIZE_ANY, " 1 " },
+        applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true"})
+    public void testLongMaskedMaxIdealFlippedInputs(int index) {
+        LongVector v1 = LongVector.fromArray(L_SPECIES, la, index);
+        LongVector v2 = LongVector.fromArray(L_SPECIES, lb, index);
+        VectorMask m = VectorMask.fromArray(L_SPECIES, m1arr, index);
+        v1.lanewise(VectorOperators.MIN, v2, m)
+          .lanewise(VectorOperators.MAX, v2.lanewise(VectorOperators.MAX, v1, m), m)
+          .intoArray(lr, index);
+    }
+
+    @Run(test = "testLongMaskedMaxIdealFlippedInputs")
+    public void runLongMaskedMaxIdealFlippedInputs() {
+        for (int i = 0; i < L_SPECIES.loopBound(LENGTH); i += L_SPECIES.length()) {
+            testLongMaskedMaxIdealFlippedInputs(i);
+        }
+        for (int i = 0; i < L_SPECIES.loopBound(LENGTH); i++) {
+            long a = la[i], b = lb[i];
+            boolean mask = m1arr[i];
+            long minAB = mask ? Math.min(a, b) : a;
+            long maxBA = mask ? Math.max(b, a) : b;
+            long expected = mask ? Math.max(minAB, maxBA) : minAB;
+            Verify.checkEQ(lr[i], expected);
+        }
+    }
+
+    // Predicated Long: min(min(a,b,m), max(b,a,m), m) => min(a,b,m)
+    @Test
+    @IR(counts = { IRNode.MIN_VL, IRNode.VECTOR_SIZE_ANY, " 1 ",
+                   IRNode.MAX_VL, IRNode.VECTOR_SIZE_ANY, " 0 " },
+        applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true"})
+    public void testLongMaskedMinIdealFlippedInputs(int index) {
+        LongVector v1 = LongVector.fromArray(L_SPECIES, la, index);
+        LongVector v2 = LongVector.fromArray(L_SPECIES, lb, index);
+        VectorMask m = VectorMask.fromArray(L_SPECIES, m1arr, index);
+        v1.lanewise(VectorOperators.MIN, v2, m)
+          .lanewise(VectorOperators.MIN, v2.lanewise(VectorOperators.MAX, v1, m), m)
+          .intoArray(lr, index);
+    }
+
+    @Run(test = "testLongMaskedMinIdealFlippedInputs")
+    public void runLongMaskedMinIdealFlippedInputs() {
+        for (int i = 0; i < L_SPECIES.loopBound(LENGTH); i += L_SPECIES.length()) {
+            testLongMaskedMinIdealFlippedInputs(i);
+        }
+        for (int i = 0; i < L_SPECIES.loopBound(LENGTH); i++) {
+            long a = la[i], b = lb[i];
+            boolean mask = m1arr[i];
+            long minAB = mask ? Math.min(a, b) : a;
+            long maxBA = mask ? Math.max(b, a) : b;
+            long expected = mask ? Math.min(minAB, maxBA) : minAB;
+            Verify.checkEQ(lr[i], expected);
+        }
+    }
+
+    // Predicated Long: min(min(a,b,m1), max(a,b,m2), m1) => NO transform
+    @Test
+    @IR(counts = { IRNode.MIN_VL, IRNode.VECTOR_SIZE_ANY, " 2 ",
+                   IRNode.MAX_VL, IRNode.VECTOR_SIZE_ANY, " 1 " },
+        applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true"})
+    public void testLongMaskedMinIdealDiffMaskMinMax(int index) {
+        LongVector v1 = LongVector.fromArray(L_SPECIES, la, index);
+        LongVector v2 = LongVector.fromArray(L_SPECIES, lb, index);
+        VectorMask mask1 = VectorMask.fromArray(L_SPECIES, m1arr, index);
+        VectorMask mask2 = VectorMask.fromArray(L_SPECIES, m2arr, index);
+        v1.lanewise(VectorOperators.MIN, v2, mask1)
+          .lanewise(VectorOperators.MIN, v1.lanewise(VectorOperators.MAX, v2, mask2), mask1)
+          .intoArray(lr, index);
+    }
+
+    @Run(test = "testLongMaskedMinIdealDiffMaskMinMax")
+    public void runLongMaskedMinIdealDiffMaskMinMax() {
+        for (int i = 0; i < L_SPECIES.loopBound(LENGTH); i += L_SPECIES.length()) {
+            testLongMaskedMinIdealDiffMaskMinMax(i);
+        }
+        for (int i = 0; i < L_SPECIES.loopBound(LENGTH); i++) {
+            long a = la[i], b = lb[i];
+            long minAB = m1arr[i] ? Math.min(a, b) : a;
+            long maxAB = m2arr[i] ? Math.max(a, b) : a;
+            long expected = m1arr[i] ? Math.min(minAB, maxAB) : minAB;
+            Verify.checkEQ(lr[i], expected);
+        }
+    }
+
+    // Predicated Long: min(min(a,b,m2), max(a,b,m1), m1) => NO transform
+    @Test
+    @IR(counts = { IRNode.MIN_VL, IRNode.VECTOR_SIZE_ANY, " 2 ",
+                   IRNode.MAX_VL, IRNode.VECTOR_SIZE_ANY, " 1 " },
+        applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true"})
+    public void testLongMaskedMinIdealDiffMaskMinMaxSwapped(int index) {
+        LongVector v1 = LongVector.fromArray(L_SPECIES, la, index);
+        LongVector v2 = LongVector.fromArray(L_SPECIES, lb, index);
+        VectorMask mask1 = VectorMask.fromArray(L_SPECIES, m1arr, index);
+        VectorMask mask2 = VectorMask.fromArray(L_SPECIES, m2arr, index);
+        v1.lanewise(VectorOperators.MIN, v2, mask2)
+          .lanewise(VectorOperators.MIN, v1.lanewise(VectorOperators.MAX, v2, mask1), mask1)
+          .intoArray(lr, index);
+    }
+
+    @Run(test = "testLongMaskedMinIdealDiffMaskMinMaxSwapped")
+    public void runLongMaskedMinIdealDiffMaskMinMaxSwapped() {
+        for (int i = 0; i < L_SPECIES.loopBound(LENGTH); i += L_SPECIES.length()) {
+            testLongMaskedMinIdealDiffMaskMinMaxSwapped(i);
+        }
+        for (int i = 0; i < L_SPECIES.loopBound(LENGTH); i++) {
+            long a = la[i], b = lb[i];
+            long minAB = m2arr[i] ? Math.min(a, b) : a;
+            long maxAB = m1arr[i] ? Math.max(a, b) : a;
+            long expected = m1arr[i] ? Math.min(minAB, maxAB) : minAB;
+            Verify.checkEQ(lr[i], expected);
+        }
+    }
+
+    // Predicated Long: min(min(a,b,m1), max(a,b,m1), m2) => NO transform
+    @Test
+    @IR(counts = { IRNode.MIN_VL, IRNode.VECTOR_SIZE_ANY, " 2 ",
+                   IRNode.MAX_VL, IRNode.VECTOR_SIZE_ANY, " 1 " },
+        applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true"})
+    public void testLongMaskedMinIdealDiffMaskOuter(int index) {
+        LongVector v1 = LongVector.fromArray(L_SPECIES, la, index);
+        LongVector v2 = LongVector.fromArray(L_SPECIES, lb, index);
+        VectorMask mask1 = VectorMask.fromArray(L_SPECIES, m1arr, index);
+        VectorMask mask2 = VectorMask.fromArray(L_SPECIES, m2arr, index);
+        v1.lanewise(VectorOperators.MIN, v2, mask1)
+          .lanewise(VectorOperators.MIN, v1.lanewise(VectorOperators.MAX, v2, mask1), mask2)
+          .intoArray(lr, index);
+    }
+
+    @Run(test = "testLongMaskedMinIdealDiffMaskOuter")
+    public void runLongMaskedMinIdealDiffMaskOuter() {
+        for (int i = 0; i < L_SPECIES.loopBound(LENGTH); i += L_SPECIES.length()) {
+            testLongMaskedMinIdealDiffMaskOuter(i);
+        }
+        for (int i = 0; i < L_SPECIES.loopBound(LENGTH); i++) {
+            long a = la[i], b = lb[i];
+            long minAB = m1arr[i] ? Math.min(a, b) : a;
+            long maxAB = m1arr[i] ? Math.max(a, b) : a;
+            long expected = m2arr[i] ? Math.min(minAB, maxAB) : minAB;
+            Verify.checkEQ(lr[i], expected);
+        }
+    }
+
+    // Predicated Long: min(min(a,b,m1), max(a,b,m2), m3) => NO transform
+    @Test
+    @IR(counts = { IRNode.MIN_VL, IRNode.VECTOR_SIZE_ANY, " 2 ",
+                   IRNode.MAX_VL, IRNode.VECTOR_SIZE_ANY, " 1 " },
+        applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true"})
+    public void testLongMaskedMinIdealAllDiffMask(int index) {
+        LongVector v1 = LongVector.fromArray(L_SPECIES, la, index);
+        LongVector v2 = LongVector.fromArray(L_SPECIES, lb, index);
+        VectorMask mask1 = VectorMask.fromArray(L_SPECIES, m1arr, index);
+        VectorMask mask2 = VectorMask.fromArray(L_SPECIES, m2arr, index);
+        VectorMask mask3 = VectorMask.fromArray(L_SPECIES, m3arr, index);
+        v1.lanewise(VectorOperators.MIN, v2, mask1)
+          .lanewise(VectorOperators.MIN, v1.lanewise(VectorOperators.MAX, v2, mask2), mask3)
+          .intoArray(lr, index);
+    }
+
+    @Run(test = "testLongMaskedMinIdealAllDiffMask")
+    public void runLongMaskedMinIdealAllDiffMask() {
+        for (int i = 0; i < L_SPECIES.loopBound(LENGTH); i += L_SPECIES.length()) {
+            testLongMaskedMinIdealAllDiffMask(i);
+        }
+        for (int i = 0; i < L_SPECIES.loopBound(LENGTH); i++) {
+            long a = la[i], b = lb[i];
+            long minAB = m1arr[i] ? Math.min(a, b) : a;
+            long maxAB = m2arr[i] ? Math.max(a, b) : a;
+            long expected = m3arr[i] ? Math.min(minAB, maxAB) : minAB;
+            Verify.checkEQ(lr[i], expected);
+        }
+    }
+
+    // Predicated Float: min(min(a,b,m), max(a,b,m), m) => min(a,b,m)
+    @Test
+    @IR(counts = { IRNode.MIN_VF, IRNode.VECTOR_SIZE_ANY, " 1 ",
+                   IRNode.MAX_VF, IRNode.VECTOR_SIZE_ANY, " 0 " },
+        applyIfCPUFeatureOr = {"avx10_2", "true", "sve", "true"})
+    public void testFloatMaskedMinIdealSameMask(int index) {
+        FloatVector v1 = FloatVector.fromArray(F_SPECIES, fa, index);
+        FloatVector v2 = FloatVector.fromArray(F_SPECIES, fb, index);
+        VectorMask m = VectorMask.fromArray(F_SPECIES, m1arr, index);
+        v1.lanewise(VectorOperators.MIN, v2, m)
+          .lanewise(VectorOperators.MIN, v1.lanewise(VectorOperators.MAX, v2, m), m)
+          .intoArray(fr, index);
+    }
+
+    @Run(test = "testFloatMaskedMinIdealSameMask")
+    public void runFloatMaskedMinIdealSameMask() {
+        for (int i = 0; i < F_SPECIES.loopBound(LENGTH); i += F_SPECIES.length()) {
+            testFloatMaskedMinIdealSameMask(i);
+        }
+        for (int i = 0; i < F_SPECIES.loopBound(LENGTH); i++) {
+            float a = fa[i], b = fb[i];
+            boolean mask = m1arr[i];
+            float minAB = mask ? Math.min(a, b) : a;
+            float maxAB = mask ? Math.max(a, b) : a;
+            float expected = mask ? Math.min(minAB, maxAB) : minAB;
+            Verify.checkEQ(fr[i], expected);
+        }
+    }
+
+    // Predicated Float: max(min(a,b,m), max(a,b,m), m) => max(a,b,m)
+    @Test
+    @IR(counts = { IRNode.MIN_VF, IRNode.VECTOR_SIZE_ANY, " 0 ",
+                   IRNode.MAX_VF, IRNode.VECTOR_SIZE_ANY, " 1 " },
+        applyIfCPUFeatureOr = {"avx10_2", "true", "sve", "true"})
+    public void testFloatMaskedMaxIdealSameMask(int index) {
+        FloatVector v1 = FloatVector.fromArray(F_SPECIES, fa, index);
+        FloatVector v2 = FloatVector.fromArray(F_SPECIES, fb, index);
+        VectorMask m = VectorMask.fromArray(F_SPECIES, m1arr, index);
+        v1.lanewise(VectorOperators.MIN, v2, m)
+          .lanewise(VectorOperators.MAX, v1.lanewise(VectorOperators.MAX, v2, m), m)
+          .intoArray(fr, index);
+    }
+
+    @Run(test = "testFloatMaskedMaxIdealSameMask")
+    public void runFloatMaskedMaxIdealSameMask() {
+        for (int i = 0; i < F_SPECIES.loopBound(LENGTH); i += F_SPECIES.length()) {
+            testFloatMaskedMaxIdealSameMask(i);
+        }
+        for (int i = 0; i < F_SPECIES.loopBound(LENGTH); i++) {
+            float a = fa[i], b = fb[i];
+            boolean mask = m1arr[i];
+            float minAB = mask ? Math.min(a, b) : a;
+            float maxAB = mask ? Math.max(a, b) : a;
+            float expected = mask ? Math.max(minAB, maxAB) : minAB;
+            Verify.checkEQ(fr[i], expected);
+        }
+    }
+
+    // Predicated Float: max(min(a,b,m), max(b,a,m), m) => max(a,b,m)
+    @Test
+    @IR(counts = { IRNode.MIN_VF, IRNode.VECTOR_SIZE_ANY, " 0 ",
+                   IRNode.MAX_VF, IRNode.VECTOR_SIZE_ANY, " 1 " },
+        applyIfCPUFeatureOr = {"avx10_2", "true", "sve", "true"})
+    public void testFloatMaskedMaxIdealFlippedInputs(int index) {
+        FloatVector v1 = FloatVector.fromArray(F_SPECIES, fa, index);
+        FloatVector v2 = FloatVector.fromArray(F_SPECIES, fb, index);
+        VectorMask m = VectorMask.fromArray(F_SPECIES, m1arr, index);
+        v1.lanewise(VectorOperators.MIN, v2, m)
+          .lanewise(VectorOperators.MAX, v2.lanewise(VectorOperators.MAX, v1, m), m)
+          .intoArray(fr, index);
+    }
+
+    @Run(test = "testFloatMaskedMaxIdealFlippedInputs")
+    public void runFloatMaskedMaxIdealFlippedInputs() {
+        for (int i = 0; i < F_SPECIES.loopBound(LENGTH); i += F_SPECIES.length()) {
+            testFloatMaskedMaxIdealFlippedInputs(i);
+        }
+        for (int i = 0; i < F_SPECIES.loopBound(LENGTH); i++) {
+            float a = fa[i], b = fb[i];
+            boolean mask = m1arr[i];
+            float minAB = mask ? Math.min(a, b) : a;
+            float maxBA = mask ? Math.max(b, a) : b;
+            float expected = mask ? Math.max(minAB, maxBA) : minAB;
+            Verify.checkEQ(fr[i], expected);
+        }
+    }
+
+    // Predicated Float: min(min(a,b,m), max(b,a,m), m) => min(a,b,m)
+    @Test
+    @IR(counts = { IRNode.MIN_VF, IRNode.VECTOR_SIZE_ANY, " 1 ",
+                   IRNode.MAX_VF, IRNode.VECTOR_SIZE_ANY, " 0 " },
+        applyIfCPUFeatureOr = {"avx10_2", "true", "sve", "true"})
+    public void testFloatMaskedMinIdealFlippedInputs(int index) {
+        FloatVector v1 = FloatVector.fromArray(F_SPECIES, fa, index);
+        FloatVector v2 = FloatVector.fromArray(F_SPECIES, fb, index);
+        VectorMask m = VectorMask.fromArray(F_SPECIES, m1arr, index);
+        v1.lanewise(VectorOperators.MIN, v2, m)
+          .lanewise(VectorOperators.MIN, v2.lanewise(VectorOperators.MAX, v1, m), m)
+          .intoArray(fr, index);
+    }
+
+    @Run(test = "testFloatMaskedMinIdealFlippedInputs")
+    public void runFloatMaskedMinIdealFlippedInputs() {
+        for (int i = 0; i < F_SPECIES.loopBound(LENGTH); i += F_SPECIES.length()) {
+            testFloatMaskedMinIdealFlippedInputs(i);
+        }
+        for (int i = 0; i < F_SPECIES.loopBound(LENGTH); i++) {
+            float a = fa[i], b = fb[i];
+            boolean mask = m1arr[i];
+            float minAB = mask ? Math.min(a, b) : a;
+            float maxBA = mask ? Math.max(b, a) : b;
+            float expected = mask ? Math.min(minAB, maxBA) : minAB;
+            Verify.checkEQ(fr[i], expected);
+        }
+    }
+
+    // Predicated Float: min(min(a,b,m1), max(a,b,m2), m1) => NO transform
+    @Test
+    @IR(counts = { IRNode.MIN_VF, IRNode.VECTOR_SIZE_ANY, " 2 ",
+                   IRNode.MAX_VF, IRNode.VECTOR_SIZE_ANY, " 1 " },
+        applyIfCPUFeatureOr = {"avx10_2", "true", "sve", "true"})
+    public void testFloatMaskedMinIdealDiffMaskMinMax(int index) {
+        FloatVector v1 = FloatVector.fromArray(F_SPECIES, fa, index);
+        FloatVector v2 = FloatVector.fromArray(F_SPECIES, fb, index);
+        VectorMask mask1 = VectorMask.fromArray(F_SPECIES, m1arr, index);
+        VectorMask mask2 = VectorMask.fromArray(F_SPECIES, m2arr, index);
+        v1.lanewise(VectorOperators.MIN, v2, mask1)
+          .lanewise(VectorOperators.MIN, v1.lanewise(VectorOperators.MAX, v2, mask2), mask1)
+          .intoArray(fr, index);
+    }
+
+    @Run(test = "testFloatMaskedMinIdealDiffMaskMinMax")
+    public void runFloatMaskedMinIdealDiffMaskMinMax() {
+        for (int i = 0; i < F_SPECIES.loopBound(LENGTH); i += F_SPECIES.length()) {
+            testFloatMaskedMinIdealDiffMaskMinMax(i);
+        }
+        for (int i = 0; i < F_SPECIES.loopBound(LENGTH); i++) {
+            float a = fa[i], b = fb[i];
+            float minAB = m1arr[i] ? Math.min(a, b) : a;
+            float maxAB = m2arr[i] ? Math.max(a, b) : a;
+            float expected = m1arr[i] ? Math.min(minAB, maxAB) : minAB;
+            Verify.checkEQ(fr[i], expected);
+        }
+    }
+
+    // Predicated Float: min(min(a,b,m2), max(a,b,m1), m1) => NO transform
+    @Test
+    @IR(counts = { IRNode.MIN_VF, IRNode.VECTOR_SIZE_ANY, " 2 ",
+                   IRNode.MAX_VF, IRNode.VECTOR_SIZE_ANY, " 1 " },
+        applyIfCPUFeatureOr = {"avx10_2", "true", "sve", "true"})
+    public void testFloatMaskedMinIdealDiffMaskMinMaxSwapped(int index) {
+        FloatVector v1 = FloatVector.fromArray(F_SPECIES, fa, index);
+        FloatVector v2 = FloatVector.fromArray(F_SPECIES, fb, index);
+        VectorMask mask1 = VectorMask.fromArray(F_SPECIES, m1arr, index);
+        VectorMask mask2 = VectorMask.fromArray(F_SPECIES, m2arr, index);
+        v1.lanewise(VectorOperators.MIN, v2, mask2)
+          .lanewise(VectorOperators.MIN, v1.lanewise(VectorOperators.MAX, v2, mask1), mask1)
+          .intoArray(fr, index);
+    }
+
+    @Run(test = "testFloatMaskedMinIdealDiffMaskMinMaxSwapped")
+    public void runFloatMaskedMinIdealDiffMaskMinMaxSwapped() {
+        for (int i = 0; i < F_SPECIES.loopBound(LENGTH); i += F_SPECIES.length()) {
+            testFloatMaskedMinIdealDiffMaskMinMaxSwapped(i);
+        }
+        for (int i = 0; i < F_SPECIES.loopBound(LENGTH); i++) {
+            float a = fa[i], b = fb[i];
+            float minAB = m2arr[i] ? Math.min(a, b) : a;
+            float maxAB = m1arr[i] ? Math.max(a, b) : a;
+            float expected = m1arr[i] ? Math.min(minAB, maxAB) : minAB;
+            Verify.checkEQ(fr[i], expected);
+        }
+    }
+
+    // Predicated Float: min(min(a,b,m1), max(a,b,m1), m2) => NO transform
+    @Test
+    @IR(counts = { IRNode.MIN_VF, IRNode.VECTOR_SIZE_ANY, " 2 ",
+                   IRNode.MAX_VF, IRNode.VECTOR_SIZE_ANY, " 1 " },
+        applyIfCPUFeatureOr = {"avx10_2", "true", "sve", "true"})
+    public void testFloatMaskedMinIdealDiffMaskOuter(int index) {
+        FloatVector v1 = FloatVector.fromArray(F_SPECIES, fa, index);
+        FloatVector v2 = FloatVector.fromArray(F_SPECIES, fb, index);
+        VectorMask mask1 = VectorMask.fromArray(F_SPECIES, m1arr, index);
+        VectorMask mask2 = VectorMask.fromArray(F_SPECIES, m2arr, index);
+        v1.lanewise(VectorOperators.MIN, v2, mask1)
+          .lanewise(VectorOperators.MIN, v1.lanewise(VectorOperators.MAX, v2, mask1), mask2)
+          .intoArray(fr, index);
+    }
+
+    @Run(test = "testFloatMaskedMinIdealDiffMaskOuter")
+    public void runFloatMaskedMinIdealDiffMaskOuter() {
+        for (int i = 0; i < F_SPECIES.loopBound(LENGTH); i += F_SPECIES.length()) {
+            testFloatMaskedMinIdealDiffMaskOuter(i);
+        }
+        for (int i = 0; i < F_SPECIES.loopBound(LENGTH); i++) {
+            float a = fa[i], b = fb[i];
+            float minAB = m1arr[i] ? Math.min(a, b) : a;
+            float maxAB = m1arr[i] ? Math.max(a, b) : a;
+            float expected = m2arr[i] ? Math.min(minAB, maxAB) : minAB;
+            Verify.checkEQ(fr[i], expected);
+        }
+    }
+
+    // Predicated Float: min(min(a,b,m1), max(a,b,m2), m3) => NO transform
+    @Test
+    @IR(counts = { IRNode.MIN_VF, IRNode.VECTOR_SIZE_ANY, " 2 ",
+                   IRNode.MAX_VF, IRNode.VECTOR_SIZE_ANY, " 1 " },
+        applyIfCPUFeatureOr = {"avx10_2", "true", "sve", "true"})
+    public void testFloatMaskedMinIdealAllDiffMask(int index) {
+        FloatVector v1 = FloatVector.fromArray(F_SPECIES, fa, index);
+        FloatVector v2 = FloatVector.fromArray(F_SPECIES, fb, index);
+        VectorMask mask1 = VectorMask.fromArray(F_SPECIES, m1arr, index);
+        VectorMask mask2 = VectorMask.fromArray(F_SPECIES, m2arr, index);
+        VectorMask mask3 = VectorMask.fromArray(F_SPECIES, m3arr, index);
+        v1.lanewise(VectorOperators.MIN, v2, mask1)
+          .lanewise(VectorOperators.MIN, v1.lanewise(VectorOperators.MAX, v2, mask2), mask3)
+          .intoArray(fr, index);
+    }
+
+    @Run(test = "testFloatMaskedMinIdealAllDiffMask")
+    public void runFloatMaskedMinIdealAllDiffMask() {
+        for (int i = 0; i < F_SPECIES.loopBound(LENGTH); i += F_SPECIES.length()) {
+            testFloatMaskedMinIdealAllDiffMask(i);
+        }
+        for (int i = 0; i < F_SPECIES.loopBound(LENGTH); i++) {
+            float a = fa[i], b = fb[i];
+            float minAB = m1arr[i] ? Math.min(a, b) : a;
+            float maxAB = m2arr[i] ? Math.max(a, b) : a;
+            float expected = m3arr[i] ? Math.min(minAB, maxAB) : minAB;
+            Verify.checkEQ(fr[i], expected);
+        }
+    }
+
+    // Predicated Double: min(min(a,b,m), max(a,b,m), m) => min(a,b,m)
+    @Test
+    @IR(counts = { IRNode.MIN_VD, IRNode.VECTOR_SIZE_ANY, " 1 ",
+                   IRNode.MAX_VD, IRNode.VECTOR_SIZE_ANY, " 0 " },
+        applyIfCPUFeatureOr = {"avx10_2", "true", "sve", "true"})
+    public void testDoubleMaskedMinIdealSameMask(int index) {
+        DoubleVector v1 = DoubleVector.fromArray(D_SPECIES, da, index);
+        DoubleVector v2 = DoubleVector.fromArray(D_SPECIES, db, index);
+        VectorMask m = VectorMask.fromArray(D_SPECIES, m1arr, index);
+        v1.lanewise(VectorOperators.MIN, v2, m)
+          .lanewise(VectorOperators.MIN, v1.lanewise(VectorOperators.MAX, v2, m), m)
+          .intoArray(dr, index);
+    }
+
+    @Run(test = "testDoubleMaskedMinIdealSameMask")
+    public void runDoubleMaskedMinIdealSameMask() {
+        for (int i = 0; i < D_SPECIES.loopBound(LENGTH); i += D_SPECIES.length()) {
+            testDoubleMaskedMinIdealSameMask(i);
+        }
+        for (int i = 0; i < D_SPECIES.loopBound(LENGTH); i++) {
+            double a = da[i], b = db[i];
+            boolean mask = m1arr[i];
+            double minAB = mask ? Math.min(a, b) : a;
+            double maxAB = mask ? Math.max(a, b) : a;
+            double expected = mask ? Math.min(minAB, maxAB) : minAB;
+            Verify.checkEQ(dr[i], expected);
+        }
+    }
+
+    // Predicated Double: max(min(a,b,m), max(a,b,m), m) => max(a,b,m)
+    @Test
+    @IR(counts = { IRNode.MIN_VD, IRNode.VECTOR_SIZE_ANY, " 0 ",
+                   IRNode.MAX_VD, IRNode.VECTOR_SIZE_ANY, " 1 " },
+        applyIfCPUFeatureOr = {"avx10_2", "true", "sve", "true"})
+    public void testDoubleMaskedMaxIdealSameMask(int index) {
+        DoubleVector v1 = DoubleVector.fromArray(D_SPECIES, da, index);
+        DoubleVector v2 = DoubleVector.fromArray(D_SPECIES, db, index);
+        VectorMask m = VectorMask.fromArray(D_SPECIES, m1arr, index);
+        v1.lanewise(VectorOperators.MIN, v2, m)
+          .lanewise(VectorOperators.MAX, v1.lanewise(VectorOperators.MAX, v2, m), m)
+          .intoArray(dr, index);
+    }
+
+    @Run(test = "testDoubleMaskedMaxIdealSameMask")
+    public void runDoubleMaskedMaxIdealSameMask() {
+        for (int i = 0; i < D_SPECIES.loopBound(LENGTH); i += D_SPECIES.length()) {
+            testDoubleMaskedMaxIdealSameMask(i);
+        }
+        for (int i = 0; i < D_SPECIES.loopBound(LENGTH); i++) {
+            double a = da[i], b = db[i];
+            boolean mask = m1arr[i];
+            double minAB = mask ? Math.min(a, b) : a;
+            double maxAB = mask ? Math.max(a, b) : a;
+            double expected = mask ? Math.max(minAB, maxAB) : minAB;
+            Verify.checkEQ(dr[i], expected);
+        }
+    }
+
+    // Predicated Double: max(min(a,b,m), max(b,a,m), m) => max(a,b,m)
+    @Test
+    @IR(counts = { IRNode.MIN_VD, IRNode.VECTOR_SIZE_ANY, " 0 ",
+                   IRNode.MAX_VD, IRNode.VECTOR_SIZE_ANY, " 1 " },
+        applyIfCPUFeatureOr = {"avx10_2", "true", "sve", "true"})
+    public void testDoubleMaskedMaxIdealFlippedInputs(int index) {
+        DoubleVector v1 = DoubleVector.fromArray(D_SPECIES, da, index);
+        DoubleVector v2 = DoubleVector.fromArray(D_SPECIES, db, index);
+        VectorMask m = VectorMask.fromArray(D_SPECIES, m1arr, index);
+        v1.lanewise(VectorOperators.MIN, v2, m)
+          .lanewise(VectorOperators.MAX, v2.lanewise(VectorOperators.MAX, v1, m), m)
+          .intoArray(dr, index);
+    }
+
+    @Run(test = "testDoubleMaskedMaxIdealFlippedInputs")
+    public void runDoubleMaskedMaxIdealFlippedInputs() {
+        for (int i = 0; i < D_SPECIES.loopBound(LENGTH); i += D_SPECIES.length()) {
+            testDoubleMaskedMaxIdealFlippedInputs(i);
+        }
+        for (int i = 0; i < D_SPECIES.loopBound(LENGTH); i++) {
+            double a = da[i], b = db[i];
+            boolean mask = m1arr[i];
+            double minAB = mask ? Math.min(a, b) : a;
+            double maxBA = mask ? Math.max(b, a) : b;
+            double expected = mask ? Math.max(minAB, maxBA) : minAB;
+            Verify.checkEQ(dr[i], expected);
+        }
+    }
+
+    // Predicated Double: min(min(a,b,m), max(b,a,m), m) => min(a,b,m)
+    @Test
+    @IR(counts = { IRNode.MIN_VD, IRNode.VECTOR_SIZE_ANY, " 1 ",
+                   IRNode.MAX_VD, IRNode.VECTOR_SIZE_ANY, " 0 " },
+        applyIfCPUFeatureOr = {"avx10_2", "true", "sve", "true"})
+    public void testDoubleMaskedMinIdealFlippedInputs(int index) {
+        DoubleVector v1 = DoubleVector.fromArray(D_SPECIES, da, index);
+        DoubleVector v2 = DoubleVector.fromArray(D_SPECIES, db, index);
+        VectorMask m = VectorMask.fromArray(D_SPECIES, m1arr, index);
+        v1.lanewise(VectorOperators.MIN, v2, m)
+          .lanewise(VectorOperators.MIN, v2.lanewise(VectorOperators.MAX, v1, m), m)
+          .intoArray(dr, index);
+    }
+
+    @Run(test = "testDoubleMaskedMinIdealFlippedInputs")
+    public void runDoubleMaskedMinIdealFlippedInputs() {
+        for (int i = 0; i < D_SPECIES.loopBound(LENGTH); i += D_SPECIES.length()) {
+            testDoubleMaskedMinIdealFlippedInputs(i);
+        }
+        for (int i = 0; i < D_SPECIES.loopBound(LENGTH); i++) {
+            double a = da[i], b = db[i];
+            boolean mask = m1arr[i];
+            double minAB = mask ? Math.min(a, b) : a;
+            double maxBA = mask ? Math.max(b, a) : b;
+            double expected = mask ? Math.min(minAB, maxBA) : minAB;
+            Verify.checkEQ(dr[i], expected);
+        }
+    }
+
+    // Predicated Double: min(min(a,b,m1), max(a,b,m2), m1) => NO transform
+    @Test
+    @IR(counts = { IRNode.MIN_VD, IRNode.VECTOR_SIZE_ANY, " 2 ",
+                   IRNode.MAX_VD, IRNode.VECTOR_SIZE_ANY, " 1 " },
+        applyIfCPUFeatureOr = {"avx10_2", "true", "sve", "true"})
+    public void testDoubleMaskedMinIdealDiffMaskMinMax(int index) {
+        DoubleVector v1 = DoubleVector.fromArray(D_SPECIES, da, index);
+        DoubleVector v2 = DoubleVector.fromArray(D_SPECIES, db, index);
+        VectorMask mask1 = VectorMask.fromArray(D_SPECIES, m1arr, index);
+        VectorMask mask2 = VectorMask.fromArray(D_SPECIES, m2arr, index);
+        v1.lanewise(VectorOperators.MIN, v2, mask1)
+          .lanewise(VectorOperators.MIN, v1.lanewise(VectorOperators.MAX, v2, mask2), mask1)
+          .intoArray(dr, index);
+    }
+
+    @Run(test = "testDoubleMaskedMinIdealDiffMaskMinMax")
+    public void runDoubleMaskedMinIdealDiffMaskMinMax() {
+        for (int i = 0; i < D_SPECIES.loopBound(LENGTH); i += D_SPECIES.length()) {
+            testDoubleMaskedMinIdealDiffMaskMinMax(i);
+        }
+        for (int i = 0; i < D_SPECIES.loopBound(LENGTH); i++) {
+            double a = da[i], b = db[i];
+            double minAB = m1arr[i] ? Math.min(a, b) : a;
+            double maxAB = m2arr[i] ? Math.max(a, b) : a;
+            double expected = m1arr[i] ? Math.min(minAB, maxAB) : minAB;
+            Verify.checkEQ(dr[i], expected);
+        }
+    }
+
+    // Predicated Double: min(min(a,b,m2), max(a,b,m1), m1) => NO transform
+    @Test
+    @IR(counts = { IRNode.MIN_VD, IRNode.VECTOR_SIZE_ANY, " 2 ",
+                   IRNode.MAX_VD, IRNode.VECTOR_SIZE_ANY, " 1 " },
+        applyIfCPUFeatureOr = {"avx10_2", "true", "sve", "true"})
+    public void testDoubleMaskedMinIdealDiffMaskMinMaxSwapped(int index) {
+        DoubleVector v1 = DoubleVector.fromArray(D_SPECIES, da, index);
+        DoubleVector v2 = DoubleVector.fromArray(D_SPECIES, db, index);
+        VectorMask mask1 = VectorMask.fromArray(D_SPECIES, m1arr, index);
+        VectorMask mask2 = VectorMask.fromArray(D_SPECIES, m2arr, index);
+        v1.lanewise(VectorOperators.MIN, v2, mask2)
+          .lanewise(VectorOperators.MIN, v1.lanewise(VectorOperators.MAX, v2, mask1), mask1)
+          .intoArray(dr, index);
+    }
+
+    @Run(test = "testDoubleMaskedMinIdealDiffMaskMinMaxSwapped")
+    public void runDoubleMaskedMinIdealDiffMaskMinMaxSwapped() {
+        for (int i = 0; i < D_SPECIES.loopBound(LENGTH); i += D_SPECIES.length()) {
+            testDoubleMaskedMinIdealDiffMaskMinMaxSwapped(i);
+        }
+        for (int i = 0; i < D_SPECIES.loopBound(LENGTH); i++) {
+            double a = da[i], b = db[i];
+            double minAB = m2arr[i] ? Math.min(a, b) : a;
+            double maxAB = m1arr[i] ? Math.max(a, b) : a;
+            double expected = m1arr[i] ? Math.min(minAB, maxAB) : minAB;
+            Verify.checkEQ(dr[i], expected);
+        }
+    }
+
+    // Predicated Double: min(min(a,b,m1), max(a,b,m1), m2) => NO transform
+    @Test
+    @IR(counts = { IRNode.MIN_VD, IRNode.VECTOR_SIZE_ANY, " 2 ",
+                   IRNode.MAX_VD, IRNode.VECTOR_SIZE_ANY, " 1 " },
+        applyIfCPUFeatureOr = {"avx10_2", "true", "sve", "true"})
+    public void testDoubleMaskedMinIdealDiffMaskOuter(int index) {
+        DoubleVector v1 = DoubleVector.fromArray(D_SPECIES, da, index);
+        DoubleVector v2 = DoubleVector.fromArray(D_SPECIES, db, index);
+        VectorMask mask1 = VectorMask.fromArray(D_SPECIES, m1arr, index);
+        VectorMask mask2 = VectorMask.fromArray(D_SPECIES, m2arr, index);
+        v1.lanewise(VectorOperators.MIN, v2, mask1)
+          .lanewise(VectorOperators.MIN, v1.lanewise(VectorOperators.MAX, v2, mask1), mask2)
+          .intoArray(dr, index);
+    }
+
+    @Run(test = "testDoubleMaskedMinIdealDiffMaskOuter")
+    public void runDoubleMaskedMinIdealDiffMaskOuter() {
+        for (int i = 0; i < D_SPECIES.loopBound(LENGTH); i += D_SPECIES.length()) {
+            testDoubleMaskedMinIdealDiffMaskOuter(i);
+        }
+        for (int i = 0; i < D_SPECIES.loopBound(LENGTH); i++) {
+            double a = da[i], b = db[i];
+            double minAB = m1arr[i] ? Math.min(a, b) : a;
+            double maxAB = m1arr[i] ? Math.max(a, b) : a;
+            double expected = m2arr[i] ? Math.min(minAB, maxAB) : minAB;
+            Verify.checkEQ(dr[i], expected);
+        }
+    }
+
+    // Predicated Double: min(min(a,b,m1), max(a,b,m2), m3) => NO transform
+    @Test
+    @IR(counts = { IRNode.MIN_VD, IRNode.VECTOR_SIZE_ANY, " 2 ",
+                   IRNode.MAX_VD, IRNode.VECTOR_SIZE_ANY, " 1 " },
+        applyIfCPUFeatureOr = {"avx10_2", "true", "sve", "true"})
+    public void testDoubleMaskedMinIdealAllDiffMask(int index) {
+        DoubleVector v1 = DoubleVector.fromArray(D_SPECIES, da, index);
+        DoubleVector v2 = DoubleVector.fromArray(D_SPECIES, db, index);
+        VectorMask mask1 = VectorMask.fromArray(D_SPECIES, m1arr, index);
+        VectorMask mask2 = VectorMask.fromArray(D_SPECIES, m2arr, index);
+        VectorMask mask3 = VectorMask.fromArray(D_SPECIES, m3arr, index);
+        v1.lanewise(VectorOperators.MIN, v2, mask1)
+          .lanewise(VectorOperators.MIN, v1.lanewise(VectorOperators.MAX, v2, mask2), mask3)
+          .intoArray(dr, index);
+    }
+
+    @Run(test = "testDoubleMaskedMinIdealAllDiffMask")
+    public void runDoubleMaskedMinIdealAllDiffMask() {
+        for (int i = 0; i < D_SPECIES.loopBound(LENGTH); i += D_SPECIES.length()) {
+            testDoubleMaskedMinIdealAllDiffMask(i);
+        }
+        for (int i = 0; i < D_SPECIES.loopBound(LENGTH); i++) {
+            double a = da[i], b = db[i];
+            double minAB = m1arr[i] ? Math.min(a, b) : a;
+            double maxAB = m2arr[i] ? Math.max(a, b) : a;
+            double expected = m3arr[i] ? Math.min(minAB, maxAB) : minAB;
+            Verify.checkEQ(dr[i], expected);
+        }
+    }
+}
diff --git a/test/hotspot/jtreg/compiler/vectorapi/VectorUnsignedMinMaxOperationsTest.java b/test/hotspot/jtreg/compiler/vectorapi/VectorUnsignedMinMaxOperationsTest.java
index 464e887cbac..b1b98306312 100644
--- a/test/hotspot/jtreg/compiler/vectorapi/VectorUnsignedMinMaxOperationsTest.java
+++ b/test/hotspot/jtreg/compiler/vectorapi/VectorUnsignedMinMaxOperationsTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved.
  * 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,10 +34,11 @@ package compiler.vectorapi;
 
 import jdk.incubator.vector.*;
 import compiler.lib.ir_framework.*;
+import compiler.lib.verify.*;
 import java.util.stream.IntStream;
 
 public class VectorUnsignedMinMaxOperationsTest {
-    private static final int COUNT = 2048;
+    private static final int COUNT = 1024;
     private static final VectorSpecies lspec    = LongVector.SPECIES_PREFERRED;
     private static final VectorSpecies ispec = IntVector.SPECIES_PREFERRED;
     private static final VectorSpecies sspec   = ShortVector.SPECIES_PREFERRED;
@@ -58,6 +59,8 @@ public class VectorUnsignedMinMaxOperationsTest {
     private short[] short_out;
     private byte[]  byte_out;
 
+    private boolean[] m1arr, m2arr, m3arr;
+
     public static void main(String[] args) {
         TestFramework testFramework = new TestFramework();
         testFramework.setDefaultWarmup(5000)
@@ -102,6 +105,14 @@ public class VectorUnsignedMinMaxOperationsTest {
         int_out   = new int[COUNT];
         short_out = new short[COUNT];
         byte_out  = new byte[COUNT];
+        m1arr = new boolean[COUNT];
+        m2arr = new boolean[COUNT];
+        m3arr = new boolean[COUNT];
+        for (int j = 0; j < COUNT; j++) {
+            m1arr[j] = (j % 2) == 0;
+            m2arr[j] = (j % 2) != 0;
+            m3arr[j] = (j % 3) == 0;
+        }
     }
 
     @Test
@@ -468,5 +479,1341 @@ public class VectorUnsignedMinMaxOperationsTest {
             }
         }
     }
-}
 
+
+    // Predicated: umin(umin(a,b,m), umax(a,b,m), m) => umin(a,b,m)
+    @Test
+    @IR(counts = {IRNode.UMIN_VI, " 1 ", IRNode.UMAX_VI, " 0 "}, applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true"})
+    public void umin_masked_same_mask(int index) {
+        IntVector vec1 = IntVector.fromArray(ispec, int_in1, index);
+        IntVector vec2 = IntVector.fromArray(ispec, int_in2, index);
+        VectorMask m = VectorMask.fromArray(ispec, m1arr, index);
+        vec1.lanewise(VectorOperators.UMIN, vec2, m)
+            .lanewise(VectorOperators.UMIN,
+                      vec1.lanewise(VectorOperators.UMAX, vec2, m), m)
+            .intoArray(int_out, index);
+    }
+
+    @Run(test = "umin_masked_same_mask")
+    public void umin_masked_same_mask_runner() {
+        for (int i = 0; i < ispec.loopBound(COUNT); i += ispec.length()) {
+            umin_masked_same_mask(i);
+        }
+        for (int i = 0; i < ispec.loopBound(COUNT); i++) {
+            int a = int_in1[i], b = int_in2[i];
+            int minAB = m1arr[i] ? VectorMath.minUnsigned(a, b) : a;
+            int maxAB = m1arr[i] ? VectorMath.maxUnsigned(a, b) : a;
+            int expected = m1arr[i] ? VectorMath.minUnsigned(minAB, maxAB) : minAB;
+            Verify.checkEQ(int_out[i], expected);
+        }
+    }
+
+    // Predicated: umin(umin(a,b,m), umax(b,a,m), m) => umin(a,b,m)
+    @Test
+    @IR(counts = {IRNode.UMIN_VI, " 1 ", IRNode.UMAX_VI, " 0 "}, applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true"})
+    public void umin_masked_flipped_inputs(int index) {
+        IntVector vec1 = IntVector.fromArray(ispec, int_in1, index);
+        IntVector vec2 = IntVector.fromArray(ispec, int_in2, index);
+        VectorMask m = VectorMask.fromArray(ispec, m1arr, index);
+        vec1.lanewise(VectorOperators.UMIN, vec2, m)
+            .lanewise(VectorOperators.UMIN,
+                      vec2.lanewise(VectorOperators.UMAX, vec1, m), m)
+            .intoArray(int_out, index);
+    }
+
+    @Run(test = "umin_masked_flipped_inputs")
+    public void umin_masked_flipped_inputs_runner() {
+        for (int i = 0; i < ispec.loopBound(COUNT); i += ispec.length()) {
+            umin_masked_flipped_inputs(i);
+        }
+        for (int i = 0; i < ispec.loopBound(COUNT); i++) {
+            int a = int_in1[i], b = int_in2[i];
+            int minAB = m1arr[i] ? VectorMath.minUnsigned(a, b) : a;
+            int maxBA = m1arr[i] ? VectorMath.maxUnsigned(b, a) : b;
+            int expected = m1arr[i] ? VectorMath.minUnsigned(minAB, maxBA) : minAB;
+            Verify.checkEQ(int_out[i], expected);
+        }
+    }
+
+    // Predicated: umin(umin(a,b,m1), umax(a,b,m2), m1) => NO transform
+    @Test
+    @IR(counts = {IRNode.UMIN_VI, " 2 ", IRNode.UMAX_VI, " 1 "}, applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true"})
+    public void umin_masked_diff_mask_minmax(int index) {
+        IntVector vec1 = IntVector.fromArray(ispec, int_in1, index);
+        IntVector vec2 = IntVector.fromArray(ispec, int_in2, index);
+        VectorMask mask1 = VectorMask.fromArray(ispec, m1arr, index);
+        VectorMask mask2 = VectorMask.fromArray(ispec, m2arr, index);
+        vec1.lanewise(VectorOperators.UMIN, vec2, mask1)
+            .lanewise(VectorOperators.UMIN,
+                      vec1.lanewise(VectorOperators.UMAX, vec2, mask2), mask1)
+            .intoArray(int_out, index);
+    }
+
+    @Run(test = "umin_masked_diff_mask_minmax")
+    public void umin_masked_diff_mask_minmax_runner() {
+        for (int i = 0; i < ispec.loopBound(COUNT); i += ispec.length()) {
+            umin_masked_diff_mask_minmax(i);
+        }
+        for (int i = 0; i < ispec.loopBound(COUNT); i++) {
+            int a = int_in1[i], b = int_in2[i];
+            int minAB = m1arr[i] ? VectorMath.minUnsigned(a, b) : a;
+            int maxAB = m2arr[i] ? VectorMath.maxUnsigned(a, b) : a;
+            int expected = m1arr[i] ? VectorMath.minUnsigned(minAB, maxAB) : minAB;
+            Verify.checkEQ(int_out[i], expected);
+        }
+    }
+
+    // Predicated: umin(umin(a,b,m2), umax(a,b,m1), m1) => NO transform
+    @Test
+    @IR(counts = {IRNode.UMIN_VI, " 2 ", IRNode.UMAX_VI, " 1 "}, applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true"})
+    public void umin_masked_diff_mask_minmax_swap(int index) {
+        IntVector vec1 = IntVector.fromArray(ispec, int_in1, index);
+        IntVector vec2 = IntVector.fromArray(ispec, int_in2, index);
+        VectorMask mask1 = VectorMask.fromArray(ispec, m1arr, index);
+        VectorMask mask2 = VectorMask.fromArray(ispec, m2arr, index);
+        vec1.lanewise(VectorOperators.UMIN, vec2, mask2)
+            .lanewise(VectorOperators.UMIN,
+                      vec1.lanewise(VectorOperators.UMAX, vec2, mask1), mask1)
+            .intoArray(int_out, index);
+    }
+
+    @Run(test = "umin_masked_diff_mask_minmax_swap")
+    public void umin_masked_diff_mask_minmax_swap_runner() {
+        for (int i = 0; i < ispec.loopBound(COUNT); i += ispec.length()) {
+            umin_masked_diff_mask_minmax_swap(i);
+        }
+        for (int i = 0; i < ispec.loopBound(COUNT); i++) {
+            int a = int_in1[i], b = int_in2[i];
+            int minAB = m2arr[i] ? VectorMath.minUnsigned(a, b) : a;
+            int maxAB = m1arr[i] ? VectorMath.maxUnsigned(a, b) : a;
+            int expected = m1arr[i] ? VectorMath.minUnsigned(minAB, maxAB) : minAB;
+            Verify.checkEQ(int_out[i], expected);
+        }
+    }
+
+    // Predicated: umin(umin(a,b,m1), umax(a,b,m1), m2) => NO transform
+    @Test
+    @IR(counts = {IRNode.UMIN_VI, " 2 ", IRNode.UMAX_VI, " 1 "}, applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true"})
+    public void umin_masked_diff_mask_outer(int index) {
+        IntVector vec1 = IntVector.fromArray(ispec, int_in1, index);
+        IntVector vec2 = IntVector.fromArray(ispec, int_in2, index);
+        VectorMask mask1 = VectorMask.fromArray(ispec, m1arr, index);
+        VectorMask mask2 = VectorMask.fromArray(ispec, m2arr, index);
+        vec1.lanewise(VectorOperators.UMIN, vec2, mask1)
+            .lanewise(VectorOperators.UMIN,
+                      vec1.lanewise(VectorOperators.UMAX, vec2, mask1), mask2)
+            .intoArray(int_out, index);
+    }
+
+    @Run(test = "umin_masked_diff_mask_outer")
+    public void umin_masked_diff_mask_outer_runner() {
+        for (int i = 0; i < ispec.loopBound(COUNT); i += ispec.length()) {
+            umin_masked_diff_mask_outer(i);
+        }
+        for (int i = 0; i < ispec.loopBound(COUNT); i++) {
+            int a = int_in1[i], b = int_in2[i];
+            int minAB = m1arr[i] ? VectorMath.minUnsigned(a, b) : a;
+            int maxAB = m1arr[i] ? VectorMath.maxUnsigned(a, b) : a;
+            int expected = m2arr[i] ? VectorMath.minUnsigned(minAB, maxAB) : minAB;
+            Verify.checkEQ(int_out[i], expected);
+        }
+    }
+
+    // Predicated: umin(umin(a,b,m1), umax(a,b,m2), m3) => NO transform
+    @Test
+    @IR(counts = {IRNode.UMIN_VI, " 2 ", IRNode.UMAX_VI, " 1 "}, applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true"})
+    public void umin_masked_all_diff_mask(int index) {
+        IntVector vec1 = IntVector.fromArray(ispec, int_in1, index);
+        IntVector vec2 = IntVector.fromArray(ispec, int_in2, index);
+        VectorMask mask1 = VectorMask.fromArray(ispec, m1arr, index);
+        VectorMask mask2 = VectorMask.fromArray(ispec, m2arr, index);
+        VectorMask mask3 = VectorMask.fromArray(ispec, m3arr, index);
+        vec1.lanewise(VectorOperators.UMIN, vec2, mask1)
+            .lanewise(VectorOperators.UMIN,
+                      vec1.lanewise(VectorOperators.UMAX, vec2, mask2), mask3)
+            .intoArray(int_out, index);
+    }
+
+    @Run(test = "umin_masked_all_diff_mask")
+    public void umin_masked_all_diff_mask_runner() {
+        for (int i = 0; i < ispec.loopBound(COUNT); i += ispec.length()) {
+            umin_masked_all_diff_mask(i);
+        }
+        for (int i = 0; i < ispec.loopBound(COUNT); i++) {
+            int a = int_in1[i], b = int_in2[i];
+            int minAB = m1arr[i] ? VectorMath.minUnsigned(a, b) : a;
+            int maxAB = m2arr[i] ? VectorMath.maxUnsigned(a, b) : a;
+            int expected = m3arr[i] ? VectorMath.minUnsigned(minAB, maxAB) : minAB;
+            Verify.checkEQ(int_out[i], expected);
+        }
+    }
+
+    // Predicated: umax(umin(a,b,m), umax(a,b,m), m) => umax(a,b,m)
+    @Test
+    @IR(counts = {IRNode.UMIN_VI, " 0 ", IRNode.UMAX_VI, " 1 "}, applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true"})
+    public void umax_masked_same_mask(int index) {
+        IntVector vec1 = IntVector.fromArray(ispec, int_in1, index);
+        IntVector vec2 = IntVector.fromArray(ispec, int_in2, index);
+        VectorMask m = VectorMask.fromArray(ispec, m1arr, index);
+        vec1.lanewise(VectorOperators.UMIN, vec2, m)
+            .lanewise(VectorOperators.UMAX,
+                      vec1.lanewise(VectorOperators.UMAX, vec2, m), m)
+            .intoArray(int_out, index);
+    }
+
+    @Run(test = "umax_masked_same_mask")
+    public void umax_masked_same_mask_runner() {
+        for (int i = 0; i < ispec.loopBound(COUNT); i += ispec.length()) {
+            umax_masked_same_mask(i);
+        }
+        for (int i = 0; i < ispec.loopBound(COUNT); i++) {
+            int a = int_in1[i], b = int_in2[i];
+            int minAB = m1arr[i] ? VectorMath.minUnsigned(a, b) : a;
+            int maxAB = m1arr[i] ? VectorMath.maxUnsigned(a, b) : a;
+            int expected = m1arr[i] ? VectorMath.maxUnsigned(minAB, maxAB) : minAB;
+            Verify.checkEQ(int_out[i], expected);
+        }
+    }
+
+    // Predicated: umax(umin(a,b,m), umax(b,a,m), m) => umax(a,b,m)
+    @Test
+    @IR(counts = {IRNode.UMIN_VI, " 0 ", IRNode.UMAX_VI, " 1 "}, applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true"})
+    public void umax_masked_flipped_inputs(int index) {
+        IntVector vec1 = IntVector.fromArray(ispec, int_in1, index);
+        IntVector vec2 = IntVector.fromArray(ispec, int_in2, index);
+        VectorMask m = VectorMask.fromArray(ispec, m1arr, index);
+        vec1.lanewise(VectorOperators.UMIN, vec2, m)
+            .lanewise(VectorOperators.UMAX,
+                      vec2.lanewise(VectorOperators.UMAX, vec1, m), m)
+            .intoArray(int_out, index);
+    }
+
+    @Run(test = "umax_masked_flipped_inputs")
+    public void umax_masked_flipped_inputs_runner() {
+        for (int i = 0; i < ispec.loopBound(COUNT); i += ispec.length()) {
+            umax_masked_flipped_inputs(i);
+        }
+        for (int i = 0; i < ispec.loopBound(COUNT); i++) {
+            int a = int_in1[i], b = int_in2[i];
+            int minAB = m1arr[i] ? VectorMath.minUnsigned(a, b) : a;
+            int maxBA = m1arr[i] ? VectorMath.maxUnsigned(b, a) : b;
+            int expected = m1arr[i] ? VectorMath.maxUnsigned(minAB, maxBA) : minAB;
+            Verify.checkEQ(int_out[i], expected);
+        }
+    }
+
+    // Predicated: umax(umin(a,b,m1), umax(a,b,m2), m1) => NO transform
+    @Test
+    @IR(counts = {IRNode.UMIN_VI, " 1 ", IRNode.UMAX_VI, " 2 "}, applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true"})
+    public void umax_masked_diff_mask_minmax(int index) {
+        IntVector vec1 = IntVector.fromArray(ispec, int_in1, index);
+        IntVector vec2 = IntVector.fromArray(ispec, int_in2, index);
+        VectorMask mask1 = VectorMask.fromArray(ispec, m1arr, index);
+        VectorMask mask2 = VectorMask.fromArray(ispec, m2arr, index);
+        vec1.lanewise(VectorOperators.UMIN, vec2, mask1)
+            .lanewise(VectorOperators.UMAX,
+                      vec1.lanewise(VectorOperators.UMAX, vec2, mask2), mask1)
+            .intoArray(int_out, index);
+    }
+
+    @Run(test = "umax_masked_diff_mask_minmax")
+    public void umax_masked_diff_mask_minmax_runner() {
+        for (int i = 0; i < ispec.loopBound(COUNT); i += ispec.length()) {
+            umax_masked_diff_mask_minmax(i);
+        }
+        for (int i = 0; i < ispec.loopBound(COUNT); i++) {
+            int a = int_in1[i], b = int_in2[i];
+            int minAB = m1arr[i] ? VectorMath.minUnsigned(a, b) : a;
+            int maxAB = m2arr[i] ? VectorMath.maxUnsigned(a, b) : a;
+            int expected = m1arr[i] ? VectorMath.maxUnsigned(minAB, maxAB) : minAB;
+            Verify.checkEQ(int_out[i], expected);
+        }
+    }
+
+    // Predicated: umax(umin(a,b,m2), umax(a,b,m1), m1) => NO transform
+    @Test
+    @IR(counts = {IRNode.UMIN_VI, " 1 ", IRNode.UMAX_VI, " 2 "}, applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true"})
+    public void umax_masked_diff_mask_minmax_swap(int index) {
+        IntVector vec1 = IntVector.fromArray(ispec, int_in1, index);
+        IntVector vec2 = IntVector.fromArray(ispec, int_in2, index);
+        VectorMask mask1 = VectorMask.fromArray(ispec, m1arr, index);
+        VectorMask mask2 = VectorMask.fromArray(ispec, m2arr, index);
+        vec1.lanewise(VectorOperators.UMIN, vec2, mask2)
+            .lanewise(VectorOperators.UMAX,
+                      vec1.lanewise(VectorOperators.UMAX, vec2, mask1), mask1)
+            .intoArray(int_out, index);
+    }
+
+    @Run(test = "umax_masked_diff_mask_minmax_swap")
+    public void umax_masked_diff_mask_minmax_swap_runner() {
+        for (int i = 0; i < ispec.loopBound(COUNT); i += ispec.length()) {
+            umax_masked_diff_mask_minmax_swap(i);
+        }
+        for (int i = 0; i < ispec.loopBound(COUNT); i++) {
+            int a = int_in1[i], b = int_in2[i];
+            int minAB = m2arr[i] ? VectorMath.minUnsigned(a, b) : a;
+            int maxAB = m1arr[i] ? VectorMath.maxUnsigned(a, b) : a;
+            int expected = m1arr[i] ? VectorMath.maxUnsigned(minAB, maxAB) : minAB;
+            Verify.checkEQ(int_out[i], expected);
+        }
+    }
+
+    // Predicated: umax(umin(a,b,m1), umax(a,b,m1), m2) => NO transform
+    @Test
+    @IR(counts = {IRNode.UMIN_VI, " 1 ", IRNode.UMAX_VI, " 2 "}, applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true"})
+    public void umax_masked_diff_mask_outer(int index) {
+        IntVector vec1 = IntVector.fromArray(ispec, int_in1, index);
+        IntVector vec2 = IntVector.fromArray(ispec, int_in2, index);
+        VectorMask mask1 = VectorMask.fromArray(ispec, m1arr, index);
+        VectorMask mask2 = VectorMask.fromArray(ispec, m2arr, index);
+        vec1.lanewise(VectorOperators.UMIN, vec2, mask1)
+            .lanewise(VectorOperators.UMAX,
+                      vec1.lanewise(VectorOperators.UMAX, vec2, mask1), mask2)
+            .intoArray(int_out, index);
+    }
+
+    @Run(test = "umax_masked_diff_mask_outer")
+    public void umax_masked_diff_mask_outer_runner() {
+        for (int i = 0; i < ispec.loopBound(COUNT); i += ispec.length()) {
+            umax_masked_diff_mask_outer(i);
+        }
+        for (int i = 0; i < ispec.loopBound(COUNT); i++) {
+            int a = int_in1[i], b = int_in2[i];
+            int minAB = m1arr[i] ? VectorMath.minUnsigned(a, b) : a;
+            int maxAB = m1arr[i] ? VectorMath.maxUnsigned(a, b) : a;
+            int expected = m2arr[i] ? VectorMath.maxUnsigned(minAB, maxAB) : minAB;
+            Verify.checkEQ(int_out[i], expected);
+        }
+    }
+
+    // Predicated: umax(umin(a,b,m1), umax(a,b,m2), m3) => NO transform
+    @Test
+    @IR(counts = {IRNode.UMIN_VI, " 1 ", IRNode.UMAX_VI, " 2 "}, applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true"})
+    public void umax_masked_all_diff_mask(int index) {
+        IntVector vec1 = IntVector.fromArray(ispec, int_in1, index);
+        IntVector vec2 = IntVector.fromArray(ispec, int_in2, index);
+        VectorMask mask1 = VectorMask.fromArray(ispec, m1arr, index);
+        VectorMask mask2 = VectorMask.fromArray(ispec, m2arr, index);
+        VectorMask mask3 = VectorMask.fromArray(ispec, m3arr, index);
+        vec1.lanewise(VectorOperators.UMIN, vec2, mask1)
+            .lanewise(VectorOperators.UMAX,
+                      vec1.lanewise(VectorOperators.UMAX, vec2, mask2), mask3)
+            .intoArray(int_out, index);
+    }
+
+    @Run(test = "umax_masked_all_diff_mask")
+    public void umax_masked_all_diff_mask_runner() {
+        for (int i = 0; i < ispec.loopBound(COUNT); i += ispec.length()) {
+            umax_masked_all_diff_mask(i);
+        }
+        for (int i = 0; i < ispec.loopBound(COUNT); i++) {
+            int a = int_in1[i], b = int_in2[i];
+            int minAB = m1arr[i] ? VectorMath.minUnsigned(a, b) : a;
+            int maxAB = m2arr[i] ? VectorMath.maxUnsigned(a, b) : a;
+            int expected = m3arr[i] ? VectorMath.maxUnsigned(minAB, maxAB) : minAB;
+            Verify.checkEQ(int_out[i], expected);
+        }
+    }
+
+    // Predicated Byte: umin(umin(a,b,m), umax(a,b,m), m) => umin(a,b,m)
+    @Test
+    @IR(counts = {IRNode.UMIN_VB, " 1 ", IRNode.UMAX_VB, " 0 "}, applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true"})
+    public void umin_byte_masked_same_mask(int index) {
+        ByteVector vec1 = ByteVector.fromArray(bspec, byte_in1, index);
+        ByteVector vec2 = ByteVector.fromArray(bspec, byte_in2, index);
+        VectorMask m = VectorMask.fromArray(bspec, m1arr, index);
+        vec1.lanewise(VectorOperators.UMIN, vec2, m)
+            .lanewise(VectorOperators.UMIN,
+                      vec1.lanewise(VectorOperators.UMAX, vec2, m), m)
+            .intoArray(byte_out, index);
+    }
+
+    @Run(test = "umin_byte_masked_same_mask")
+    public void umin_byte_masked_same_mask_runner() {
+        for (int i = 0; i < bspec.loopBound(COUNT); i += bspec.length()) {
+            umin_byte_masked_same_mask(i);
+        }
+        for (int i = 0; i < bspec.loopBound(COUNT); i++) {
+            byte a = byte_in1[i], b = byte_in2[i];
+            byte minAB = (byte)(m1arr[i] ? VectorMath.minUnsigned(a, b) : a);
+            byte maxAB = (byte)(m1arr[i] ? VectorMath.maxUnsigned(a, b) : a);
+            byte expected = (byte)(m1arr[i] ? VectorMath.minUnsigned(minAB, maxAB) : minAB);
+            Verify.checkEQ(byte_out[i], expected);
+        }
+    }
+
+    // Predicated Byte: umin(umin(a,b,m), umax(b,a,m), m) => umin(a,b,m)
+    @Test
+    @IR(counts = {IRNode.UMIN_VB, " 1 ", IRNode.UMAX_VB, " 0 "}, applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true"})
+    public void umin_byte_masked_flipped_inputs(int index) {
+        ByteVector vec1 = ByteVector.fromArray(bspec, byte_in1, index);
+        ByteVector vec2 = ByteVector.fromArray(bspec, byte_in2, index);
+        VectorMask m = VectorMask.fromArray(bspec, m1arr, index);
+        vec1.lanewise(VectorOperators.UMIN, vec2, m)
+            .lanewise(VectorOperators.UMIN,
+                      vec2.lanewise(VectorOperators.UMAX, vec1, m), m)
+            .intoArray(byte_out, index);
+    }
+
+    @Run(test = "umin_byte_masked_flipped_inputs")
+    public void umin_byte_masked_flipped_inputs_runner() {
+        for (int i = 0; i < bspec.loopBound(COUNT); i += bspec.length()) {
+            umin_byte_masked_flipped_inputs(i);
+        }
+        for (int i = 0; i < bspec.loopBound(COUNT); i++) {
+            byte a = byte_in1[i], b = byte_in2[i];
+            byte minAB = (byte)(m1arr[i] ? VectorMath.minUnsigned(a, b) : a);
+            byte maxBA = (byte)(m1arr[i] ? VectorMath.maxUnsigned(b, a) : b);
+            byte expected = (byte)(m1arr[i] ? VectorMath.minUnsigned(minAB, maxBA) : minAB);
+            Verify.checkEQ(byte_out[i], expected);
+        }
+    }
+
+    // Predicated Byte: umin(umin(a,b,m1), umax(a,b,m2), m1) => NO transform
+    @Test
+    @IR(counts = {IRNode.UMIN_VB, " 2 ", IRNode.UMAX_VB, " 1 "}, applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true"})
+    public void umin_byte_masked_diff_mask_minmax(int index) {
+        ByteVector vec1 = ByteVector.fromArray(bspec, byte_in1, index);
+        ByteVector vec2 = ByteVector.fromArray(bspec, byte_in2, index);
+        VectorMask mask1 = VectorMask.fromArray(bspec, m1arr, index);
+        VectorMask mask2 = VectorMask.fromArray(bspec, m2arr, index);
+        vec1.lanewise(VectorOperators.UMIN, vec2, mask1)
+            .lanewise(VectorOperators.UMIN,
+                      vec1.lanewise(VectorOperators.UMAX, vec2, mask2), mask1)
+            .intoArray(byte_out, index);
+    }
+
+    @Run(test = "umin_byte_masked_diff_mask_minmax")
+    public void umin_byte_masked_diff_mask_minmax_runner() {
+        for (int i = 0; i < bspec.loopBound(COUNT); i += bspec.length()) {
+            umin_byte_masked_diff_mask_minmax(i);
+        }
+        for (int i = 0; i < bspec.loopBound(COUNT); i++) {
+            byte a = byte_in1[i], b = byte_in2[i];
+            byte minAB = (byte)(m1arr[i] ? VectorMath.minUnsigned(a, b) : a);
+            byte maxAB = (byte)(m2arr[i] ? VectorMath.maxUnsigned(a, b) : a);
+            byte expected = (byte)(m1arr[i] ? VectorMath.minUnsigned(minAB, maxAB) : minAB);
+            Verify.checkEQ(byte_out[i], expected);
+        }
+    }
+
+    // Predicated Byte: umin(umin(a,b,m2), umax(a,b,m1), m1) => NO transform
+    @Test
+    @IR(counts = {IRNode.UMIN_VB, " 2 ", IRNode.UMAX_VB, " 1 "}, applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true"})
+    public void umin_byte_masked_diff_mask_minmax_swap(int index) {
+        ByteVector vec1 = ByteVector.fromArray(bspec, byte_in1, index);
+        ByteVector vec2 = ByteVector.fromArray(bspec, byte_in2, index);
+        VectorMask mask1 = VectorMask.fromArray(bspec, m1arr, index);
+        VectorMask mask2 = VectorMask.fromArray(bspec, m2arr, index);
+        vec1.lanewise(VectorOperators.UMIN, vec2, mask2)
+            .lanewise(VectorOperators.UMIN,
+                      vec1.lanewise(VectorOperators.UMAX, vec2, mask1), mask1)
+            .intoArray(byte_out, index);
+    }
+
+    @Run(test = "umin_byte_masked_diff_mask_minmax_swap")
+    public void umin_byte_masked_diff_mask_minmax_swap_runner() {
+        for (int i = 0; i < bspec.loopBound(COUNT); i += bspec.length()) {
+            umin_byte_masked_diff_mask_minmax_swap(i);
+        }
+        for (int i = 0; i < bspec.loopBound(COUNT); i++) {
+            byte a = byte_in1[i], b = byte_in2[i];
+            byte minAB = (byte)(m2arr[i] ? VectorMath.minUnsigned(a, b) : a);
+            byte maxAB = (byte)(m1arr[i] ? VectorMath.maxUnsigned(a, b) : a);
+            byte expected = (byte)(m1arr[i] ? VectorMath.minUnsigned(minAB, maxAB) : minAB);
+            Verify.checkEQ(byte_out[i], expected);
+        }
+    }
+
+    // Predicated Byte: umin(umin(a,b,m1), umax(a,b,m1), m2) => NO transform
+    @Test
+    @IR(counts = {IRNode.UMIN_VB, " 2 ", IRNode.UMAX_VB, " 1 "}, applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true"})
+    public void umin_byte_masked_diff_mask_outer(int index) {
+        ByteVector vec1 = ByteVector.fromArray(bspec, byte_in1, index);
+        ByteVector vec2 = ByteVector.fromArray(bspec, byte_in2, index);
+        VectorMask mask1 = VectorMask.fromArray(bspec, m1arr, index);
+        VectorMask mask2 = VectorMask.fromArray(bspec, m2arr, index);
+        vec1.lanewise(VectorOperators.UMIN, vec2, mask1)
+            .lanewise(VectorOperators.UMIN,
+                      vec1.lanewise(VectorOperators.UMAX, vec2, mask1), mask2)
+            .intoArray(byte_out, index);
+    }
+
+    @Run(test = "umin_byte_masked_diff_mask_outer")
+    public void umin_byte_masked_diff_mask_outer_runner() {
+        for (int i = 0; i < bspec.loopBound(COUNT); i += bspec.length()) {
+            umin_byte_masked_diff_mask_outer(i);
+        }
+        for (int i = 0; i < bspec.loopBound(COUNT); i++) {
+            byte a = byte_in1[i], b = byte_in2[i];
+            byte minAB = (byte)(m1arr[i] ? VectorMath.minUnsigned(a, b) : a);
+            byte maxAB = (byte)(m1arr[i] ? VectorMath.maxUnsigned(a, b) : a);
+            byte expected = (byte)(m2arr[i] ? VectorMath.minUnsigned(minAB, maxAB) : minAB);
+            Verify.checkEQ(byte_out[i], expected);
+        }
+    }
+
+    // Predicated Byte: umin(umin(a,b,m1), umax(a,b,m2), m3) => NO transform
+    @Test
+    @IR(counts = {IRNode.UMIN_VB, " 2 ", IRNode.UMAX_VB, " 1 "}, applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true"})
+    public void umin_byte_masked_all_diff_mask(int index) {
+        ByteVector vec1 = ByteVector.fromArray(bspec, byte_in1, index);
+        ByteVector vec2 = ByteVector.fromArray(bspec, byte_in2, index);
+        VectorMask mask1 = VectorMask.fromArray(bspec, m1arr, index);
+        VectorMask mask2 = VectorMask.fromArray(bspec, m2arr, index);
+        VectorMask mask3 = VectorMask.fromArray(bspec, m3arr, index);
+        vec1.lanewise(VectorOperators.UMIN, vec2, mask1)
+            .lanewise(VectorOperators.UMIN,
+                      vec1.lanewise(VectorOperators.UMAX, vec2, mask2), mask3)
+            .intoArray(byte_out, index);
+    }
+
+    @Run(test = "umin_byte_masked_all_diff_mask")
+    public void umin_byte_masked_all_diff_mask_runner() {
+        for (int i = 0; i < bspec.loopBound(COUNT); i += bspec.length()) {
+            umin_byte_masked_all_diff_mask(i);
+        }
+        for (int i = 0; i < bspec.loopBound(COUNT); i++) {
+            byte a = byte_in1[i], b = byte_in2[i];
+            byte minAB = (byte)(m1arr[i] ? VectorMath.minUnsigned(a, b) : a);
+            byte maxAB = (byte)(m2arr[i] ? VectorMath.maxUnsigned(a, b) : a);
+            byte expected = (byte)(m3arr[i] ? VectorMath.minUnsigned(minAB, maxAB) : minAB);
+            Verify.checkEQ(byte_out[i], expected);
+        }
+    }
+
+    // Predicated Byte: umax(umin(a,b,m), umax(a,b,m), m) => umax(a,b,m)
+    @Test
+    @IR(counts = {IRNode.UMIN_VB, " 0 ", IRNode.UMAX_VB, " 1 "}, applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true"})
+    public void umax_byte_masked_same_mask(int index) {
+        ByteVector vec1 = ByteVector.fromArray(bspec, byte_in1, index);
+        ByteVector vec2 = ByteVector.fromArray(bspec, byte_in2, index);
+        VectorMask m = VectorMask.fromArray(bspec, m1arr, index);
+        vec1.lanewise(VectorOperators.UMIN, vec2, m)
+            .lanewise(VectorOperators.UMAX,
+                      vec1.lanewise(VectorOperators.UMAX, vec2, m), m)
+            .intoArray(byte_out, index);
+    }
+
+    @Run(test = "umax_byte_masked_same_mask")
+    public void umax_byte_masked_same_mask_runner() {
+        for (int i = 0; i < bspec.loopBound(COUNT); i += bspec.length()) {
+            umax_byte_masked_same_mask(i);
+        }
+        for (int i = 0; i < bspec.loopBound(COUNT); i++) {
+            byte a = byte_in1[i], b = byte_in2[i];
+            byte minAB = (byte)(m1arr[i] ? VectorMath.minUnsigned(a, b) : a);
+            byte maxAB = (byte)(m1arr[i] ? VectorMath.maxUnsigned(a, b) : a);
+            byte expected = (byte)(m1arr[i] ? VectorMath.maxUnsigned(minAB, maxAB) : minAB);
+            Verify.checkEQ(byte_out[i], expected);
+        }
+    }
+
+    // Predicated Byte: umax(umin(a,b,m), umax(b,a,m), m) => umax(a,b,m)
+    @Test
+    @IR(counts = {IRNode.UMIN_VB, " 0 ", IRNode.UMAX_VB, " 1 "}, applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true"})
+    public void umax_byte_masked_flipped_inputs(int index) {
+        ByteVector vec1 = ByteVector.fromArray(bspec, byte_in1, index);
+        ByteVector vec2 = ByteVector.fromArray(bspec, byte_in2, index);
+        VectorMask m = VectorMask.fromArray(bspec, m1arr, index);
+        vec1.lanewise(VectorOperators.UMIN, vec2, m)
+            .lanewise(VectorOperators.UMAX,
+                      vec2.lanewise(VectorOperators.UMAX, vec1, m), m)
+            .intoArray(byte_out, index);
+    }
+
+    @Run(test = "umax_byte_masked_flipped_inputs")
+    public void umax_byte_masked_flipped_inputs_runner() {
+        for (int i = 0; i < bspec.loopBound(COUNT); i += bspec.length()) {
+            umax_byte_masked_flipped_inputs(i);
+        }
+        for (int i = 0; i < bspec.loopBound(COUNT); i++) {
+            byte a = byte_in1[i], b = byte_in2[i];
+            byte minAB = (byte)(m1arr[i] ? VectorMath.minUnsigned(a, b) : a);
+            byte maxBA = (byte)(m1arr[i] ? VectorMath.maxUnsigned(b, a) : b);
+            byte expected = (byte)(m1arr[i] ? VectorMath.maxUnsigned(minAB, maxBA) : minAB);
+            Verify.checkEQ(byte_out[i], expected);
+        }
+    }
+
+    // Predicated Byte: umax(umin(a,b,m1), umax(a,b,m2), m1) => NO transform
+    @Test
+    @IR(counts = {IRNode.UMIN_VB, " 1 ", IRNode.UMAX_VB, " 2 "}, applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true"})
+    public void umax_byte_masked_diff_mask_minmax(int index) {
+        ByteVector vec1 = ByteVector.fromArray(bspec, byte_in1, index);
+        ByteVector vec2 = ByteVector.fromArray(bspec, byte_in2, index);
+        VectorMask mask1 = VectorMask.fromArray(bspec, m1arr, index);
+        VectorMask mask2 = VectorMask.fromArray(bspec, m2arr, index);
+        vec1.lanewise(VectorOperators.UMIN, vec2, mask1)
+            .lanewise(VectorOperators.UMAX,
+                      vec1.lanewise(VectorOperators.UMAX, vec2, mask2), mask1)
+            .intoArray(byte_out, index);
+    }
+
+    @Run(test = "umax_byte_masked_diff_mask_minmax")
+    public void umax_byte_masked_diff_mask_minmax_runner() {
+        for (int i = 0; i < bspec.loopBound(COUNT); i += bspec.length()) {
+            umax_byte_masked_diff_mask_minmax(i);
+        }
+        for (int i = 0; i < bspec.loopBound(COUNT); i++) {
+            byte a = byte_in1[i], b = byte_in2[i];
+            byte minAB = (byte)(m1arr[i] ? VectorMath.minUnsigned(a, b) : a);
+            byte maxAB = (byte)(m2arr[i] ? VectorMath.maxUnsigned(a, b) : a);
+            byte expected = (byte)(m1arr[i] ? VectorMath.maxUnsigned(minAB, maxAB) : minAB);
+            Verify.checkEQ(byte_out[i], expected);
+        }
+    }
+
+    // Predicated Byte: umax(umin(a,b,m2), umax(a,b,m1), m1) => NO transform
+    @Test
+    @IR(counts = {IRNode.UMIN_VB, " 1 ", IRNode.UMAX_VB, " 2 "}, applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true"})
+    public void umax_byte_masked_diff_mask_minmax_swap(int index) {
+        ByteVector vec1 = ByteVector.fromArray(bspec, byte_in1, index);
+        ByteVector vec2 = ByteVector.fromArray(bspec, byte_in2, index);
+        VectorMask mask1 = VectorMask.fromArray(bspec, m1arr, index);
+        VectorMask mask2 = VectorMask.fromArray(bspec, m2arr, index);
+        vec1.lanewise(VectorOperators.UMIN, vec2, mask2)
+            .lanewise(VectorOperators.UMAX,
+                      vec1.lanewise(VectorOperators.UMAX, vec2, mask1), mask1)
+            .intoArray(byte_out, index);
+    }
+
+    @Run(test = "umax_byte_masked_diff_mask_minmax_swap")
+    public void umax_byte_masked_diff_mask_minmax_swap_runner() {
+        for (int i = 0; i < bspec.loopBound(COUNT); i += bspec.length()) {
+            umax_byte_masked_diff_mask_minmax_swap(i);
+        }
+        for (int i = 0; i < bspec.loopBound(COUNT); i++) {
+            byte a = byte_in1[i], b = byte_in2[i];
+            byte minAB = (byte)(m2arr[i] ? VectorMath.minUnsigned(a, b) : a);
+            byte maxAB = (byte)(m1arr[i] ? VectorMath.maxUnsigned(a, b) : a);
+            byte expected = (byte)(m1arr[i] ? VectorMath.maxUnsigned(minAB, maxAB) : minAB);
+            Verify.checkEQ(byte_out[i], expected);
+        }
+    }
+
+    // Predicated Byte: umax(umin(a,b,m1), umax(a,b,m1), m2) => NO transform
+    @Test
+    @IR(counts = {IRNode.UMIN_VB, " 1 ", IRNode.UMAX_VB, " 2 "}, applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true"})
+    public void umax_byte_masked_diff_mask_outer(int index) {
+        ByteVector vec1 = ByteVector.fromArray(bspec, byte_in1, index);
+        ByteVector vec2 = ByteVector.fromArray(bspec, byte_in2, index);
+        VectorMask mask1 = VectorMask.fromArray(bspec, m1arr, index);
+        VectorMask mask2 = VectorMask.fromArray(bspec, m2arr, index);
+        vec1.lanewise(VectorOperators.UMIN, vec2, mask1)
+            .lanewise(VectorOperators.UMAX,
+                      vec1.lanewise(VectorOperators.UMAX, vec2, mask1), mask2)
+            .intoArray(byte_out, index);
+    }
+
+    @Run(test = "umax_byte_masked_diff_mask_outer")
+    public void umax_byte_masked_diff_mask_outer_runner() {
+        for (int i = 0; i < bspec.loopBound(COUNT); i += bspec.length()) {
+            umax_byte_masked_diff_mask_outer(i);
+        }
+        for (int i = 0; i < bspec.loopBound(COUNT); i++) {
+            byte a = byte_in1[i], b = byte_in2[i];
+            byte minAB = (byte)(m1arr[i] ? VectorMath.minUnsigned(a, b) : a);
+            byte maxAB = (byte)(m1arr[i] ? VectorMath.maxUnsigned(a, b) : a);
+            byte expected = (byte)(m2arr[i] ? VectorMath.maxUnsigned(minAB, maxAB) : minAB);
+            Verify.checkEQ(byte_out[i], expected);
+        }
+    }
+
+    // Predicated Byte: umax(umin(a,b,m1), umax(a,b,m2), m3) => NO transform
+    @Test
+    @IR(counts = {IRNode.UMIN_VB, " 1 ", IRNode.UMAX_VB, " 2 "}, applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true"})
+    public void umax_byte_masked_all_diff_mask(int index) {
+        ByteVector vec1 = ByteVector.fromArray(bspec, byte_in1, index);
+        ByteVector vec2 = ByteVector.fromArray(bspec, byte_in2, index);
+        VectorMask mask1 = VectorMask.fromArray(bspec, m1arr, index);
+        VectorMask mask2 = VectorMask.fromArray(bspec, m2arr, index);
+        VectorMask mask3 = VectorMask.fromArray(bspec, m3arr, index);
+        vec1.lanewise(VectorOperators.UMIN, vec2, mask1)
+            .lanewise(VectorOperators.UMAX,
+                      vec1.lanewise(VectorOperators.UMAX, vec2, mask2), mask3)
+            .intoArray(byte_out, index);
+    }
+
+    @Run(test = "umax_byte_masked_all_diff_mask")
+    public void umax_byte_masked_all_diff_mask_runner() {
+        for (int i = 0; i < bspec.loopBound(COUNT); i += bspec.length()) {
+            umax_byte_masked_all_diff_mask(i);
+        }
+        for (int i = 0; i < bspec.loopBound(COUNT); i++) {
+            byte a = byte_in1[i], b = byte_in2[i];
+            byte minAB = (byte)(m1arr[i] ? VectorMath.minUnsigned(a, b) : a);
+            byte maxAB = (byte)(m2arr[i] ? VectorMath.maxUnsigned(a, b) : a);
+            byte expected = (byte)(m3arr[i] ? VectorMath.maxUnsigned(minAB, maxAB) : minAB);
+            Verify.checkEQ(byte_out[i], expected);
+        }
+    }
+
+    // Predicated Short: umin(umin(a,b,m), umax(a,b,m), m) => umin(a,b,m)
+    @Test
+    @IR(counts = {IRNode.UMIN_VS, " 1 ", IRNode.UMAX_VS, " 0 "}, applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true"})
+    public void umin_short_masked_same_mask(int index) {
+        ShortVector vec1 = ShortVector.fromArray(sspec, short_in1, index);
+        ShortVector vec2 = ShortVector.fromArray(sspec, short_in2, index);
+        VectorMask m = VectorMask.fromArray(sspec, m1arr, index);
+        vec1.lanewise(VectorOperators.UMIN, vec2, m)
+            .lanewise(VectorOperators.UMIN,
+                      vec1.lanewise(VectorOperators.UMAX, vec2, m), m)
+            .intoArray(short_out, index);
+    }
+
+    @Run(test = "umin_short_masked_same_mask")
+    public void umin_short_masked_same_mask_runner() {
+        for (int i = 0; i < sspec.loopBound(COUNT); i += sspec.length()) {
+            umin_short_masked_same_mask(i);
+        }
+        for (int i = 0; i < sspec.loopBound(COUNT); i++) {
+            short a = short_in1[i], b = short_in2[i];
+            short minAB = (short)(m1arr[i] ? VectorMath.minUnsigned(a, b) : a);
+            short maxAB = (short)(m1arr[i] ? VectorMath.maxUnsigned(a, b) : a);
+            short expected = (short)(m1arr[i] ? VectorMath.minUnsigned(minAB, maxAB) : minAB);
+            Verify.checkEQ(short_out[i], expected);
+        }
+    }
+
+    // Predicated Short: umin(umin(a,b,m), umax(b,a,m), m) => umin(a,b,m)
+    @Test
+    @IR(counts = {IRNode.UMIN_VS, " 1 ", IRNode.UMAX_VS, " 0 "}, applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true"})
+    public void umin_short_masked_flipped_inputs(int index) {
+        ShortVector vec1 = ShortVector.fromArray(sspec, short_in1, index);
+        ShortVector vec2 = ShortVector.fromArray(sspec, short_in2, index);
+        VectorMask m = VectorMask.fromArray(sspec, m1arr, index);
+        vec1.lanewise(VectorOperators.UMIN, vec2, m)
+            .lanewise(VectorOperators.UMIN,
+                      vec2.lanewise(VectorOperators.UMAX, vec1, m), m)
+            .intoArray(short_out, index);
+    }
+
+    @Run(test = "umin_short_masked_flipped_inputs")
+    public void umin_short_masked_flipped_inputs_runner() {
+        for (int i = 0; i < sspec.loopBound(COUNT); i += sspec.length()) {
+            umin_short_masked_flipped_inputs(i);
+        }
+        for (int i = 0; i < sspec.loopBound(COUNT); i++) {
+            short a = short_in1[i], b = short_in2[i];
+            short minAB = (short)(m1arr[i] ? VectorMath.minUnsigned(a, b) : a);
+            short maxBA = (short)(m1arr[i] ? VectorMath.maxUnsigned(b, a) : b);
+            short expected = (short)(m1arr[i] ? VectorMath.minUnsigned(minAB, maxBA) : minAB);
+            Verify.checkEQ(short_out[i], expected);
+        }
+    }
+
+    // Predicated Short: umin(umin(a,b,m1), umax(a,b,m2), m1) => NO transform
+    @Test
+    @IR(counts = {IRNode.UMIN_VS, " 2 ", IRNode.UMAX_VS, " 1 "}, applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true"})
+    public void umin_short_masked_diff_mask_minmax(int index) {
+        ShortVector vec1 = ShortVector.fromArray(sspec, short_in1, index);
+        ShortVector vec2 = ShortVector.fromArray(sspec, short_in2, index);
+        VectorMask mask1 = VectorMask.fromArray(sspec, m1arr, index);
+        VectorMask mask2 = VectorMask.fromArray(sspec, m2arr, index);
+        vec1.lanewise(VectorOperators.UMIN, vec2, mask1)
+            .lanewise(VectorOperators.UMIN,
+                      vec1.lanewise(VectorOperators.UMAX, vec2, mask2), mask1)
+            .intoArray(short_out, index);
+    }
+
+    @Run(test = "umin_short_masked_diff_mask_minmax")
+    public void umin_short_masked_diff_mask_minmax_runner() {
+        for (int i = 0; i < sspec.loopBound(COUNT); i += sspec.length()) {
+            umin_short_masked_diff_mask_minmax(i);
+        }
+        for (int i = 0; i < sspec.loopBound(COUNT); i++) {
+            short a = short_in1[i], b = short_in2[i];
+            short minAB = (short)(m1arr[i] ? VectorMath.minUnsigned(a, b) : a);
+            short maxAB = (short)(m2arr[i] ? VectorMath.maxUnsigned(a, b) : a);
+            short expected = (short)(m1arr[i] ? VectorMath.minUnsigned(minAB, maxAB) : minAB);
+            Verify.checkEQ(short_out[i], expected);
+        }
+    }
+
+    // Predicated Short: umin(umin(a,b,m2), umax(a,b,m1), m1) => NO transform
+    @Test
+    @IR(counts = {IRNode.UMIN_VS, " 2 ", IRNode.UMAX_VS, " 1 "}, applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true"})
+    public void umin_short_masked_diff_mask_minmax_swap(int index) {
+        ShortVector vec1 = ShortVector.fromArray(sspec, short_in1, index);
+        ShortVector vec2 = ShortVector.fromArray(sspec, short_in2, index);
+        VectorMask mask1 = VectorMask.fromArray(sspec, m1arr, index);
+        VectorMask mask2 = VectorMask.fromArray(sspec, m2arr, index);
+        vec1.lanewise(VectorOperators.UMIN, vec2, mask2)
+            .lanewise(VectorOperators.UMIN,
+                      vec1.lanewise(VectorOperators.UMAX, vec2, mask1), mask1)
+            .intoArray(short_out, index);
+    }
+
+    @Run(test = "umin_short_masked_diff_mask_minmax_swap")
+    public void umin_short_masked_diff_mask_minmax_swap_runner() {
+        for (int i = 0; i < sspec.loopBound(COUNT); i += sspec.length()) {
+            umin_short_masked_diff_mask_minmax_swap(i);
+        }
+        for (int i = 0; i < sspec.loopBound(COUNT); i++) {
+            short a = short_in1[i], b = short_in2[i];
+            short minAB = (short)(m2arr[i] ? VectorMath.minUnsigned(a, b) : a);
+            short maxAB = (short)(m1arr[i] ? VectorMath.maxUnsigned(a, b) : a);
+            short expected = (short)(m1arr[i] ? VectorMath.minUnsigned(minAB, maxAB) : minAB);
+            Verify.checkEQ(short_out[i], expected);
+        }
+    }
+
+    // Predicated Short: umin(umin(a,b,m1), umax(a,b,m1), m2) => NO transform
+    @Test
+    @IR(counts = {IRNode.UMIN_VS, " 2 ", IRNode.UMAX_VS, " 1 "}, applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true"})
+    public void umin_short_masked_diff_mask_outer(int index) {
+        ShortVector vec1 = ShortVector.fromArray(sspec, short_in1, index);
+        ShortVector vec2 = ShortVector.fromArray(sspec, short_in2, index);
+        VectorMask mask1 = VectorMask.fromArray(sspec, m1arr, index);
+        VectorMask mask2 = VectorMask.fromArray(sspec, m2arr, index);
+        vec1.lanewise(VectorOperators.UMIN, vec2, mask1)
+            .lanewise(VectorOperators.UMIN,
+                      vec1.lanewise(VectorOperators.UMAX, vec2, mask1), mask2)
+            .intoArray(short_out, index);
+    }
+
+    @Run(test = "umin_short_masked_diff_mask_outer")
+    public void umin_short_masked_diff_mask_outer_runner() {
+        for (int i = 0; i < sspec.loopBound(COUNT); i += sspec.length()) {
+            umin_short_masked_diff_mask_outer(i);
+        }
+        for (int i = 0; i < sspec.loopBound(COUNT); i++) {
+            short a = short_in1[i], b = short_in2[i];
+            short minAB = (short)(m1arr[i] ? VectorMath.minUnsigned(a, b) : a);
+            short maxAB = (short)(m1arr[i] ? VectorMath.maxUnsigned(a, b) : a);
+            short expected = (short)(m2arr[i] ? VectorMath.minUnsigned(minAB, maxAB) : minAB);
+            Verify.checkEQ(short_out[i], expected);
+        }
+    }
+
+    // Predicated Short: umin(umin(a,b,m1), umax(a,b,m2), m3) => NO transform
+    @Test
+    @IR(counts = {IRNode.UMIN_VS, " 2 ", IRNode.UMAX_VS, " 1 "}, applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true"})
+    public void umin_short_masked_all_diff_mask(int index) {
+        ShortVector vec1 = ShortVector.fromArray(sspec, short_in1, index);
+        ShortVector vec2 = ShortVector.fromArray(sspec, short_in2, index);
+        VectorMask mask1 = VectorMask.fromArray(sspec, m1arr, index);
+        VectorMask mask2 = VectorMask.fromArray(sspec, m2arr, index);
+        VectorMask mask3 = VectorMask.fromArray(sspec, m3arr, index);
+        vec1.lanewise(VectorOperators.UMIN, vec2, mask1)
+            .lanewise(VectorOperators.UMIN,
+                      vec1.lanewise(VectorOperators.UMAX, vec2, mask2), mask3)
+            .intoArray(short_out, index);
+    }
+
+    @Run(test = "umin_short_masked_all_diff_mask")
+    public void umin_short_masked_all_diff_mask_runner() {
+        for (int i = 0; i < sspec.loopBound(COUNT); i += sspec.length()) {
+            umin_short_masked_all_diff_mask(i);
+        }
+        for (int i = 0; i < sspec.loopBound(COUNT); i++) {
+            short a = short_in1[i], b = short_in2[i];
+            short minAB = (short)(m1arr[i] ? VectorMath.minUnsigned(a, b) : a);
+            short maxAB = (short)(m2arr[i] ? VectorMath.maxUnsigned(a, b) : a);
+            short expected = (short)(m3arr[i] ? VectorMath.minUnsigned(minAB, maxAB) : minAB);
+            Verify.checkEQ(short_out[i], expected);
+        }
+    }
+
+    // Predicated Short: umax(umin(a,b,m), umax(a,b,m), m) => umax(a,b,m)
+    @Test
+    @IR(counts = {IRNode.UMIN_VS, " 0 ", IRNode.UMAX_VS, " 1 "}, applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true"})
+    public void umax_short_masked_same_mask(int index) {
+        ShortVector vec1 = ShortVector.fromArray(sspec, short_in1, index);
+        ShortVector vec2 = ShortVector.fromArray(sspec, short_in2, index);
+        VectorMask m = VectorMask.fromArray(sspec, m1arr, index);
+        vec1.lanewise(VectorOperators.UMIN, vec2, m)
+            .lanewise(VectorOperators.UMAX,
+                      vec1.lanewise(VectorOperators.UMAX, vec2, m), m)
+            .intoArray(short_out, index);
+    }
+
+    @Run(test = "umax_short_masked_same_mask")
+    public void umax_short_masked_same_mask_runner() {
+        for (int i = 0; i < sspec.loopBound(COUNT); i += sspec.length()) {
+            umax_short_masked_same_mask(i);
+        }
+        for (int i = 0; i < sspec.loopBound(COUNT); i++) {
+            short a = short_in1[i], b = short_in2[i];
+            short minAB = (short)(m1arr[i] ? VectorMath.minUnsigned(a, b) : a);
+            short maxAB = (short)(m1arr[i] ? VectorMath.maxUnsigned(a, b) : a);
+            short expected = (short)(m1arr[i] ? VectorMath.maxUnsigned(minAB, maxAB) : minAB);
+            Verify.checkEQ(short_out[i], expected);
+        }
+    }
+
+    // Predicated Short: umax(umin(a,b,m), umax(b,a,m), m) => umax(a,b,m)
+    @Test
+    @IR(counts = {IRNode.UMIN_VS, " 0 ", IRNode.UMAX_VS, " 1 "}, applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true"})
+    public void umax_short_masked_flipped_inputs(int index) {
+        ShortVector vec1 = ShortVector.fromArray(sspec, short_in1, index);
+        ShortVector vec2 = ShortVector.fromArray(sspec, short_in2, index);
+        VectorMask m = VectorMask.fromArray(sspec, m1arr, index);
+        vec1.lanewise(VectorOperators.UMIN, vec2, m)
+            .lanewise(VectorOperators.UMAX,
+                      vec2.lanewise(VectorOperators.UMAX, vec1, m), m)
+            .intoArray(short_out, index);
+    }
+
+    @Run(test = "umax_short_masked_flipped_inputs")
+    public void umax_short_masked_flipped_inputs_runner() {
+        for (int i = 0; i < sspec.loopBound(COUNT); i += sspec.length()) {
+            umax_short_masked_flipped_inputs(i);
+        }
+        for (int i = 0; i < sspec.loopBound(COUNT); i++) {
+            short a = short_in1[i], b = short_in2[i];
+            short minAB = (short)(m1arr[i] ? VectorMath.minUnsigned(a, b) : a);
+            short maxBA = (short)(m1arr[i] ? VectorMath.maxUnsigned(b, a) : b);
+            short expected = (short)(m1arr[i] ? VectorMath.maxUnsigned(minAB, maxBA) : minAB);
+            Verify.checkEQ(short_out[i], expected);
+        }
+    }
+
+    // Predicated Short: umax(umin(a,b,m1), umax(a,b,m2), m1) => NO transform
+    @Test
+    @IR(counts = {IRNode.UMIN_VS, " 1 ", IRNode.UMAX_VS, " 2 "}, applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true"})
+    public void umax_short_masked_diff_mask_minmax(int index) {
+        ShortVector vec1 = ShortVector.fromArray(sspec, short_in1, index);
+        ShortVector vec2 = ShortVector.fromArray(sspec, short_in2, index);
+        VectorMask mask1 = VectorMask.fromArray(sspec, m1arr, index);
+        VectorMask mask2 = VectorMask.fromArray(sspec, m2arr, index);
+        vec1.lanewise(VectorOperators.UMIN, vec2, mask1)
+            .lanewise(VectorOperators.UMAX,
+                      vec1.lanewise(VectorOperators.UMAX, vec2, mask2), mask1)
+            .intoArray(short_out, index);
+    }
+
+    @Run(test = "umax_short_masked_diff_mask_minmax")
+    public void umax_short_masked_diff_mask_minmax_runner() {
+        for (int i = 0; i < sspec.loopBound(COUNT); i += sspec.length()) {
+            umax_short_masked_diff_mask_minmax(i);
+        }
+        for (int i = 0; i < sspec.loopBound(COUNT); i++) {
+            short a = short_in1[i], b = short_in2[i];
+            short minAB = (short)(m1arr[i] ? VectorMath.minUnsigned(a, b) : a);
+            short maxAB = (short)(m2arr[i] ? VectorMath.maxUnsigned(a, b) : a);
+            short expected = (short)(m1arr[i] ? VectorMath.maxUnsigned(minAB, maxAB) : minAB);
+            Verify.checkEQ(short_out[i], expected);
+        }
+    }
+
+    // Predicated Short: umax(umin(a,b,m2), umax(a,b,m1), m1) => NO transform
+    @Test
+    @IR(counts = {IRNode.UMIN_VS, " 1 ", IRNode.UMAX_VS, " 2 "}, applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true"})
+    public void umax_short_masked_diff_mask_minmax_swap(int index) {
+        ShortVector vec1 = ShortVector.fromArray(sspec, short_in1, index);
+        ShortVector vec2 = ShortVector.fromArray(sspec, short_in2, index);
+        VectorMask mask1 = VectorMask.fromArray(sspec, m1arr, index);
+        VectorMask mask2 = VectorMask.fromArray(sspec, m2arr, index);
+        vec1.lanewise(VectorOperators.UMIN, vec2, mask2)
+            .lanewise(VectorOperators.UMAX,
+                      vec1.lanewise(VectorOperators.UMAX, vec2, mask1), mask1)
+            .intoArray(short_out, index);
+    }
+
+    @Run(test = "umax_short_masked_diff_mask_minmax_swap")
+    public void umax_short_masked_diff_mask_minmax_swap_runner() {
+        for (int i = 0; i < sspec.loopBound(COUNT); i += sspec.length()) {
+            umax_short_masked_diff_mask_minmax_swap(i);
+        }
+        for (int i = 0; i < sspec.loopBound(COUNT); i++) {
+            short a = short_in1[i], b = short_in2[i];
+            short minAB = (short)(m2arr[i] ? VectorMath.minUnsigned(a, b) : a);
+            short maxAB = (short)(m1arr[i] ? VectorMath.maxUnsigned(a, b) : a);
+            short expected = (short)(m1arr[i] ? VectorMath.maxUnsigned(minAB, maxAB) : minAB);
+            Verify.checkEQ(short_out[i], expected);
+        }
+    }
+
+    // Predicated Short: umax(umin(a,b,m1), umax(a,b,m1), m2) => NO transform
+    @Test
+    @IR(counts = {IRNode.UMIN_VS, " 1 ", IRNode.UMAX_VS, " 2 "}, applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true"})
+    public void umax_short_masked_diff_mask_outer(int index) {
+        ShortVector vec1 = ShortVector.fromArray(sspec, short_in1, index);
+        ShortVector vec2 = ShortVector.fromArray(sspec, short_in2, index);
+        VectorMask mask1 = VectorMask.fromArray(sspec, m1arr, index);
+        VectorMask mask2 = VectorMask.fromArray(sspec, m2arr, index);
+        vec1.lanewise(VectorOperators.UMIN, vec2, mask1)
+            .lanewise(VectorOperators.UMAX,
+                      vec1.lanewise(VectorOperators.UMAX, vec2, mask1), mask2)
+            .intoArray(short_out, index);
+    }
+
+    @Run(test = "umax_short_masked_diff_mask_outer")
+    public void umax_short_masked_diff_mask_outer_runner() {
+        for (int i = 0; i < sspec.loopBound(COUNT); i += sspec.length()) {
+            umax_short_masked_diff_mask_outer(i);
+        }
+        for (int i = 0; i < sspec.loopBound(COUNT); i++) {
+            short a = short_in1[i], b = short_in2[i];
+            short minAB = (short)(m1arr[i] ? VectorMath.minUnsigned(a, b) : a);
+            short maxAB = (short)(m1arr[i] ? VectorMath.maxUnsigned(a, b) : a);
+            short expected = (short)(m2arr[i] ? VectorMath.maxUnsigned(minAB, maxAB) : minAB);
+            Verify.checkEQ(short_out[i], expected);
+        }
+    }
+
+    // Predicated Short: umax(umin(a,b,m1), umax(a,b,m2), m3) => NO transform
+    @Test
+    @IR(counts = {IRNode.UMIN_VS, " 1 ", IRNode.UMAX_VS, " 2 "}, applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true"})
+    public void umax_short_masked_all_diff_mask(int index) {
+        ShortVector vec1 = ShortVector.fromArray(sspec, short_in1, index);
+        ShortVector vec2 = ShortVector.fromArray(sspec, short_in2, index);
+        VectorMask mask1 = VectorMask.fromArray(sspec, m1arr, index);
+        VectorMask mask2 = VectorMask.fromArray(sspec, m2arr, index);
+        VectorMask mask3 = VectorMask.fromArray(sspec, m3arr, index);
+        vec1.lanewise(VectorOperators.UMIN, vec2, mask1)
+            .lanewise(VectorOperators.UMAX,
+                      vec1.lanewise(VectorOperators.UMAX, vec2, mask2), mask3)
+            .intoArray(short_out, index);
+    }
+
+    @Run(test = "umax_short_masked_all_diff_mask")
+    public void umax_short_masked_all_diff_mask_runner() {
+        for (int i = 0; i < sspec.loopBound(COUNT); i += sspec.length()) {
+            umax_short_masked_all_diff_mask(i);
+        }
+        for (int i = 0; i < sspec.loopBound(COUNT); i++) {
+            short a = short_in1[i], b = short_in2[i];
+            short minAB = (short)(m1arr[i] ? VectorMath.minUnsigned(a, b) : a);
+            short maxAB = (short)(m2arr[i] ? VectorMath.maxUnsigned(a, b) : a);
+            short expected = (short)(m3arr[i] ? VectorMath.maxUnsigned(minAB, maxAB) : minAB);
+            Verify.checkEQ(short_out[i], expected);
+        }
+    }
+
+    // Predicated Long: umin(umin(a,b,m), umax(a,b,m), m) => umin(a,b,m)
+    @Test
+    @IR(counts = {IRNode.UMIN_VL, " 1 ", IRNode.UMAX_VL, " 0 "}, applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true"})
+    public void umin_long_masked_same_mask(int index) {
+        LongVector vec1 = LongVector.fromArray(lspec, long_in1, index);
+        LongVector vec2 = LongVector.fromArray(lspec, long_in2, index);
+        VectorMask m = VectorMask.fromArray(lspec, m1arr, index);
+        vec1.lanewise(VectorOperators.UMIN, vec2, m)
+            .lanewise(VectorOperators.UMIN,
+                      vec1.lanewise(VectorOperators.UMAX, vec2, m), m)
+            .intoArray(long_out, index);
+    }
+
+    @Run(test = "umin_long_masked_same_mask")
+    public void umin_long_masked_same_mask_runner() {
+        for (int i = 0; i < lspec.loopBound(COUNT); i += lspec.length()) {
+            umin_long_masked_same_mask(i);
+        }
+        for (int i = 0; i < lspec.loopBound(COUNT); i++) {
+            long a = long_in1[i], b = long_in2[i];
+            long minAB = m1arr[i] ? VectorMath.minUnsigned(a, b) : a;
+            long maxAB = m1arr[i] ? VectorMath.maxUnsigned(a, b) : a;
+            long expected = m1arr[i] ? VectorMath.minUnsigned(minAB, maxAB) : minAB;
+            Verify.checkEQ(long_out[i], expected);
+        }
+    }
+
+    // Predicated Long: umin(umin(a,b,m), umax(b,a,m), m) => umin(a,b,m)
+    @Test
+    @IR(counts = {IRNode.UMIN_VL, " 1 ", IRNode.UMAX_VL, " 0 "}, applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true"})
+    public void umin_long_masked_flipped_inputs(int index) {
+        LongVector vec1 = LongVector.fromArray(lspec, long_in1, index);
+        LongVector vec2 = LongVector.fromArray(lspec, long_in2, index);
+        VectorMask m = VectorMask.fromArray(lspec, m1arr, index);
+        vec1.lanewise(VectorOperators.UMIN, vec2, m)
+            .lanewise(VectorOperators.UMIN,
+                      vec2.lanewise(VectorOperators.UMAX, vec1, m), m)
+            .intoArray(long_out, index);
+    }
+
+    @Run(test = "umin_long_masked_flipped_inputs")
+    public void umin_long_masked_flipped_inputs_runner() {
+        for (int i = 0; i < lspec.loopBound(COUNT); i += lspec.length()) {
+            umin_long_masked_flipped_inputs(i);
+        }
+        for (int i = 0; i < lspec.loopBound(COUNT); i++) {
+            long a = long_in1[i], b = long_in2[i];
+            long minAB = m1arr[i] ? VectorMath.minUnsigned(a, b) : a;
+            long maxBA = m1arr[i] ? VectorMath.maxUnsigned(b, a) : b;
+            long expected = m1arr[i] ? VectorMath.minUnsigned(minAB, maxBA) : minAB;
+            Verify.checkEQ(long_out[i], expected);
+        }
+    }
+
+    // Predicated Long: umin(umin(a,b,m1), umax(a,b,m2), m1) => NO transform
+    @Test
+    @IR(counts = {IRNode.UMIN_VL, " 2 ", IRNode.UMAX_VL, " 1 "}, applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true"})
+    public void umin_long_masked_diff_mask_minmax(int index) {
+        LongVector vec1 = LongVector.fromArray(lspec, long_in1, index);
+        LongVector vec2 = LongVector.fromArray(lspec, long_in2, index);
+        VectorMask mask1 = VectorMask.fromArray(lspec, m1arr, index);
+        VectorMask mask2 = VectorMask.fromArray(lspec, m2arr, index);
+        vec1.lanewise(VectorOperators.UMIN, vec2, mask1)
+            .lanewise(VectorOperators.UMIN,
+                      vec1.lanewise(VectorOperators.UMAX, vec2, mask2), mask1)
+            .intoArray(long_out, index);
+    }
+
+    @Run(test = "umin_long_masked_diff_mask_minmax")
+    public void umin_long_masked_diff_mask_minmax_runner() {
+        for (int i = 0; i < lspec.loopBound(COUNT); i += lspec.length()) {
+            umin_long_masked_diff_mask_minmax(i);
+        }
+        for (int i = 0; i < lspec.loopBound(COUNT); i++) {
+            long a = long_in1[i], b = long_in2[i];
+            long minAB = m1arr[i] ? VectorMath.minUnsigned(a, b) : a;
+            long maxAB = m2arr[i] ? VectorMath.maxUnsigned(a, b) : a;
+            long expected = m1arr[i] ? VectorMath.minUnsigned(minAB, maxAB) : minAB;
+            Verify.checkEQ(long_out[i], expected);
+        }
+    }
+
+    // Predicated Long: umin(umin(a,b,m2), umax(a,b,m1), m1) => NO transform
+    @Test
+    @IR(counts = {IRNode.UMIN_VL, " 2 ", IRNode.UMAX_VL, " 1 "}, applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true"})
+    public void umin_long_masked_diff_mask_minmax_swap(int index) {
+        LongVector vec1 = LongVector.fromArray(lspec, long_in1, index);
+        LongVector vec2 = LongVector.fromArray(lspec, long_in2, index);
+        VectorMask mask1 = VectorMask.fromArray(lspec, m1arr, index);
+        VectorMask mask2 = VectorMask.fromArray(lspec, m2arr, index);
+        vec1.lanewise(VectorOperators.UMIN, vec2, mask2)
+            .lanewise(VectorOperators.UMIN,
+                      vec1.lanewise(VectorOperators.UMAX, vec2, mask1), mask1)
+            .intoArray(long_out, index);
+    }
+
+    @Run(test = "umin_long_masked_diff_mask_minmax_swap")
+    public void umin_long_masked_diff_mask_minmax_swap_runner() {
+        for (int i = 0; i < lspec.loopBound(COUNT); i += lspec.length()) {
+            umin_long_masked_diff_mask_minmax_swap(i);
+        }
+        for (int i = 0; i < lspec.loopBound(COUNT); i++) {
+            long a = long_in1[i], b = long_in2[i];
+            long minAB = m2arr[i] ? VectorMath.minUnsigned(a, b) : a;
+            long maxAB = m1arr[i] ? VectorMath.maxUnsigned(a, b) : a;
+            long expected = m1arr[i] ? VectorMath.minUnsigned(minAB, maxAB) : minAB;
+            Verify.checkEQ(long_out[i], expected);
+        }
+    }
+
+    // Predicated Long: umin(umin(a,b,m1), umax(a,b,m1), m2) => NO transform
+    @Test
+    @IR(counts = {IRNode.UMIN_VL, " 2 ", IRNode.UMAX_VL, " 1 "}, applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true"})
+    public void umin_long_masked_diff_mask_outer(int index) {
+        LongVector vec1 = LongVector.fromArray(lspec, long_in1, index);
+        LongVector vec2 = LongVector.fromArray(lspec, long_in2, index);
+        VectorMask mask1 = VectorMask.fromArray(lspec, m1arr, index);
+        VectorMask mask2 = VectorMask.fromArray(lspec, m2arr, index);
+        vec1.lanewise(VectorOperators.UMIN, vec2, mask1)
+            .lanewise(VectorOperators.UMIN,
+                      vec1.lanewise(VectorOperators.UMAX, vec2, mask1), mask2)
+            .intoArray(long_out, index);
+    }
+
+    @Run(test = "umin_long_masked_diff_mask_outer")
+    public void umin_long_masked_diff_mask_outer_runner() {
+        for (int i = 0; i < lspec.loopBound(COUNT); i += lspec.length()) {
+            umin_long_masked_diff_mask_outer(i);
+        }
+        for (int i = 0; i < lspec.loopBound(COUNT); i++) {
+            long a = long_in1[i], b = long_in2[i];
+            long minAB = m1arr[i] ? VectorMath.minUnsigned(a, b) : a;
+            long maxAB = m1arr[i] ? VectorMath.maxUnsigned(a, b) : a;
+            long expected = m2arr[i] ? VectorMath.minUnsigned(minAB, maxAB) : minAB;
+            Verify.checkEQ(long_out[i], expected);
+        }
+    }
+
+    // Predicated Long: umin(umin(a,b,m1), umax(a,b,m2), m3) => NO transform
+    @Test
+    @IR(counts = {IRNode.UMIN_VL, " 2 ", IRNode.UMAX_VL, " 1 "}, applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true"})
+    public void umin_long_masked_all_diff_mask(int index) {
+        LongVector vec1 = LongVector.fromArray(lspec, long_in1, index);
+        LongVector vec2 = LongVector.fromArray(lspec, long_in2, index);
+        VectorMask mask1 = VectorMask.fromArray(lspec, m1arr, index);
+        VectorMask mask2 = VectorMask.fromArray(lspec, m2arr, index);
+        VectorMask mask3 = VectorMask.fromArray(lspec, m3arr, index);
+        vec1.lanewise(VectorOperators.UMIN, vec2, mask1)
+            .lanewise(VectorOperators.UMIN,
+                      vec1.lanewise(VectorOperators.UMAX, vec2, mask2), mask3)
+            .intoArray(long_out, index);
+    }
+
+    @Run(test = "umin_long_masked_all_diff_mask")
+    public void umin_long_masked_all_diff_mask_runner() {
+        for (int i = 0; i < lspec.loopBound(COUNT); i += lspec.length()) {
+            umin_long_masked_all_diff_mask(i);
+        }
+        for (int i = 0; i < lspec.loopBound(COUNT); i++) {
+            long a = long_in1[i], b = long_in2[i];
+            long minAB = m1arr[i] ? VectorMath.minUnsigned(a, b) : a;
+            long maxAB = m2arr[i] ? VectorMath.maxUnsigned(a, b) : a;
+            long expected = m3arr[i] ? VectorMath.minUnsigned(minAB, maxAB) : minAB;
+            Verify.checkEQ(long_out[i], expected);
+        }
+    }
+
+    // Predicated Long: umax(umin(a,b,m), umax(a,b,m), m) => umax(a,b,m)
+    @Test
+    @IR(counts = {IRNode.UMIN_VL, " 0 ", IRNode.UMAX_VL, " 1 "}, applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true"})
+    public void umax_long_masked_same_mask(int index) {
+        LongVector vec1 = LongVector.fromArray(lspec, long_in1, index);
+        LongVector vec2 = LongVector.fromArray(lspec, long_in2, index);
+        VectorMask m = VectorMask.fromArray(lspec, m1arr, index);
+        vec1.lanewise(VectorOperators.UMIN, vec2, m)
+            .lanewise(VectorOperators.UMAX,
+                      vec1.lanewise(VectorOperators.UMAX, vec2, m), m)
+            .intoArray(long_out, index);
+    }
+
+    @Run(test = "umax_long_masked_same_mask")
+    public void umax_long_masked_same_mask_runner() {
+        for (int i = 0; i < lspec.loopBound(COUNT); i += lspec.length()) {
+            umax_long_masked_same_mask(i);
+        }
+        for (int i = 0; i < lspec.loopBound(COUNT); i++) {
+            long a = long_in1[i], b = long_in2[i];
+            long minAB = m1arr[i] ? VectorMath.minUnsigned(a, b) : a;
+            long maxAB = m1arr[i] ? VectorMath.maxUnsigned(a, b) : a;
+            long expected = m1arr[i] ? VectorMath.maxUnsigned(minAB, maxAB) : minAB;
+            Verify.checkEQ(long_out[i], expected);
+        }
+    }
+
+    // Predicated Long: umax(umin(a,b,m), umax(b,a,m), m) => umax(a,b,m)
+    @Test
+    @IR(counts = {IRNode.UMIN_VL, " 0 ", IRNode.UMAX_VL, " 1 "}, applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true"})
+    public void umax_long_masked_flipped_inputs(int index) {
+        LongVector vec1 = LongVector.fromArray(lspec, long_in1, index);
+        LongVector vec2 = LongVector.fromArray(lspec, long_in2, index);
+        VectorMask m = VectorMask.fromArray(lspec, m1arr, index);
+        vec1.lanewise(VectorOperators.UMIN, vec2, m)
+            .lanewise(VectorOperators.UMAX,
+                      vec2.lanewise(VectorOperators.UMAX, vec1, m), m)
+            .intoArray(long_out, index);
+    }
+
+    @Run(test = "umax_long_masked_flipped_inputs")
+    public void umax_long_masked_flipped_inputs_runner() {
+        for (int i = 0; i < lspec.loopBound(COUNT); i += lspec.length()) {
+            umax_long_masked_flipped_inputs(i);
+        }
+        for (int i = 0; i < lspec.loopBound(COUNT); i++) {
+            long a = long_in1[i], b = long_in2[i];
+            long minAB = m1arr[i] ? VectorMath.minUnsigned(a, b) : a;
+            long maxBA = m1arr[i] ? VectorMath.maxUnsigned(b, a) : b;
+            long expected = m1arr[i] ? VectorMath.maxUnsigned(minAB, maxBA) : minAB;
+            Verify.checkEQ(long_out[i], expected);
+        }
+    }
+
+    // Predicated Long: umax(umin(a,b,m1), umax(a,b,m2), m1) => NO transform
+    @Test
+    @IR(counts = {IRNode.UMIN_VL, " 1 ", IRNode.UMAX_VL, " 2 "}, applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true"})
+    public void umax_long_masked_diff_mask_minmax(int index) {
+        LongVector vec1 = LongVector.fromArray(lspec, long_in1, index);
+        LongVector vec2 = LongVector.fromArray(lspec, long_in2, index);
+        VectorMask mask1 = VectorMask.fromArray(lspec, m1arr, index);
+        VectorMask mask2 = VectorMask.fromArray(lspec, m2arr, index);
+        vec1.lanewise(VectorOperators.UMIN, vec2, mask1)
+            .lanewise(VectorOperators.UMAX,
+                      vec1.lanewise(VectorOperators.UMAX, vec2, mask2), mask1)
+            .intoArray(long_out, index);
+    }
+
+    @Run(test = "umax_long_masked_diff_mask_minmax")
+    public void umax_long_masked_diff_mask_minmax_runner() {
+        for (int i = 0; i < lspec.loopBound(COUNT); i += lspec.length()) {
+            umax_long_masked_diff_mask_minmax(i);
+        }
+        for (int i = 0; i < lspec.loopBound(COUNT); i++) {
+            long a = long_in1[i], b = long_in2[i];
+            long minAB = m1arr[i] ? VectorMath.minUnsigned(a, b) : a;
+            long maxAB = m2arr[i] ? VectorMath.maxUnsigned(a, b) : a;
+            long expected = m1arr[i] ? VectorMath.maxUnsigned(minAB, maxAB) : minAB;
+            Verify.checkEQ(long_out[i], expected);
+        }
+    }
+
+    // Predicated Long: umax(umin(a,b,m2), umax(a,b,m1), m1) => NO transform
+    @Test
+    @IR(counts = {IRNode.UMIN_VL, " 1 ", IRNode.UMAX_VL, " 2 "}, applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true"})
+    public void umax_long_masked_diff_mask_minmax_swap(int index) {
+        LongVector vec1 = LongVector.fromArray(lspec, long_in1, index);
+        LongVector vec2 = LongVector.fromArray(lspec, long_in2, index);
+        VectorMask mask1 = VectorMask.fromArray(lspec, m1arr, index);
+        VectorMask mask2 = VectorMask.fromArray(lspec, m2arr, index);
+        vec1.lanewise(VectorOperators.UMIN, vec2, mask2)
+            .lanewise(VectorOperators.UMAX,
+                      vec1.lanewise(VectorOperators.UMAX, vec2, mask1), mask1)
+            .intoArray(long_out, index);
+    }
+
+    @Run(test = "umax_long_masked_diff_mask_minmax_swap")
+    public void umax_long_masked_diff_mask_minmax_swap_runner() {
+        for (int i = 0; i < lspec.loopBound(COUNT); i += lspec.length()) {
+            umax_long_masked_diff_mask_minmax_swap(i);
+        }
+        for (int i = 0; i < lspec.loopBound(COUNT); i++) {
+            long a = long_in1[i], b = long_in2[i];
+            long minAB = m2arr[i] ? VectorMath.minUnsigned(a, b) : a;
+            long maxAB = m1arr[i] ? VectorMath.maxUnsigned(a, b) : a;
+            long expected = m1arr[i] ? VectorMath.maxUnsigned(minAB, maxAB) : minAB;
+            Verify.checkEQ(long_out[i], expected);
+        }
+    }
+
+    // Predicated Long: umax(umin(a,b,m1), umax(a,b,m1), m2) => NO transform
+    @Test
+    @IR(counts = {IRNode.UMIN_VL, " 1 ", IRNode.UMAX_VL, " 2 "}, applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true"})
+    public void umax_long_masked_diff_mask_outer(int index) {
+        LongVector vec1 = LongVector.fromArray(lspec, long_in1, index);
+        LongVector vec2 = LongVector.fromArray(lspec, long_in2, index);
+        VectorMask mask1 = VectorMask.fromArray(lspec, m1arr, index);
+        VectorMask mask2 = VectorMask.fromArray(lspec, m2arr, index);
+        vec1.lanewise(VectorOperators.UMIN, vec2, mask1)
+            .lanewise(VectorOperators.UMAX,
+                      vec1.lanewise(VectorOperators.UMAX, vec2, mask1), mask2)
+            .intoArray(long_out, index);
+    }
+
+    @Run(test = "umax_long_masked_diff_mask_outer")
+    public void umax_long_masked_diff_mask_outer_runner() {
+        for (int i = 0; i < lspec.loopBound(COUNT); i += lspec.length()) {
+            umax_long_masked_diff_mask_outer(i);
+        }
+        for (int i = 0; i < lspec.loopBound(COUNT); i++) {
+            long a = long_in1[i], b = long_in2[i];
+            long minAB = m1arr[i] ? VectorMath.minUnsigned(a, b) : a;
+            long maxAB = m1arr[i] ? VectorMath.maxUnsigned(a, b) : a;
+            long expected = m2arr[i] ? VectorMath.maxUnsigned(minAB, maxAB) : minAB;
+            Verify.checkEQ(long_out[i], expected);
+        }
+    }
+
+    // Predicated Long: umax(umin(a,b,m1), umax(a,b,m2), m3) => NO transform
+    @Test
+    @IR(counts = {IRNode.UMIN_VL, " 1 ", IRNode.UMAX_VL, " 2 "}, applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true"})
+    public void umax_long_masked_all_diff_mask(int index) {
+        LongVector vec1 = LongVector.fromArray(lspec, long_in1, index);
+        LongVector vec2 = LongVector.fromArray(lspec, long_in2, index);
+        VectorMask mask1 = VectorMask.fromArray(lspec, m1arr, index);
+        VectorMask mask2 = VectorMask.fromArray(lspec, m2arr, index);
+        VectorMask mask3 = VectorMask.fromArray(lspec, m3arr, index);
+        vec1.lanewise(VectorOperators.UMIN, vec2, mask1)
+            .lanewise(VectorOperators.UMAX,
+                      vec1.lanewise(VectorOperators.UMAX, vec2, mask2), mask3)
+            .intoArray(long_out, index);
+    }
+
+    @Run(test = "umax_long_masked_all_diff_mask")
+    public void umax_long_masked_all_diff_mask_runner() {
+        for (int i = 0; i < lspec.loopBound(COUNT); i += lspec.length()) {
+            umax_long_masked_all_diff_mask(i);
+        }
+        for (int i = 0; i < lspec.loopBound(COUNT); i++) {
+            long a = long_in1[i], b = long_in2[i];
+            long minAB = m1arr[i] ? VectorMath.minUnsigned(a, b) : a;
+            long maxAB = m2arr[i] ? VectorMath.maxUnsigned(a, b) : a;
+            long expected = m3arr[i] ? VectorMath.maxUnsigned(minAB, maxAB) : minAB;
+            Verify.checkEQ(long_out[i], expected);
+        }
+    }
+}

From 0a6775a4dcae5f92e116e22399d0ec31dd2b8e41 Mon Sep 17 00:00:00 2001
From: Amit Kumar 
Date: Wed, 15 Apr 2026 04:38:38 +0000
Subject: [PATCH 286/359] 8381787: Add testcase for Vector Lane Reversal issue

Reviewed-by: mdoerr, varadam
---
 .../vector/TestLongVectorReinterpret.java     | 84 +++++++++++++++++++
 1 file changed, 84 insertions(+)
 create mode 100644 test/jdk/jdk/incubator/vector/TestLongVectorReinterpret.java

diff --git a/test/jdk/jdk/incubator/vector/TestLongVectorReinterpret.java b/test/jdk/jdk/incubator/vector/TestLongVectorReinterpret.java
new file mode 100644
index 00000000000..3d51031840c
--- /dev/null
+++ b/test/jdk/jdk/incubator/vector/TestLongVectorReinterpret.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2026 IBM Corp. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please 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 8371187
+ * @summary Randomized test for lane swapping issue in LongVector reinterpretation on BE platforms
+ * @modules jdk.incubator.vector
+ * @run main/othervm --add-modules=jdk.incubator.vector TestLongVectorReinterpret
+ */
+
+import jdk.incubator.vector.*;
+import java.util.SplittableRandom;
+
+public class TestLongVectorReinterpret {
+
+    static final VectorSpecies SPECIES = LongVector.SPECIES_128;
+    static final SplittableRandom RAND = new SplittableRandom(42);
+
+    public static void main(String[] args) {
+        for (int iter = 0; iter < 1000; iter++) {
+            verifyLaneOrdering();
+        }
+    }
+
+    static void verifyLaneOrdering() {
+        long[] a = new long[SPECIES.length()];
+        long[] b = new long[SPECIES.length()];
+
+        for (int i = 0; i < a.length; i++) {
+            a[i] = RAND.nextLong();
+            b[i] = RAND.nextLong();
+        }
+
+        LongVector v1 = LongVector.fromArray(SPECIES, a, 0);
+        LongVector v2 = LongVector.fromArray(SPECIES, b, 0);
+
+        IntVector result = v2.reinterpretAsInts().add(v1.reinterpretAsInts());
+
+        int[] expected = new int[SPECIES.length() * 2];
+
+        for (int i = 0; i < a.length; i++) {
+            int loA = (int) a[i];
+            int hiA = (int) (a[i] >>> 32);
+
+            int loB = (int) b[i];
+            int hiB = (int) (b[i] >>> 32);
+
+            expected[2 * i]     = loA + loB;
+            expected[2 * i + 1] = hiA + hiB;
+        }
+
+        for (int i = 0; i < expected.length; i++) {
+            int actual = result.lane(i);
+            if (actual != expected[i]) {
+                throw new AssertionError(
+                    "Mismatch at lane " + i +
+                    " expected=" + expected[i] +
+                    " actual=" + actual +
+                    " vector=" + result);
+            }
+        }
+    }
+}

From 29024c253e3970a2f32a2573936bb85b0eabdbcc Mon Sep 17 00:00:00 2001
From: David Holmes 
Date: Wed, 15 Apr 2026 05:27:03 +0000
Subject: [PATCH 287/359] 8382202: New file VectorMinMaxTransforms.java has a
 copyright format error

Reviewed-by: mikael
---
 .../jtreg/compiler/vectorapi/VectorMinMaxTransforms.java    | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/test/hotspot/jtreg/compiler/vectorapi/VectorMinMaxTransforms.java b/test/hotspot/jtreg/compiler/vectorapi/VectorMinMaxTransforms.java
index acffe4d3257..be3ec322892 100644
--- a/test/hotspot/jtreg/compiler/vectorapi/VectorMinMaxTransforms.java
+++ b/test/hotspot/jtreg/compiler/vectorapi/VectorMinMaxTransforms.java
@@ -12,9 +12,9 @@
  * version 2 for more details (a copy is included in the LICENSE file that
  * accompanied this code).
  *
- * You should have received a copy of the GNU General Public License
- * version 2 along with this work; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  *
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any

From 436d291a1c679f892e5164ddf7d04ca59d6ca254 Mon Sep 17 00:00:00 2001
From: Eric Fang 
Date: Wed, 15 Apr 2026 08:24:51 +0000
Subject: [PATCH 288/359] 8370863: VectorAPI: Optimize the VectorMaskCast chain
 in specific patterns

Reviewed-by: xgong, vlivanov, galder
---
 src/hotspot/share/opto/phaseX.cpp             |   7 +-
 src/hotspot/share/opto/vectornode.cpp         |  33 +-
 src/hotspot/share/opto/vectornode.hpp         |   1 +
 .../TestVectorLongToMaskNodeIdealization.java |   8 +-
 .../vectorapi/VectorMaskCastIdentityTest.java | 104 +++---
 .../vectorapi/VectorMaskCastTest.java         | 188 +++++++----
 .../vectorapi/VectorMaskToLongTest.java       |  33 +-
 .../VectorStoreMaskIdentityTest.java          | 317 ++++++++++++++++++
 .../vector/VectorStoreMaskBenchmark.java      |  84 +++++
 9 files changed, 654 insertions(+), 121 deletions(-)
 create mode 100644 test/hotspot/jtreg/compiler/vectorapi/VectorStoreMaskIdentityTest.java
 create mode 100644 test/micro/org/openjdk/bench/jdk/incubator/vector/VectorStoreMaskBenchmark.java

diff --git a/src/hotspot/share/opto/phaseX.cpp b/src/hotspot/share/opto/phaseX.cpp
index 0fecc14f31a..a4d6a6c33d0 100644
--- a/src/hotspot/share/opto/phaseX.cpp
+++ b/src/hotspot/share/opto/phaseX.cpp
@@ -2123,7 +2123,12 @@ void PhaseIterGVN::verify_Identity_for(Node* n) {
 
   if (n->is_Vector()) {
     // Found with tier1-3. Not investigated yet.
-    // The observed issue was with AndVNode::Identity
+    // The observed issue was with AndVNode::Identity and
+    // VectorStoreMaskNode::Identity (see JDK-8370863).
+    //
+    // Found with:
+    //   compiler/vectorapi/VectorStoreMaskIdentityTest.java
+    //   -XX:CompileThreshold=100 -XX:-TieredCompilation -XX:VerifyIterativeGVN=1110
     return;
   }
 
diff --git a/src/hotspot/share/opto/vectornode.cpp b/src/hotspot/share/opto/vectornode.cpp
index b07f0234492..dbadc18da01 100644
--- a/src/hotspot/share/opto/vectornode.cpp
+++ b/src/hotspot/share/opto/vectornode.cpp
@@ -1047,6 +1047,20 @@ Node* VectorNode::Ideal(PhaseGVN* phase, bool can_reshape) {
   return nullptr;
 }
 
+// Traverses a chain of VectorMaskCast and returns the first non VectorMaskCast node.
+//
+// Due to the unique nature of vector masks, for specific IR patterns,
+// VectorMaskCast does not affect the output results. For example:
+//   (VectorStoreMask (VectorMaskCast* (VectorLoadMask x))) => (x)
+//   x remains to be a bool vector with no changes.
+// This function can be used to eliminate the VectorMaskCast in such patterns.
+Node* VectorNode::uncast_mask(Node* n) {
+  while (n->Opcode() == Op_VectorMaskCast) {
+    n = n->in(1);
+  }
+  return n;
+}
+
 // Return initial Pack node. Additional operands added with add_opd() calls.
 PackNode* PackNode::make(Node* s, uint vlen, BasicType bt) {
   const TypeVect* vt = TypeVect::make(bt, vlen);
@@ -1495,10 +1509,12 @@ Node* VectorLoadMaskNode::Identity(PhaseGVN* phase) {
 
 Node* VectorStoreMaskNode::Identity(PhaseGVN* phase) {
   // Identity transformation on boolean vectors.
-  //   VectorStoreMask (VectorLoadMask bv) elem_size ==> bv
+  //   VectorStoreMask (VectorMaskCast* VectorLoadMask bv) elem_size ==> bv
   //   vector[n]{bool} => vector[n]{t} => vector[n]{bool}
-  if (in(1)->Opcode() == Op_VectorLoadMask) {
-    return in(1)->in(1);
+  Node* in1 = VectorNode::uncast_mask(in(1));
+  if (in1->Opcode() == Op_VectorLoadMask) {
+    assert(length() == in1->as_Vector()->length(), "vector length must match");
+    return in1->in(1);
   }
   return this;
 }
@@ -1959,11 +1975,12 @@ Node* VectorMaskOpNode::Ideal(PhaseGVN* phase, bool can_reshape) {
 }
 
 Node* VectorMaskCastNode::Identity(PhaseGVN* phase) {
-  Node* in1 = in(1);
-  // VectorMaskCast (VectorMaskCast x) => x
-  if (in1->Opcode() == Op_VectorMaskCast &&
-      vect_type()->eq(in1->in(1)->bottom_type())) {
-      return in1->in(1);
+  // (VectorMaskCast+ x) => (x)
+  // If the types of the input and output nodes in a VectorMaskCast chain are
+  // exactly the same, the intermediate VectorMaskCast nodes can be eliminated.
+  Node* n = VectorNode::uncast_mask(this);
+  if (vect_type()->eq(n->bottom_type())) {
+      return n;
   }
   return this;
 }
diff --git a/src/hotspot/share/opto/vectornode.hpp b/src/hotspot/share/opto/vectornode.hpp
index c4fff06e771..de866898302 100644
--- a/src/hotspot/share/opto/vectornode.hpp
+++ b/src/hotspot/share/opto/vectornode.hpp
@@ -195,6 +195,7 @@ class VectorNode : public TypeNode {
   static bool is_scalar_op_that_returns_int_but_vector_op_returns_long(int opc);
   static bool is_reinterpret_opcode(int opc);
 
+  static Node* uncast_mask(Node* n);
 
   static void trace_new_vector(Node* n, const char* context) {
 #ifdef ASSERT
diff --git a/test/hotspot/jtreg/compiler/vectorapi/TestVectorLongToMaskNodeIdealization.java b/test/hotspot/jtreg/compiler/vectorapi/TestVectorLongToMaskNodeIdealization.java
index 706e21554bb..f9e50fbd23b 100644
--- a/test/hotspot/jtreg/compiler/vectorapi/TestVectorLongToMaskNodeIdealization.java
+++ b/test/hotspot/jtreg/compiler/vectorapi/TestVectorLongToMaskNodeIdealization.java
@@ -46,7 +46,7 @@ import static compiler.lib.template_framework.Template.let;
 
 /*
  * @test
- * @bug 8277997 8378968
+ * @bug 8277997 8378968 8380290
  * @key randomness
  * @summary Testing some optimizations in VectorLongToMaskNode::Ideal
  *          For now: VectorMask.fromLong(.., mask.toLong())
@@ -93,7 +93,7 @@ public class TestVectorLongToMaskNodeIdealization {
                   IRNode.VECTOR_STORE_MASK,                     "> 0", // Not yet optimized away
                   IRNode.VECTOR_LONG_TO_MASK,                   "= 0", // Optimized away
                   IRNode.VECTOR_MASK_TO_LONG,                   "= 0", // Optimized away
-                  IRNode.VECTOR_MASK_CAST,                      "> 0", // Not yet optimized away
+                  IRNode.VECTOR_MASK_CAST,                      "= 0", // Optimized away
                   IRNode.VECTOR_BLEND_I,  IRNode.VECTOR_SIZE_4, "> 0",
                   IRNode.XOR_VI,          IRNode.VECTOR_SIZE_4, "> 0",
                   IRNode.STORE_VECTOR,                          "> 0"},
@@ -168,7 +168,7 @@ public class TestVectorLongToMaskNodeIdealization {
                   IRNode.VECTOR_STORE_MASK,                     "> 0", // Not yet optimized away
                   IRNode.VECTOR_LONG_TO_MASK,                   "= 0", // Optimized away
                   IRNode.VECTOR_MASK_TO_LONG,                   "= 0", // Optimized away
-                  IRNode.VECTOR_MASK_CAST,                      "> 0", // Not yet optimized away: Cast Z->Z, see JDK-8379866
+                  IRNode.VECTOR_MASK_CAST,                      "= 0", // Optimized away
                   IRNode.VECTOR_BLEND_I,  IRNode.VECTOR_SIZE_4, "> 0",
                   IRNode.XOR_VI,          IRNode.VECTOR_SIZE_4, "> 0",
                   IRNode.STORE_VECTOR,                          "> 0"},
@@ -219,7 +219,7 @@ public class TestVectorLongToMaskNodeIdealization {
                   IRNode.VECTOR_STORE_MASK,                     "= 0",
                   IRNode.VECTOR_LONG_TO_MASK,                   "= 0", // Optimized away
                   IRNode.VECTOR_MASK_TO_LONG,                   "= 0", // Optimized away
-                  IRNode.VECTOR_MASK_CAST,                      "> 0", // Not yet optimized Z->Z, see JDK-8379866
+                  IRNode.VECTOR_MASK_CAST,                      "= 0", // Optimized away
                   IRNode.VECTOR_BLEND_I,  IRNode.VECTOR_SIZE_4, "> 0",
                   IRNode.XOR_VI,          IRNode.VECTOR_SIZE_4, "> 0",
                   IRNode.STORE_VECTOR,                          "> 0"},
diff --git a/test/hotspot/jtreg/compiler/vectorapi/VectorMaskCastIdentityTest.java b/test/hotspot/jtreg/compiler/vectorapi/VectorMaskCastIdentityTest.java
index e4f166f510a..e1c20da76ec 100644
--- a/test/hotspot/jtreg/compiler/vectorapi/VectorMaskCastIdentityTest.java
+++ b/test/hotspot/jtreg/compiler/vectorapi/VectorMaskCastIdentityTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * Copyright (c) 2025, 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,10 +23,10 @@
 
 /*
 * @test
-* @bug 8356760
+* @bug 8356760 8370863
 * @key randomness
 * @library /test/lib /
-* @summary Optimize VectorMask.fromLong for all-true/all-false cases
+* @summary test VectorMaskCast Identity() optimizations
 * @modules jdk.incubator.vector
 *
 * @run driver compiler.vectorapi.VectorMaskCastIdentityTest
@@ -50,70 +50,88 @@ public class VectorMaskCastIdentityTest {
     }
 
     @Test
-    @IR(counts = { IRNode.VECTOR_MASK_CAST, "= 2" }, applyIfCPUFeatureOr = {"asimd", "true", "rvv", "true"})
-    public static int testTwoCastToDifferentType() {
-        // The types before and after the two casts are not the same, so the cast cannot be eliminated.
-        VectorMask mFloat64 = VectorMask.fromArray(FloatVector.SPECIES_64, mr, 0);
-        VectorMask mDouble128 = mFloat64.cast(DoubleVector.SPECIES_128);
-        VectorMask mInt64 = mDouble128.cast(IntVector.SPECIES_64);
-        return mInt64.trueCount();
+    @IR(counts = { IRNode.LOAD_VECTOR_Z, IRNode.VECTOR_SIZE_4, "> 0",
+                   IRNode.VECTOR_MASK_CAST, "= 0" },
+        applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" },
+        applyIf = { "MaxVectorSize", ">= 16" })
+    public static int testOneCastToSameType() {
+        // The types before and after the cast sequence are the same,
+        // so the casts will be eliminated.
+        VectorMask mInt128 = VectorMask.fromArray(IntVector.SPECIES_128, mr, 0);
+        mInt128 = mInt128.cast(IntVector.SPECIES_128);
+        // Insert a not() to prevent the casts being optimized by the optimization:
+        // (VectorStoreMask (VectorMaskCast* (VectorLoadMask x))) => x
+        return mInt128.not().trueCount();
     }
 
-    @Run(test = "testTwoCastToDifferentType")
-    public static void testTwoCastToDifferentType_runner() {
-        int count = testTwoCastToDifferentType();
-        VectorMask mFloat64 = VectorMask.fromArray(FloatVector.SPECIES_64, mr, 0);
-        Asserts.assertEquals(count, mFloat64.trueCount());
+    @Run(test = "testOneCastToSameType")
+    public static void testOneCastToSameType_runner() {
+        int count = testOneCastToSameType();
+        VectorMask mInt128 = VectorMask.fromArray(IntVector.SPECIES_128, mr, 0);
+        Asserts.assertEquals(count, mInt128.not().trueCount());
     }
 
     @Test
-    @IR(counts = { IRNode.VECTOR_MASK_CAST, "= 2" }, applyIfCPUFeatureOr = {"avx2", "true"})
-    public static int testTwoCastToDifferentType2() {
-        // The types before and after the two casts are not the same, so the cast cannot be eliminated.
-        VectorMask mInt128 = VectorMask.fromArray(IntVector.SPECIES_128, mr, 0);
-        VectorMask mDouble256 = mInt128.cast(DoubleVector.SPECIES_256);
-        VectorMask  mShort64 = mDouble256.cast(ShortVector.SPECIES_64);
-        return mShort64.trueCount();
-    }
-
-    @Run(test = "testTwoCastToDifferentType2")
-    public static void testTwoCastToDifferentType2_runner() {
-        int count = testTwoCastToDifferentType2();
-        VectorMask mInt128 = VectorMask.fromArray(IntVector.SPECIES_128, mr, 0);
-        Asserts.assertEquals(count, mInt128.trueCount());
-    }
-
-    @Test
-    @IR(counts = { IRNode.VECTOR_MASK_CAST, "= 0" }, applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true", "rvv", "true"})
+    @IR(counts = { IRNode.LOAD_VECTOR_Z, IRNode.VECTOR_SIZE_4, "> 0",
+                   IRNode.VECTOR_MASK_CAST, "= 0" },
+        applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" },
+        applyIf = { "MaxVectorSize", ">= 16" })
     public static int testTwoCastToSameType() {
-        // The types before and after the two casts are the same, so the cast will be eliminated.
+        // The types before and after the cast sequence are the same,
+        // so the casts will be eliminated.
         VectorMask mInt128 = VectorMask.fromArray(IntVector.SPECIES_128, mr, 0);
         VectorMask mFloat128 = mInt128.cast(FloatVector.SPECIES_128);
         VectorMask mInt128_2 = mFloat128.cast(IntVector.SPECIES_128);
-        return mInt128_2.trueCount();
+        return mInt128_2.not().trueCount();
     }
 
     @Run(test = "testTwoCastToSameType")
     public static void testTwoCastToSameType_runner() {
         int count = testTwoCastToSameType();
         VectorMask mInt128 = VectorMask.fromArray(IntVector.SPECIES_128, mr, 0);
-        Asserts.assertEquals(count, mInt128.trueCount());
+        Asserts.assertEquals(count, mInt128.not().trueCount());
     }
 
     @Test
-    @IR(counts = { IRNode.VECTOR_MASK_CAST, "= 1" }, applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true", "rvv", "true"})
+    @IR(counts = { IRNode.LOAD_VECTOR_Z, IRNode.VECTOR_SIZE_4, "> 0",
+                   IRNode.VECTOR_MASK_CAST, "= 1" },
+        applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" },
+        applyIf = { "MaxVectorSize", ">= 16" })
     public static int testOneCastToDifferentType() {
-        // The types before and after the only cast are different, the cast will not be eliminated.
-        VectorMask mFloat128 = VectorMask.fromArray(FloatVector.SPECIES_128, mr, 0).not();
-        VectorMask mInt128 = mFloat128.cast(IntVector.SPECIES_128);
-        return mInt128.trueCount();
+        // The types before and after the cast sequence are different,
+        // so the casts will not be eliminated.
+        VectorMask mInt128 = VectorMask.fromArray(IntVector.SPECIES_128, mr, 0);
+        VectorMask mShort64 = mInt128.cast(ShortVector.SPECIES_64);
+        return mShort64.not().trueCount();
     }
 
     @Run(test = "testOneCastToDifferentType")
     public static void testOneCastToDifferentType_runner() {
         int count = testOneCastToDifferentType();
-        VectorMask mInt128 = VectorMask.fromArray(FloatVector.SPECIES_128, mr, 0).not();
-        Asserts.assertEquals(count, mInt128.trueCount());
+        VectorMask mInt128 = VectorMask.fromArray(IntVector.SPECIES_128, mr, 0);
+        Asserts.assertEquals(count, mInt128.not().trueCount());
+    }
+
+    @Test
+    @IR(counts = { IRNode.LOAD_VECTOR_Z, IRNode.VECTOR_SIZE_4, "> 0",
+                   IRNode.VECTOR_MASK_CAST, "= 2" },
+        applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" },
+        applyIf = { "MaxVectorSize", ">= 16" })
+    public static int testTwoCastToDifferentType() {
+        // The types before and after the cast sequence are different, so the
+        // casts are not eliminated. We should probably be able to eliminate
+        // the intermediate cast, so that we only need a cast from short to int.
+        VectorMask mShort64 = VectorMask.fromArray(ShortVector.SPECIES_64, mr, 0);
+        VectorMask mFloat128 = mShort64.cast(FloatVector.SPECIES_128);
+        VectorMask mInt128 = mFloat128.cast(IntVector.SPECIES_128);
+        return mInt128.not().trueCount();
+    }
+
+    @Run(test = "testTwoCastToDifferentType")
+    public static void testTwoCastToDifferentType_runner() {
+        int count = testTwoCastToDifferentType();
+        VectorMask mShort64 = VectorMask.fromArray(ShortVector.SPECIES_64, mr, 0);
+        Asserts.assertEquals(count, mShort64.not().trueCount());
     }
 
     public static void main(String[] args) {
diff --git a/test/hotspot/jtreg/compiler/vectorapi/VectorMaskCastTest.java b/test/hotspot/jtreg/compiler/vectorapi/VectorMaskCastTest.java
index 1f346cffd2f..c75ea6c7a66 100644
--- a/test/hotspot/jtreg/compiler/vectorapi/VectorMaskCastTest.java
+++ b/test/hotspot/jtreg/compiler/vectorapi/VectorMaskCastTest.java
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2021, 2023, Arm Limited. All rights reserved.
+ * Copyright (c) 2025, 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -76,13 +77,15 @@ public class VectorMaskCastTest {
     @Test
     @IR(counts = { IRNode.VECTOR_MASK_CAST, "> 0" }, applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true", "rvv", "true"})
     public static VectorMask testByte64ToShort128(VectorMask v) {
-        return v.cast(ShortVector.SPECIES_128);
+        // A not operation is introduced to prevent the cast from being optimized away.
+        return v.not().cast(ShortVector.SPECIES_128);
     }
 
     @Run(test = "testByte64ToShort128")
     public static void testByte64ToShort128_runner() {
         VectorMask mByte64 = VectorMask.fromArray(ByteVector.SPECIES_64, mask_arr, 0);
         VectorMask res = testByte64ToShort128(mByte64);
+        mByte64 = mByte64.not();
         Asserts.assertEquals(res.toString(), mByte64.toString());
         Asserts.assertEquals(res.trueCount(), mByte64.trueCount());
     }
@@ -90,13 +93,14 @@ public class VectorMaskCastTest {
     @Test
     @IR(counts = { IRNode.VECTOR_MASK_CAST, "> 0" }, applyIfCPUFeature = {"avx2", "true"})
     public static VectorMask testByte64ToInt256(VectorMask v) {
-        return v.cast(IntVector.SPECIES_256);
+        return v.not().cast(IntVector.SPECIES_256);
     }
 
     @Run(test = "testByte64ToInt256")
     public static void testByte64ToInt256_runner() {
         VectorMask mByte64 = VectorMask.fromArray(ByteVector.SPECIES_64, mask_arr, 0);
         VectorMask res = testByte64ToInt256(mByte64);
+        mByte64 = mByte64.not();
         Asserts.assertEquals(res.toString(), mByte64.toString());
         Asserts.assertEquals(res.trueCount(), mByte64.trueCount());
     }
@@ -104,13 +108,14 @@ public class VectorMaskCastTest {
     @Test
     @IR(counts = { IRNode.VECTOR_MASK_CAST, "> 0" }, applyIfCPUFeature = {"avx2", "true"})
     public static VectorMask testByte64ToFloat256(VectorMask v) {
-        return v.cast(FloatVector.SPECIES_256);
+        return v.not().cast(FloatVector.SPECIES_256);
     }
 
     @Run(test = "testByte64ToFloat256")
     public static void testByte64ToFloat256_runner() {
         VectorMask mByte64 = VectorMask.fromArray(ByteVector.SPECIES_64, mask_arr, 0);
         VectorMask res = testByte64ToFloat256(mByte64);
+        mByte64 = mByte64.not();
         Asserts.assertEquals(res.toString(), mByte64.toString());
         Asserts.assertEquals(res.trueCount(), mByte64.trueCount());
     }
@@ -118,13 +123,14 @@ public class VectorMaskCastTest {
     @Test
     @IR(counts = { IRNode.VECTOR_MASK_CAST, "> 0" }, applyIfCPUFeature = {"avx512vl", "true"})
     public static VectorMask testByte64ToLong512(VectorMask v) {
-        return v.cast(LongVector.SPECIES_512);
+        return v.not().cast(LongVector.SPECIES_512);
     }
 
     @Run(test = "testByte64ToLong512")
     public static void testByte64ToLong512_runner() {
         VectorMask mByte64 = VectorMask.fromArray(ByteVector.SPECIES_64, mask_arr, 0);
         VectorMask res = testByte64ToLong512(mByte64);
+        mByte64 = mByte64.not();
         Asserts.assertEquals(res.toString(), mByte64.toString());
         Asserts.assertEquals(res.trueCount(), mByte64.trueCount());
     }
@@ -132,13 +138,14 @@ public class VectorMaskCastTest {
     @Test
     @IR(counts = { IRNode.VECTOR_MASK_CAST, "> 0" }, applyIfCPUFeature = {"avx512vl", "true"})
     public static VectorMask testByte64ToDouble512(VectorMask v) {
-       return v.cast(DoubleVector.SPECIES_512);
+       return v.not().cast(DoubleVector.SPECIES_512);
     }
 
     @Run(test = "testByte64ToDouble512")
     public static void testByte64ToDouble512_runner() {
         VectorMask mByte64 = VectorMask.fromArray(ByteVector.SPECIES_64, mask_arr, 0);
         VectorMask res = testByte64ToDouble512(mByte64);
+        mByte64 = mByte64.not();
         Asserts.assertEquals(res.toString(), mByte64.toString());
         Asserts.assertEquals(res.trueCount(), mByte64.trueCount());
     }
@@ -146,13 +153,14 @@ public class VectorMaskCastTest {
     @Test
     @IR(counts = { IRNode.VECTOR_MASK_CAST, "> 0" }, applyIfCPUFeature = {"avx2", "true"})
     public static VectorMask testByte128ToShort256(VectorMask v) {
-        return v.cast(ShortVector.SPECIES_256);
+        return v.not().cast(ShortVector.SPECIES_256);
     }
 
     @Run(test = "testByte128ToShort256")
     public static void testByte128ToShort256_runner() {
         VectorMask mByte128 = VectorMask.fromArray(ByteVector.SPECIES_128, mask_arr, 0);
         VectorMask res = testByte128ToShort256(mByte128);
+        mByte128 = mByte128.not();
         Asserts.assertEquals(res.toString(), mByte128.toString());
         Asserts.assertEquals(res.trueCount(), mByte128.trueCount());
     }
@@ -160,13 +168,14 @@ public class VectorMaskCastTest {
     @Test
     @IR(counts = { IRNode.VECTOR_MASK_CAST, "> 0" }, applyIfCPUFeature = {"avx512vl", "true"})
     public static VectorMask testByte128ToInt512(VectorMask v) {
-        return v.cast(IntVector.SPECIES_512);
+        return v.not().cast(IntVector.SPECIES_512);
     }
 
     @Run(test = "testByte128ToInt512")
     public static void testByte128ToInt512_runner() {
         VectorMask mByte128 = VectorMask.fromArray(ByteVector.SPECIES_128, mask_arr, 0);
         VectorMask res = testByte128ToInt512(mByte128);
+        mByte128 = mByte128.not();
         Asserts.assertEquals(res.toString(), mByte128.toString());
         Asserts.assertEquals(res.trueCount(), mByte128.trueCount());
     }
@@ -174,13 +183,14 @@ public class VectorMaskCastTest {
     @Test
     @IR(counts = { IRNode.VECTOR_MASK_CAST, "> 0" }, applyIfCPUFeature = {"avx512vl", "true"})
     public static VectorMask testByte128ToFloat512(VectorMask v) {
-        return v.cast(FloatVector.SPECIES_512);
+        return v.not().cast(FloatVector.SPECIES_512);
     }
 
     @Run(test = "testByte128ToFloat512")
     public static void testByte128ToFloat512_runner() {
         VectorMask mByte128 = VectorMask.fromArray(ByteVector.SPECIES_128, mask_arr, 0);
         VectorMask res = testByte128ToFloat512(mByte128);
+        mByte128 = mByte128.not();
         Asserts.assertEquals(res.toString(), mByte128.toString());
         Asserts.assertEquals(res.trueCount(), mByte128.trueCount());
     }
@@ -188,13 +198,14 @@ public class VectorMaskCastTest {
     @Test
     @IR(counts = { IRNode.VECTOR_MASK_CAST, "> 0" }, applyIfCPUFeature = {"avx512vl", "true"})
     public static VectorMask testByte256ToShort512(VectorMask v) {
-        return v.cast(ShortVector.SPECIES_512);
+        return v.not().cast(ShortVector.SPECIES_512);
     }
 
     @Run(test = "testByte256ToShort512")
     public static void testByte256ToShort512_runner() {
         VectorMask mByte256 = VectorMask.fromArray(ByteVector.SPECIES_256, mask_arr, 0);
         VectorMask res = testByte256ToShort512(mByte256);
+        mByte256 = mByte256.not();
         Asserts.assertEquals(res.toString(), mByte256.toString());
         Asserts.assertEquals(res.trueCount(), mByte256.trueCount());
     }
@@ -203,13 +214,14 @@ public class VectorMaskCastTest {
     @Test
     @IR(counts = { IRNode.VECTOR_MASK_CAST, "> 0" }, applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true", "rvv", "true"})
     public static VectorMask testShort64ToInt128(VectorMask v) {
-        return v.cast(IntVector.SPECIES_128);
+        return v.not().cast(IntVector.SPECIES_128);
     }
 
     @Run(test = "testShort64ToInt128")
     public static void testShort64ToInt128_runner() {
         VectorMask mShort64 = VectorMask.fromArray(ShortVector.SPECIES_64, mask_arr, 0);
         VectorMask res = testShort64ToInt128(mShort64);
+        mShort64 = mShort64.not();
         Asserts.assertEquals(res.toString(), mShort64.toString());
         Asserts.assertEquals(res.trueCount(), mShort64.trueCount());
     }
@@ -217,13 +229,14 @@ public class VectorMaskCastTest {
     @Test
     @IR(counts = { IRNode.VECTOR_MASK_CAST, "> 0" }, applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true", "rvv", "true"})
     public static VectorMask testShort64ToFloat128(VectorMask v) {
-        return v.cast(FloatVector.SPECIES_128);
+        return v.not().cast(FloatVector.SPECIES_128);
     }
 
     @Run(test = "testShort64ToFloat128")
     public static void testShort64ToFloat128_runner() {
         VectorMask mShort64 = VectorMask.fromArray(ShortVector.SPECIES_64, mask_arr, 0);
         VectorMask res = testShort64ToFloat128(mShort64);
+        mShort64 = mShort64.not();
         Asserts.assertEquals(res.toString(), mShort64.toString());
         Asserts.assertEquals(res.trueCount(), mShort64.trueCount());
     }
@@ -231,13 +244,14 @@ public class VectorMaskCastTest {
     @Test
     @IR(counts = { IRNode.VECTOR_MASK_CAST, "> 0" }, applyIfCPUFeature = {"avx2", "true"})
     public static VectorMask testShort64ToLong256(VectorMask v) {
-        return v.cast(LongVector.SPECIES_256);
+        return v.not().cast(LongVector.SPECIES_256);
     }
 
     @Run(test = "testShort64ToLong256")
     public static void testShort64ToLong256_runner() {
         VectorMask mShort64 = VectorMask.fromArray(ShortVector.SPECIES_64, mask_arr, 0);
         VectorMask res = testShort64ToLong256(mShort64);
+        mShort64 = mShort64.not();
         Asserts.assertEquals(res.toString(), mShort64.toString());
         Asserts.assertEquals(res.trueCount(), mShort64.trueCount());
     }
@@ -245,13 +259,14 @@ public class VectorMaskCastTest {
     @Test
     @IR(counts = { IRNode.VECTOR_MASK_CAST, "> 0" }, applyIfCPUFeature = {"avx2", "true"})
     public static VectorMask testShort64ToDouble256(VectorMask v) {
-        return v.cast(DoubleVector.SPECIES_256);
+        return v.not().cast(DoubleVector.SPECIES_256);
     }
 
     @Run(test = "testShort64ToDouble256")
     public static void testShort64ToDouble256_runner() {
         VectorMask mShort64 = VectorMask.fromArray(ShortVector.SPECIES_64, mask_arr, 0);
         VectorMask res = testShort64ToDouble256(mShort64);
+        mShort64 = mShort64.not();
         Asserts.assertEquals(res.toString(), mShort64.toString());
         Asserts.assertEquals(res.trueCount(), mShort64.trueCount());
     }
@@ -259,13 +274,14 @@ public class VectorMaskCastTest {
     @Test
     @IR(counts = { IRNode.VECTOR_MASK_CAST, "> 0" }, applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true", "rvv", "true"})
     public static VectorMask testShort128ToByte64(VectorMask v) {
-        return v.cast(ByteVector.SPECIES_64);
+        return v.not().cast(ByteVector.SPECIES_64);
     }
 
     @Run(test = "testShort128ToByte64")
     public static void testShort128ToByte64_runner() {
         VectorMask mShort128 = VectorMask.fromArray(ShortVector.SPECIES_128, mask_arr, 0);
         VectorMask res = testShort128ToByte64(mShort128);
+        mShort128 = mShort128.not();
         Asserts.assertEquals(res.toString(), mShort128.toString());
         Asserts.assertEquals(res.trueCount(), mShort128.trueCount());
     }
@@ -273,13 +289,14 @@ public class VectorMaskCastTest {
     @Test
     @IR(counts = { IRNode.VECTOR_MASK_CAST, "> 0" }, applyIfCPUFeature = {"avx2", "true"})
     public static VectorMask testShort128ToInt256(VectorMask v) {
-        return v.cast(IntVector.SPECIES_256);
+        return v.not().cast(IntVector.SPECIES_256);
     }
 
     @Run(test = "testShort128ToInt256")
     public static void testShort128ToInt256_runner() {
         VectorMask mShort128 = VectorMask.fromArray(ShortVector.SPECIES_128, mask_arr, 0);
         VectorMask res = testShort128ToInt256(mShort128);
+        mShort128 = mShort128.not();
         Asserts.assertEquals(res.toString(), mShort128.toString());
         Asserts.assertEquals(res.trueCount(), mShort128.trueCount());
     }
@@ -287,13 +304,14 @@ public class VectorMaskCastTest {
     @Test
     @IR(counts = { IRNode.VECTOR_MASK_CAST, "> 0" }, applyIfCPUFeature = {"avx2", "true"})
     public static VectorMask testShort128ToFloat256(VectorMask v) {
-        return v.cast(FloatVector.SPECIES_256);
+        return v.not().cast(FloatVector.SPECIES_256);
     }
 
     @Run(test = "testShort128ToFloat256")
     public static void testShort128ToFloat256_runner() {
         VectorMask mShort128 = VectorMask.fromArray(ShortVector.SPECIES_128, mask_arr, 0);
         VectorMask res = testShort128ToFloat256(mShort128);
+        mShort128 = mShort128.not();
         Asserts.assertEquals(res.toString(), mShort128.toString());
         Asserts.assertEquals(res.trueCount(), mShort128.trueCount());
     }
@@ -301,13 +319,14 @@ public class VectorMaskCastTest {
     @Test
     @IR(counts = { IRNode.VECTOR_MASK_CAST, "> 0" }, applyIfCPUFeature = {"avx512vl", "true"})
     public static VectorMask testShort128ToLong512(VectorMask v) {
-        return v.cast(LongVector.SPECIES_512);
+        return v.not().cast(LongVector.SPECIES_512);
     }
 
     @Run(test = "testShort128ToLong512")
     public static void testShort128ToLong512_runner() {
         VectorMask mShort128 = VectorMask.fromArray(ShortVector.SPECIES_128, mask_arr, 0);
         VectorMask res = testShort128ToLong512(mShort128);
+        mShort128 = mShort128.not();
         Asserts.assertEquals(res.toString(), mShort128.toString());
         Asserts.assertEquals(res.trueCount(), mShort128.trueCount());
     }
@@ -315,13 +334,14 @@ public class VectorMaskCastTest {
     @Test
     @IR(counts = { IRNode.VECTOR_MASK_CAST, "> 0" }, applyIfCPUFeature = {"avx512vl", "true"})
     public static VectorMask testShort128ToDouble512(VectorMask v) {
-        return v.cast(DoubleVector.SPECIES_512);
+        return v.not().cast(DoubleVector.SPECIES_512);
     }
 
     @Run(test = "testShort128ToDouble512")
     public static void testShort128ToDouble512_runner() {
         VectorMask mShort128 = VectorMask.fromArray(ShortVector.SPECIES_128, mask_arr, 0);
         VectorMask res = testShort128ToDouble512(mShort128);
+        mShort128 = mShort128.not();
         Asserts.assertEquals(res.toString(), mShort128.toString());
         Asserts.assertEquals(res.trueCount(), mShort128.trueCount());
     }
@@ -329,13 +349,14 @@ public class VectorMaskCastTest {
     @Test
     @IR(counts = { IRNode.VECTOR_MASK_CAST, "> 0" }, applyIfCPUFeature = {"avx2", "true"})
     public static VectorMask testShort256ToByte128(VectorMask v) {
-       return v.cast(ByteVector.SPECIES_128);
+       return v.not().cast(ByteVector.SPECIES_128);
     }
 
     @Run(test = "testShort256ToByte128")
     public static void testShort256ToByte128_runner() {
         VectorMask mShort256 = VectorMask.fromArray(ShortVector.SPECIES_256, mask_arr, 0);
         VectorMask res = testShort256ToByte128(mShort256);
+        mShort256 = mShort256.not();
         Asserts.assertEquals(res.toString(), mShort256.toString());
         Asserts.assertEquals(res.trueCount(), mShort256.trueCount());
     }
@@ -343,13 +364,14 @@ public class VectorMaskCastTest {
     @Test
     @IR(counts = { IRNode.VECTOR_MASK_CAST, "> 0" }, applyIfCPUFeature = {"avx512vl", "true"})
     public static VectorMask testShort256ToInt512(VectorMask v) {
-        return v.cast(IntVector.SPECIES_512);
+        return v.not().cast(IntVector.SPECIES_512);
     }
 
     @Run(test = "testShort256ToInt512")
     public static void testShort256ToInt512_runner() {
         VectorMask mShort256 = VectorMask.fromArray(ShortVector.SPECIES_256, mask_arr, 0);
         VectorMask res = testShort256ToInt512(mShort256);
+        mShort256 = mShort256.not();
         Asserts.assertEquals(res.toString(), mShort256.toString());
         Asserts.assertEquals(res.trueCount(), mShort256.trueCount());
     }
@@ -357,13 +379,14 @@ public class VectorMaskCastTest {
     @Test
     @IR(counts = { IRNode.VECTOR_MASK_CAST, "> 0" }, applyIfCPUFeature = {"avx512vl", "true"})
     public static VectorMask testShort256ToFloat512(VectorMask v) {
-        return v.cast(FloatVector.SPECIES_512);
+        return v.not().cast(FloatVector.SPECIES_512);
     }
 
     @Run(test = "testShort256ToFloat512")
     public static void testShort256ToFloat512_runner() {
         VectorMask mShort256 = VectorMask.fromArray(ShortVector.SPECIES_256, mask_arr, 0);
         VectorMask res = testShort256ToFloat512(mShort256);
+        mShort256 = mShort256.not();
         Asserts.assertEquals(res.toString(), mShort256.toString());
         Asserts.assertEquals(res.trueCount(), mShort256.trueCount());
     }
@@ -371,13 +394,14 @@ public class VectorMaskCastTest {
     @Test
     @IR(counts = { IRNode.VECTOR_MASK_CAST, "> 0" }, applyIfCPUFeature = {"avx512vl", "true"})
     public static VectorMask testShort512ToByte256(VectorMask v) {
-        return v.cast(ByteVector.SPECIES_256);
+        return v.not().cast(ByteVector.SPECIES_256);
     }
 
     @Run(test = "testShort512ToByte256")
     public static void testShort512ToByte256_runner() {
         VectorMask mShort512 = VectorMask.fromArray(ShortVector.SPECIES_512, mask_arr, 0);
         VectorMask res = testShort512ToByte256(mShort512);
+        mShort512 = mShort512.not();
         Asserts.assertEquals(res.toString(), mShort512.toString());
         Asserts.assertEquals(res.trueCount(), mShort512.trueCount());
     }
@@ -386,13 +410,14 @@ public class VectorMaskCastTest {
     @Test
     @IR(counts = { IRNode.VECTOR_MASK_CAST, "> 0" }, applyIfCPUFeatureOr = {"asimd", "true", "rvv", "true"})
     public static VectorMask testInt64ToLong128(VectorMask v) {
-        return v.cast(LongVector.SPECIES_128);
+        return v.not().cast(LongVector.SPECIES_128);
     }
 
     @Run(test = "testInt64ToLong128")
     public static void testInt64ToLong128_runner() {
         VectorMask mInt64 = VectorMask.fromArray(IntVector.SPECIES_64, mask_arr, 0);
         VectorMask res = testInt64ToLong128(mInt64);
+        mInt64 = mInt64.not();
         Asserts.assertEquals(res.toString(), mInt64.toString());
         Asserts.assertEquals(res.trueCount(), mInt64.trueCount());
     }
@@ -400,13 +425,14 @@ public class VectorMaskCastTest {
     @Test
     @IR(counts = { IRNode.VECTOR_MASK_CAST, "> 0" }, applyIfCPUFeatureOr = {"asimd", "true", "rvv", "true"})
     public static VectorMask testInt64ToDouble128(VectorMask v) {
-        return v.cast(DoubleVector.SPECIES_128);
+        return v.not().cast(DoubleVector.SPECIES_128);
     }
 
     @Run(test = "testInt64ToDouble128")
     public static void testInt64ToDouble128_runner() {
         VectorMask mInt64 = VectorMask.fromArray(IntVector.SPECIES_64, mask_arr, 0);
         VectorMask res = testInt64ToDouble128(mInt64);
+        mInt64 = mInt64.not();
         Asserts.assertEquals(res.toString(), mInt64.toString());
         Asserts.assertEquals(res.trueCount(), mInt64.trueCount());
     }
@@ -414,13 +440,14 @@ public class VectorMaskCastTest {
     @Test
     @IR(counts = { IRNode.VECTOR_MASK_CAST, "> 0" }, applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true", "rvv", "true"})
     public static VectorMask testInt128ToShort64(VectorMask v) {
-        return v.cast(ShortVector.SPECIES_64);
+        return v.not().cast(ShortVector.SPECIES_64);
     }
 
     @Run(test = "testInt128ToShort64")
     public static void testInt128ToShort64_runner() {
         VectorMask mInt128 = VectorMask.fromArray(IntVector.SPECIES_128, mask_arr, 0);
         VectorMask res = testInt128ToShort64(mInt128);
+        mInt128 = mInt128.not();
         Asserts.assertEquals(res.toString(), mInt128.toString());
         Asserts.assertEquals(res.trueCount(), mInt128.trueCount());
     }
@@ -428,13 +455,14 @@ public class VectorMaskCastTest {
     @Test
     @IR(counts = { IRNode.VECTOR_MASK_CAST, "> 0" }, applyIfCPUFeature = {"avx2", "true"})
     public static VectorMask testInt128ToLong256(VectorMask v) {
-        return v.cast(LongVector.SPECIES_256);
+        return v.not().cast(LongVector.SPECIES_256);
     }
 
     @Run(test = "testInt128ToLong256")
     public static void testInt128ToLong256_runner() {
         VectorMask mInt128 = VectorMask.fromArray(IntVector.SPECIES_128, mask_arr, 0);
         VectorMask res = testInt128ToLong256(mInt128);
+        mInt128 = mInt128.not();
         Asserts.assertEquals(res.toString(), mInt128.toString());
         Asserts.assertEquals(res.trueCount(), mInt128.trueCount());
     }
@@ -442,13 +470,14 @@ public class VectorMaskCastTest {
     @Test
     @IR(counts = { IRNode.VECTOR_MASK_CAST, "> 0" }, applyIfCPUFeature = {"avx2", "true"})
     public static VectorMask testInt128ToDouble256(VectorMask v) {
-        return v.cast(DoubleVector.SPECIES_256);
+        return v.not().cast(DoubleVector.SPECIES_256);
     }
 
     @Run(test = "testInt128ToDouble256")
     public static void testInt128ToDouble256_runner() {
         VectorMask mInt128 = VectorMask.fromArray(IntVector.SPECIES_128, mask_arr, 0);
         VectorMask res = testInt128ToDouble256(mInt128);
+        mInt128 = mInt128.not();
         Asserts.assertEquals(res.toString(), mInt128.toString());
         Asserts.assertEquals(res.trueCount(), mInt128.trueCount());
     }
@@ -456,13 +485,14 @@ public class VectorMaskCastTest {
     @Test
     @IR(counts = { IRNode.VECTOR_MASK_CAST, "> 0" }, applyIfCPUFeature = {"avx2", "true"})
     public static VectorMask testInt256ToShort128(VectorMask v) {
-        return v.cast(ShortVector.SPECIES_128);
+        return v.not().cast(ShortVector.SPECIES_128);
     }
 
     @Run(test = "testInt256ToShort128")
     public static void testInt256ToShort128_runner() {
         VectorMask mInt256 = VectorMask.fromArray(IntVector.SPECIES_256, mask_arr, 0);
         VectorMask res = testInt256ToShort128(mInt256);
+        mInt256 = mInt256.not();
         Asserts.assertEquals(res.toString(), mInt256.toString());
         Asserts.assertEquals(res.trueCount(), mInt256.trueCount());
     }
@@ -470,13 +500,14 @@ public class VectorMaskCastTest {
     @Test
     @IR(counts = { IRNode.VECTOR_MASK_CAST, "> 0" }, applyIfCPUFeature = {"avx2", "true"})
     public static VectorMask testInt256ToByte64(VectorMask v) {
-    return v.cast(ByteVector.SPECIES_64);
+    return v.not().cast(ByteVector.SPECIES_64);
     }
 
     @Run(test = "testInt256ToByte64")
     public static void testInt256ToByte64_runner() {
         VectorMask mInt256 = VectorMask.fromArray(IntVector.SPECIES_256, mask_arr, 0);
         VectorMask res = testInt256ToByte64(mInt256);
+        mInt256 = mInt256.not();
         Asserts.assertEquals(res.toString(), mInt256.toString());
         Asserts.assertEquals(res.trueCount(), mInt256.trueCount());
     }
@@ -484,13 +515,14 @@ public class VectorMaskCastTest {
     @Test
     @IR(counts = { IRNode.VECTOR_MASK_CAST, "> 0" }, applyIfCPUFeature = {"avx512vl", "true"})
     public static VectorMask testInt256ToLong512(VectorMask v) {
-        return v.cast(LongVector.SPECIES_512);
+        return v.not().cast(LongVector.SPECIES_512);
     }
 
     @Run(test = "testInt256ToLong512")
     public static void testInt256ToLong512_runner() {
         VectorMask mInt256 = VectorMask.fromArray(IntVector.SPECIES_256, mask_arr, 0);
         VectorMask res = testInt256ToLong512(mInt256);
+        mInt256 = mInt256.not();
         Asserts.assertEquals(res.toString(), mInt256.toString());
         Asserts.assertEquals(res.trueCount(), mInt256.trueCount());
     }
@@ -498,13 +530,14 @@ public class VectorMaskCastTest {
     @Test
     @IR(counts = { IRNode.VECTOR_MASK_CAST, "> 0" }, applyIfCPUFeature = {"avx512vl", "true"})
     public static VectorMask testInt256ToDouble512(VectorMask v) {
-        return v.cast(DoubleVector.SPECIES_512);
+        return v.not().cast(DoubleVector.SPECIES_512);
     }
 
     @Run(test = "testInt256ToDouble512")
     public static void testInt256ToDouble512_runner() {
         VectorMask mInt256 = VectorMask.fromArray(IntVector.SPECIES_256, mask_arr, 0);
         VectorMask res = testInt256ToDouble512(mInt256);
+        mInt256 = mInt256.not();
         Asserts.assertEquals(res.toString(), mInt256.toString());
         Asserts.assertEquals(res.trueCount(), mInt256.trueCount());
     }
@@ -512,13 +545,14 @@ public class VectorMaskCastTest {
     @Test
     @IR(counts = { IRNode.VECTOR_MASK_CAST, "> 0" }, applyIfCPUFeature = {"avx512vl", "true"})
     public static VectorMask testInt512ToShort256(VectorMask v) {
-        return v.cast(ShortVector.SPECIES_256);
+        return v.not().cast(ShortVector.SPECIES_256);
     }
 
     @Run(test = "testInt512ToShort256")
     public static void testInt512ToShort256_runner() {
         VectorMask mInt512 = VectorMask.fromArray(IntVector.SPECIES_512, mask_arr, 0);
         VectorMask res = testInt512ToShort256(mInt512);
+        mInt512 = mInt512.not();
         Asserts.assertEquals(res.toString(), mInt512.toString());
         Asserts.assertEquals(res.trueCount(), mInt512.trueCount());
     }
@@ -526,13 +560,14 @@ public class VectorMaskCastTest {
     @Test
     @IR(counts = { IRNode.VECTOR_MASK_CAST, "> 0" }, applyIfCPUFeature = {"avx512vl", "true"})
     public static VectorMask testInt512ToByte128(VectorMask v) {
-        return v.cast(ByteVector.SPECIES_128);
+        return v.not().cast(ByteVector.SPECIES_128);
     }
 
     @Run(test = "testInt512ToByte128")
     public static void testInt512ToByte128_runner() {
         VectorMask mInt512 = VectorMask.fromArray(IntVector.SPECIES_512, mask_arr, 0);
         VectorMask res = testInt512ToByte128(mInt512);
+        mInt512 = mInt512.not();
         Asserts.assertEquals(res.toString(), mInt512.toString());
         Asserts.assertEquals(res.trueCount(), mInt512.trueCount());
     }
@@ -541,13 +576,14 @@ public class VectorMaskCastTest {
     @Test
     @IR(counts = { IRNode.VECTOR_MASK_CAST, "> 0" }, applyIfCPUFeatureOr = {"asimd", "true", "rvv", "true"})
     public static VectorMask testFloat64ToLong128(VectorMask v) {
-        return v.cast(LongVector.SPECIES_128);
+        return v.not().cast(LongVector.SPECIES_128);
     }
 
     @Run(test = "testFloat64ToLong128")
     public static void testFloat64ToLong128_runner() {
         VectorMask mFloat64 = VectorMask.fromArray(FloatVector.SPECIES_64, mask_arr, 0);
         VectorMask res = testFloat64ToLong128(mFloat64);
+        mFloat64 = mFloat64.not();
         Asserts.assertEquals(res.toString(), mFloat64.toString());
         Asserts.assertEquals(res.trueCount(), mFloat64.trueCount());
     }
@@ -555,13 +591,14 @@ public class VectorMaskCastTest {
     @Test
     @IR(counts = { IRNode.VECTOR_MASK_CAST, "> 0" }, applyIfCPUFeatureOr = {"asimd", "true", "rvv", "true"})
     public static VectorMask testFloat64ToDouble128(VectorMask v) {
-        return v.cast(DoubleVector.SPECIES_128);
+        return v.not().cast(DoubleVector.SPECIES_128);
     }
 
     @Run(test = "testFloat64ToDouble128")
     public static void testFloat64ToDouble128_runner() {
         VectorMask mFloat64 = VectorMask.fromArray(FloatVector.SPECIES_64, mask_arr, 0);
         VectorMask res = testFloat64ToDouble128(mFloat64);
+        mFloat64 = mFloat64.not();
         Asserts.assertEquals(res.toString(), mFloat64.toString());
         Asserts.assertEquals(res.trueCount(), mFloat64.trueCount());
     }
@@ -569,13 +606,14 @@ public class VectorMaskCastTest {
     @Test
     @IR(counts = { IRNode.VECTOR_MASK_CAST, "> 0" }, applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true", "rvv", "true"})
     public static VectorMask testFloat128ToShort64(VectorMask v) {
-        return v.cast(ShortVector.SPECIES_64);
+        return v.not().cast(ShortVector.SPECIES_64);
     }
 
     @Run(test = "testFloat128ToShort64")
     public static void testFloat128ToShort64_runner() {
         VectorMask mFloat128 = VectorMask.fromArray(FloatVector.SPECIES_128, mask_arr, 0);
         VectorMask res = testFloat128ToShort64(mFloat128);
+        mFloat128 = mFloat128.not();
         Asserts.assertEquals(res.toString(), mFloat128.toString());
         Asserts.assertEquals(res.trueCount(), mFloat128.trueCount());
     }
@@ -583,13 +621,14 @@ public class VectorMaskCastTest {
     @Test
     @IR(counts = { IRNode.VECTOR_MASK_CAST, "> 0" }, applyIfCPUFeature = {"avx2", "true"})
     public static VectorMask testFloat128ToLong256(VectorMask v) {
-        return v.cast(LongVector.SPECIES_256);
+        return v.not().cast(LongVector.SPECIES_256);
     }
 
     @Run(test = "testFloat128ToLong256")
     public static void testFloat128ToLong256_runner() {
         VectorMask mFloat128 = VectorMask.fromArray(FloatVector.SPECIES_128, mask_arr, 0);
         VectorMask res = testFloat128ToLong256(mFloat128);
+        mFloat128 = mFloat128.not();
         Asserts.assertEquals(res.toString(), mFloat128.toString());
         Asserts.assertEquals(res.trueCount(), mFloat128.trueCount());
     }
@@ -597,13 +636,14 @@ public class VectorMaskCastTest {
     @Test
     @IR(counts = { IRNode.VECTOR_MASK_CAST, "> 0" }, applyIfCPUFeature = {"avx2", "true"})
     public static VectorMask testFloat128ToDouble256(VectorMask v) {
-        return v.cast(DoubleVector.SPECIES_256);
+        return v.not().cast(DoubleVector.SPECIES_256);
     }
 
     @Run(test = "testFloat128ToDouble256")
     public static void testFloat128ToDouble256_runner() {
         VectorMask mFloat128 = VectorMask.fromArray(FloatVector.SPECIES_128, mask_arr, 0);
         VectorMask res = testFloat128ToDouble256(mFloat128);
+        mFloat128 = mFloat128.not();
         Asserts.assertEquals(res.toString(), mFloat128.toString());
         Asserts.assertEquals(res.trueCount(), mFloat128.trueCount());
     }
@@ -611,13 +651,14 @@ public class VectorMaskCastTest {
     @Test
     @IR(counts = { IRNode.VECTOR_MASK_CAST, "> 0" }, applyIfCPUFeature = {"avx2", "true"})
     public static VectorMask testFloat256ToShort128(VectorMask v) {
-        return v.cast(ShortVector.SPECIES_128);
+        return v.not().cast(ShortVector.SPECIES_128);
     }
 
     @Run(test = "testFloat256ToShort128")
     public static void testFloat256ToShort128_runner() {
         VectorMask mFloat256 = VectorMask.fromArray(FloatVector.SPECIES_256, mask_arr, 0);
         VectorMask res = testFloat256ToShort128(mFloat256);
+        mFloat256 = mFloat256.not();
         Asserts.assertEquals(res.toString(), mFloat256.toString());
         Asserts.assertEquals(res.trueCount(), mFloat256.trueCount());
     }
@@ -625,13 +666,14 @@ public class VectorMaskCastTest {
     @Test
     @IR(counts = { IRNode.VECTOR_MASK_CAST, "> 0" }, applyIfCPUFeature = {"avx2", "true"})
     public static VectorMask testFloat256ToByte64(VectorMask v) {
-        return v.cast(ByteVector.SPECIES_64);
+        return v.not().cast(ByteVector.SPECIES_64);
     }
 
     @Run(test = "testFloat256ToByte64")
     public static void testFloat256ToByte64_runner() {
         VectorMask mFloat256 = VectorMask.fromArray(FloatVector.SPECIES_256, mask_arr, 0);
         VectorMask res = testFloat256ToByte64(mFloat256);
+        mFloat256 = mFloat256.not();
         Asserts.assertEquals(res.toString(), mFloat256.toString());
         Asserts.assertEquals(res.trueCount(), mFloat256.trueCount());
     }
@@ -639,13 +681,14 @@ public class VectorMaskCastTest {
     @Test
     @IR(counts = { IRNode.VECTOR_MASK_CAST, "> 0" }, applyIfCPUFeature = {"avx512vl", "true"})
     public static VectorMask testFloat256ToLong512(VectorMask v) {
-        return v.cast(LongVector.SPECIES_512);
+        return v.not().cast(LongVector.SPECIES_512);
     }
 
     @Run(test = "testFloat256ToLong512")
     public static void testFloat256ToLong512_runner() {
         VectorMask mFloat256 = VectorMask.fromArray(FloatVector.SPECIES_256, mask_arr, 0);
         VectorMask res = testFloat256ToLong512(mFloat256);
+        mFloat256 = mFloat256.not();
         Asserts.assertEquals(res.toString(), mFloat256.toString());
         Asserts.assertEquals(res.trueCount(), mFloat256.trueCount());
     }
@@ -653,13 +696,14 @@ public class VectorMaskCastTest {
     @Test
     @IR(counts = { IRNode.VECTOR_MASK_CAST, "> 0" }, applyIfCPUFeature = {"avx512vl", "true"})
     public static VectorMask testFloat256ToDouble512(VectorMask v) {
-        return v.cast(DoubleVector.SPECIES_512);
+        return v.not().cast(DoubleVector.SPECIES_512);
     }
 
     @Run(test = "testFloat256ToDouble512")
     public static void testFloat256ToDouble512_runner() {
         VectorMask mFloat256 = VectorMask.fromArray(FloatVector.SPECIES_256, mask_arr, 0);
         VectorMask res = testFloat256ToDouble512(mFloat256);
+        mFloat256 = mFloat256.not();
         Asserts.assertEquals(res.toString(), mFloat256.toString());
         Asserts.assertEquals(res.trueCount(), mFloat256.trueCount());
     }
@@ -667,13 +711,14 @@ public class VectorMaskCastTest {
     @Test
     @IR(counts = { IRNode.VECTOR_MASK_CAST, "> 0" }, applyIfCPUFeature = {"avx512vl", "true"})
     public static VectorMask testFloat512ToShort256(VectorMask v) {
-        return v.cast(ShortVector.SPECIES_256);
+        return v.not().cast(ShortVector.SPECIES_256);
     }
 
     @Run(test = "testFloat512ToShort256")
     public static void testFloat512ToShort256_runner() {
         VectorMask mFloat512 = VectorMask.fromArray(FloatVector.SPECIES_512, mask_arr, 0);
         VectorMask res = testFloat512ToShort256(mFloat512);
+        mFloat512 = mFloat512.not();
         Asserts.assertEquals(res.toString(), mFloat512.toString());
         Asserts.assertEquals(res.trueCount(), mFloat512.trueCount());
     }
@@ -681,13 +726,14 @@ public class VectorMaskCastTest {
     @Test
     @IR(counts = { IRNode.VECTOR_MASK_CAST, "> 0" }, applyIfCPUFeature = {"avx512vl", "true"})
     public static VectorMask testFloat512ToByte128(VectorMask v) {
-        return v.cast(ByteVector.SPECIES_128);
+        return v.not().cast(ByteVector.SPECIES_128);
     }
 
     @Run(test = "testFloat512ToByte128")
     public static void testFloat512ToByte128_runner() {
         VectorMask mFloat512 = VectorMask.fromArray(FloatVector.SPECIES_512, mask_arr, 0);
         VectorMask res = testFloat512ToByte128(mFloat512);
+        mFloat512 = mFloat512.not();
         Asserts.assertEquals(res.toString(), mFloat512.toString());
         Asserts.assertEquals(res.trueCount(), mFloat512.trueCount());
     }
@@ -696,13 +742,14 @@ public class VectorMaskCastTest {
     @Test
     @IR(counts = { IRNode.VECTOR_MASK_CAST, "> 0" }, applyIfCPUFeatureOr = {"asimd", "true", "rvv", "true"})
     public static VectorMask testLong128ToInt64(VectorMask v) {
-        return v.cast(IntVector.SPECIES_64);
+        return v.not().cast(IntVector.SPECIES_64);
     }
 
     @Run(test = "testLong128ToInt64")
     public static void testLong128ToInt64_runner() {
         VectorMask mLong128 = VectorMask.fromArray(LongVector.SPECIES_128, mask_arr, 0);
         VectorMask res = testLong128ToInt64(mLong128);
+        mLong128 = mLong128.not();
         Asserts.assertEquals(res.toString(), mLong128.toString());
         Asserts.assertEquals(res.trueCount(), mLong128.trueCount());
     }
@@ -710,13 +757,14 @@ public class VectorMaskCastTest {
     @Test
     @IR(counts = { IRNode.VECTOR_MASK_CAST, "> 0" }, applyIfCPUFeatureOr = {"asimd", "true", "rvv", "true"})
     public static VectorMask testLong128ToFloat64(VectorMask v) {
-        return v.cast(FloatVector.SPECIES_64);
+        return v.not().cast(FloatVector.SPECIES_64);
     }
 
     @Run(test = "testLong128ToFloat64")
     public static void testLong128ToFloat64_runner() {
         VectorMask mLong128 = VectorMask.fromArray(LongVector.SPECIES_128, mask_arr, 0);
         VectorMask res = testLong128ToFloat64(mLong128);
+        mLong128 = mLong128.not();
         Asserts.assertEquals(res.toString(), mLong128.toString());
         Asserts.assertEquals(res.trueCount(), mLong128.trueCount());
     }
@@ -724,13 +772,14 @@ public class VectorMaskCastTest {
     @Test
     @IR(counts = { IRNode.VECTOR_MASK_CAST, "> 0" }, applyIfCPUFeature = {"avx2", "true"})
     public static VectorMask testLong256ToInt128(VectorMask v) {
-        return v.cast(IntVector.SPECIES_128);
+        return v.not().cast(IntVector.SPECIES_128);
     }
 
     @Run(test = "testLong256ToInt128")
     public static void testLong256ToInt128_runner() {
         VectorMask mLong256 = VectorMask.fromArray(LongVector.SPECIES_256, mask_arr, 0);
         VectorMask res = testLong256ToInt128(mLong256);
+        mLong256 = mLong256.not();
         Asserts.assertEquals(res.toString(), mLong256.toString());
         Asserts.assertEquals(res.trueCount(), mLong256.trueCount());
     }
@@ -738,13 +787,14 @@ public class VectorMaskCastTest {
     @Test
     @IR(counts = { IRNode.VECTOR_MASK_CAST, "> 0" }, applyIfCPUFeature = {"avx2", "true"})
     public static VectorMask testLong256ToFloat128(VectorMask v) {
-        return v.cast(FloatVector.SPECIES_128);
+        return v.not().cast(FloatVector.SPECIES_128);
     }
 
     @Run(test = "testLong256ToFloat128")
     public static void testLong256ToFloat128_runner() {
         VectorMask mLong256 = VectorMask.fromArray(LongVector.SPECIES_256, mask_arr, 0);
         VectorMask res = testLong256ToFloat128(mLong256);
+        mLong256 = mLong256.not();
         Asserts.assertEquals(res.toString(), mLong256.toString());
         Asserts.assertEquals(res.trueCount(), mLong256.trueCount());
     }
@@ -752,13 +802,14 @@ public class VectorMaskCastTest {
     @Test
     @IR(counts = { IRNode.VECTOR_MASK_CAST, "> 0" }, applyIfCPUFeature = {"avx2", "true"})
     public static VectorMask testLong256ToShort64(VectorMask v) {
-       return v.cast(ShortVector.SPECIES_64);
+       return v.not().cast(ShortVector.SPECIES_64);
     }
 
     @Run(test = "testLong256ToShort64")
     public static void testLong256ToShort64_runner() {
         VectorMask mLong256 = VectorMask.fromArray(LongVector.SPECIES_256, mask_arr, 0);
         VectorMask res = testLong256ToShort64(mLong256);
+        mLong256 = mLong256.not();
         Asserts.assertEquals(res.toString(), mLong256.toString());
         Asserts.assertEquals(res.trueCount(), mLong256.trueCount());
     }
@@ -766,13 +817,14 @@ public class VectorMaskCastTest {
     @Test
     @IR(counts = { IRNode.VECTOR_MASK_CAST, "> 0" }, applyIfCPUFeature = {"avx512vl", "true"})
     public static VectorMask testLong512ToInt256(VectorMask v) {
-        return v.cast(IntVector.SPECIES_256);
+        return v.not().cast(IntVector.SPECIES_256);
     }
 
     @Run(test = "testLong512ToInt256")
     public static void testLong512ToInt256_runner() {
         VectorMask mLong512 = VectorMask.fromArray(LongVector.SPECIES_512, mask_arr, 0);
         VectorMask res = testLong512ToInt256(mLong512);
+        mLong512 = mLong512.not();
         Asserts.assertEquals(res.toString(), mLong512.toString());
         Asserts.assertEquals(res.trueCount(), mLong512.trueCount());
     }
@@ -780,13 +832,14 @@ public class VectorMaskCastTest {
     @Test
     @IR(counts = { IRNode.VECTOR_MASK_CAST, "> 0" }, applyIfCPUFeature = {"avx512vl", "true"})
     public static VectorMask testLong512ToFloat256(VectorMask v) {
-        return v.cast(FloatVector.SPECIES_256);
+        return v.not().cast(FloatVector.SPECIES_256);
     }
 
     @Run(test = "testLong512ToFloat256")
     public static void testLong512ToFloat256_runner() {
         VectorMask mLong512 = VectorMask.fromArray(LongVector.SPECIES_512, mask_arr, 0);
         VectorMask res = testLong512ToFloat256(mLong512);
+        mLong512 = mLong512.not();
         Asserts.assertEquals(res.toString(), mLong512.toString());
         Asserts.assertEquals(res.trueCount(), mLong512.trueCount());
     }
@@ -794,13 +847,14 @@ public class VectorMaskCastTest {
     @Test
     @IR(counts = { IRNode.VECTOR_MASK_CAST, "> 0" }, applyIfCPUFeature = {"avx512vl", "true"})
     public static VectorMask testLong512ToShort128(VectorMask v) {
-        return v.cast(ShortVector.SPECIES_128);
+        return v.not().cast(ShortVector.SPECIES_128);
     }
 
     @Run(test = "testLong512ToShort128")
     public static void testLong512ToShort128_runner() {
         VectorMask mLong512 = VectorMask.fromArray(LongVector.SPECIES_512, mask_arr, 0);
         VectorMask res = testLong512ToShort128(mLong512);
+        mLong512 = mLong512.not();
         Asserts.assertEquals(res.toString(), mLong512.toString());
         Asserts.assertEquals(res.trueCount(), mLong512.trueCount());
     }
@@ -808,13 +862,14 @@ public class VectorMaskCastTest {
     @Test
     @IR(counts = { IRNode.VECTOR_MASK_CAST, "> 0" }, applyIfCPUFeature = {"avx512vl", "true"})
     public static VectorMask testLong512ToByte64(VectorMask v) {
-        return v.cast(ByteVector.SPECIES_64);
+        return v.not().cast(ByteVector.SPECIES_64);
     }
 
     @Run(test = "testLong512ToByte64")
     public static void testLong512ToByte64_runner() {
         VectorMask mLong512 = VectorMask.fromArray(LongVector.SPECIES_512, mask_arr, 0);
         VectorMask res = testLong512ToByte64(mLong512);
+        mLong512 = mLong512.not();
         Asserts.assertEquals(res.toString(), mLong512.toString());
         Asserts.assertEquals(res.trueCount(), mLong512.trueCount());
     }
@@ -823,13 +878,14 @@ public class VectorMaskCastTest {
     @Test
     @IR(counts = { IRNode.VECTOR_MASK_CAST, "> 0" }, applyIfCPUFeatureOr = {"asimd", "true", "rvv", "true"})
     public static VectorMask testDouble128ToInt64(VectorMask v) {
-        return v.cast(IntVector.SPECIES_64);
+        return v.not().cast(IntVector.SPECIES_64);
     }
 
     @Run(test = "testDouble128ToInt64")
     public static void testDouble128ToInt64_runner() {
         VectorMask mDouble128 = VectorMask.fromArray(DoubleVector.SPECIES_128, mask_arr, 0);
         VectorMask res = testDouble128ToInt64(mDouble128);
+        mDouble128 = mDouble128.not();
         Asserts.assertEquals(res.toString(), mDouble128.toString());
         Asserts.assertEquals(res.trueCount(), mDouble128.trueCount());
     }
@@ -837,13 +893,14 @@ public class VectorMaskCastTest {
     @Test
     @IR(counts = { IRNode.VECTOR_MASK_CAST, "> 0" }, applyIfCPUFeatureOr = {"asimd", "true", "rvv", "true"})
     public static VectorMask testDouble128ToFloat64(VectorMask v) {
-        return v.cast(FloatVector.SPECIES_64);
+        return v.not().cast(FloatVector.SPECIES_64);
     }
 
     @Run(test = "testDouble128ToFloat64")
     public static void testDouble128ToFloat64_runner() {
         VectorMask mDouble128 = VectorMask.fromArray(DoubleVector.SPECIES_128, mask_arr, 0);
         VectorMask res = testDouble128ToFloat64(mDouble128);
+        mDouble128 = mDouble128.not();
         Asserts.assertEquals(res.toString(), mDouble128.toString());
         Asserts.assertEquals(res.trueCount(), mDouble128.trueCount());
     }
@@ -851,13 +908,14 @@ public class VectorMaskCastTest {
     @Test
     @IR(counts = { IRNode.VECTOR_MASK_CAST, "> 0" }, applyIfCPUFeature = {"avx2", "true"})
     public static VectorMask testDouble256ToInt128(VectorMask v) {
-        return v.cast(IntVector.SPECIES_128);
+        return v.not().cast(IntVector.SPECIES_128);
     }
 
     @Run(test = "testDouble256ToInt128")
     public static void testDouble256ToInt128_runner() {
         VectorMask mDouble256 = VectorMask.fromArray(DoubleVector.SPECIES_256, mask_arr, 0);
         VectorMask res = testDouble256ToInt128(mDouble256);
+        mDouble256 = mDouble256.not();
         Asserts.assertEquals(res.toString(), mDouble256.toString());
         Asserts.assertEquals(res.trueCount(), mDouble256.trueCount());
     }
@@ -865,13 +923,14 @@ public class VectorMaskCastTest {
     @Test
     @IR(counts = { IRNode.VECTOR_MASK_CAST, "> 0" }, applyIfCPUFeature = {"avx2", "true"})
     public static VectorMask testDouble256ToFloat128(VectorMask v) {
-        return v.cast(FloatVector.SPECIES_128);
+        return v.not().cast(FloatVector.SPECIES_128);
     }
 
     @Run(test = "testDouble256ToFloat128")
     public static void testDouble256ToFloat128_runner() {
         VectorMask mDouble256 = VectorMask.fromArray(DoubleVector.SPECIES_256, mask_arr, 0);
         VectorMask res = testDouble256ToFloat128(mDouble256);
+        mDouble256 = mDouble256.not();
         Asserts.assertEquals(res.toString(), mDouble256.toString());
         Asserts.assertEquals(res.trueCount(), mDouble256.trueCount());
     }
@@ -879,13 +938,14 @@ public class VectorMaskCastTest {
     @Test
     @IR(counts = { IRNode.VECTOR_MASK_CAST, "> 0" }, applyIfCPUFeature = {"avx2", "true"})
     public static VectorMask testDouble256ToShort64(VectorMask v) {
-        return v.cast(ShortVector.SPECIES_64);
+        return v.not().cast(ShortVector.SPECIES_64);
     }
 
     @Run(test = "testDouble256ToShort64")
     public static void testDouble256ToShort64_runner() {
         VectorMask mDouble256 = VectorMask.fromArray(DoubleVector.SPECIES_256, mask_arr, 0);
         VectorMask res = testDouble256ToShort64(mDouble256);
+        mDouble256 = mDouble256.not();
         Asserts.assertEquals(res.toString(), mDouble256.toString());
         Asserts.assertEquals(res.trueCount(), mDouble256.trueCount());
     }
@@ -893,13 +953,14 @@ public class VectorMaskCastTest {
     @Test
     @IR(counts = { IRNode.VECTOR_MASK_CAST, "> 0" }, applyIfCPUFeature = {"avx512vl", "true"})
     public static VectorMask testDouble512ToInt256(VectorMask v) {
-        return v.cast(IntVector.SPECIES_256);
+        return v.not().cast(IntVector.SPECIES_256);
     }
 
     @Run(test = "testDouble512ToInt256")
     public static void testDouble512ToInt256_runner() {
         VectorMask mDouble512 = VectorMask.fromArray(DoubleVector.SPECIES_512, mask_arr, 0);
         VectorMask res = testDouble512ToInt256(mDouble512);
+        mDouble512 = mDouble512.not();
         Asserts.assertEquals(res.toString(), mDouble512.toString());
         Asserts.assertEquals(res.trueCount(), mDouble512.trueCount());
     }
@@ -907,13 +968,14 @@ public class VectorMaskCastTest {
     @Test
     @IR(counts = { IRNode.VECTOR_MASK_CAST, "> 0" }, applyIfCPUFeature = {"avx512vl", "true"})
     public static VectorMask testDouble512ToFloat256(VectorMask v) {
-        return v.cast(FloatVector.SPECIES_256);
+        return v.not().cast(FloatVector.SPECIES_256);
     }
 
     @Run(test = "testDouble512ToFloat256")
     public static void testDouble512ToFloat256_runner() {
         VectorMask mDouble512 = VectorMask.fromArray(DoubleVector.SPECIES_512, mask_arr, 0);
         VectorMask res = testDouble512ToFloat256(mDouble512);
+        mDouble512 = mDouble512.not();
         Asserts.assertEquals(res.toString(), mDouble512.toString());
         Asserts.assertEquals(res.trueCount(), mDouble512.trueCount());
     }
@@ -921,13 +983,14 @@ public class VectorMaskCastTest {
     @Test
     @IR(counts = { IRNode.VECTOR_MASK_CAST, "> 0" }, applyIfCPUFeature = {"avx512vl", "true"})
     public static VectorMask testDouble512ToShort128(VectorMask v) {
-        return v.cast(ShortVector.SPECIES_128);
+        return v.not().cast(ShortVector.SPECIES_128);
     }
 
     @Run(test = "testDouble512ToShort128")
     public static void testDouble512ToShort128_runner() {
         VectorMask mDouble512 = VectorMask.fromArray(DoubleVector.SPECIES_512, mask_arr, 0);
         VectorMask res = testDouble512ToShort128(mDouble512);
+        mDouble512 = mDouble512.not();
         Asserts.assertEquals(res.toString(), mDouble512.toString());
         Asserts.assertEquals(res.trueCount(), mDouble512.trueCount());
     }
@@ -935,13 +998,14 @@ public class VectorMaskCastTest {
     @Test
     @IR(counts = { IRNode.VECTOR_MASK_CAST, "> 0" }, applyIfCPUFeature = {"avx512vl", "true"})
     public static VectorMask testDouble512ToByte64(VectorMask v) {
-        return v.cast(ByteVector.SPECIES_64);
+        return v.not().cast(ByteVector.SPECIES_64);
     }
 
     @Run(test = "testDouble512ToByte64")
     public static void testDouble512ToByte64_runner() {
         VectorMask mDouble512 = VectorMask.fromArray(DoubleVector.SPECIES_512, mask_arr, 0);
         VectorMask res = testDouble512ToByte64(mDouble512);
+        mDouble512 = mDouble512.not();
         Asserts.assertEquals(res.toString(), mDouble512.toString());
         Asserts.assertEquals(res.trueCount(), mDouble512.trueCount());
     }
diff --git a/test/hotspot/jtreg/compiler/vectorapi/VectorMaskToLongTest.java b/test/hotspot/jtreg/compiler/vectorapi/VectorMaskToLongTest.java
index 35a5aca966a..43415496072 100644
--- a/test/hotspot/jtreg/compiler/vectorapi/VectorMaskToLongTest.java
+++ b/test/hotspot/jtreg/compiler/vectorapi/VectorMaskToLongTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * Copyright (c) 2025, 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -236,10 +236,29 @@ public class VectorMaskToLongTest {
         verifyMaskToLong(L_SPECIES, inputLong, got);
     }
 
+    // Test VectorMask.fromLong().toLong() with Float species.
+    // For floating-point types, VectorMaskCast is inserted between fromLong and toLong to convert
+    // between float and integer types. There are two relevant optimizations:
+    //   1. (VectorStoreMask (VectorMaskCast* (VectorLoadMask x))) => (x)
+    //   2. (VectorMaskToLong (VectorLongToMask x)) => (x)
+    // The optimization behavior varies by architecture:
+    // - SVE with bitperm: IR chain is (VectorMaskToLong (VectorStoreMask (VectorMaskCast
+    //   (VectorLoadMask (VectorLongToMask x))))), so both optimizations are triggered.
+    // - AVX-512/RVV: IR pattern is (VectorMaskToLong (VectorMaskCast (VectorLongToMask x))),
+    //   so neither optimization is triggered.
+    // - AVX2: Same as SVE with bitperm, both optimizations are triggered.
+    // - ASIMD (without SVE bitperm): VectorLongToMaskNode is not supported,
+    //   so neither optimization is triggered.
     @Test
+    @IR(counts = { IRNode.VECTOR_LONG_TO_MASK, "= 0",
+                   IRNode.VECTOR_MASK_TO_LONG, "= 0" },
+        applyIfCPUFeature = { "svebitperm", "true" })
     @IR(counts = { IRNode.VECTOR_LONG_TO_MASK, "= 1",
                    IRNode.VECTOR_MASK_TO_LONG, "= 1" },
-        applyIfCPUFeatureOr = { "svebitperm", "true", "avx2", "true", "rvv", "true" })
+        applyIfCPUFeatureOr = { "avx512", "true", "rvv", "true" })
+    @IR(counts = { IRNode.VECTOR_LONG_TO_MASK, "= 0",
+                   IRNode.VECTOR_MASK_TO_LONG, "= 0" },
+        applyIfCPUFeatureAnd = { "avx2", "true", "avx512", "false" })
     @IR(counts = { IRNode.VECTOR_LONG_TO_MASK, "= 0",
                    IRNode.VECTOR_MASK_TO_LONG, "= 1" },
         applyIfCPUFeatureAnd = { "asimd", "true", "svebitperm", "false" })
@@ -250,10 +269,18 @@ public class VectorMaskToLongTest {
         verifyMaskToLong(F_SPECIES, inputLong, got);
     }
 
+    // Test VectorMask.fromLong().toLong() with Double species.
+    // Same as testFromLongToLongFloat() - see comments there for detailed explanation.
     @Test
+    @IR(counts = { IRNode.VECTOR_LONG_TO_MASK, "= 0",
+                   IRNode.VECTOR_MASK_TO_LONG, "= 0" },
+        applyIfCPUFeature = { "svebitperm", "true" })
     @IR(counts = { IRNode.VECTOR_LONG_TO_MASK, "= 1",
                    IRNode.VECTOR_MASK_TO_LONG, "= 1" },
-        applyIfCPUFeatureOr = { "svebitperm", "true", "avx2", "true", "rvv", "true" })
+        applyIfCPUFeatureOr = { "avx512", "true", "rvv", "true" })
+    @IR(counts = { IRNode.VECTOR_LONG_TO_MASK, "= 0",
+                   IRNode.VECTOR_MASK_TO_LONG, "= 0" },
+        applyIfCPUFeatureAnd = { "avx2", "true", "avx512", "false" })
     @IR(counts = { IRNode.VECTOR_LONG_TO_MASK, "= 0",
                    IRNode.VECTOR_MASK_TO_LONG, "= 1" },
         applyIfCPUFeatureAnd = { "asimd", "true", "svebitperm", "false" })
diff --git a/test/hotspot/jtreg/compiler/vectorapi/VectorStoreMaskIdentityTest.java b/test/hotspot/jtreg/compiler/vectorapi/VectorStoreMaskIdentityTest.java
new file mode 100644
index 00000000000..c019f116373
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/vectorapi/VectorStoreMaskIdentityTest.java
@@ -0,0 +1,317 @@
+/*
+ * Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+* @test
+* @bug 8370863
+* @library /test/lib /
+* @summary VectorStoreMaskNode Identity optimization tests
+* @modules jdk.incubator.vector
+*
+* @run driver ${test.main.class}
+*/
+
+package compiler.vectorapi;
+
+import compiler.lib.ir_framework.*;
+import jdk.incubator.vector.*;
+import jdk.test.lib.Asserts;
+
+public class VectorStoreMaskIdentityTest {
+    private static final VectorSpecies B64 = ByteVector.SPECIES_64;
+    private static final VectorSpecies S64 = ShortVector.SPECIES_64;
+    private static final VectorSpecies S128 = ShortVector.SPECIES_128;
+    private static final VectorSpecies I64 = IntVector.SPECIES_64;
+    private static final VectorSpecies I128 = IntVector.SPECIES_128;
+    private static final VectorSpecies I256 = IntVector.SPECIES_256;
+    private static final VectorSpecies L128 = LongVector.SPECIES_128;
+    private static final VectorSpecies L256 = LongVector.SPECIES_256;
+    private static final VectorSpecies F128 = FloatVector.SPECIES_128;
+    private static final VectorSpecies F256 = FloatVector.SPECIES_256;
+    private static final VectorSpecies D128 = DoubleVector.SPECIES_128;
+    private static final VectorSpecies D256 = DoubleVector.SPECIES_256;
+    private static final int LENGTH = 256; // large enough
+    private static boolean[] mask_in;
+    private static boolean[] mask_out;
+    static {
+        mask_in = new boolean[LENGTH];
+        mask_out = new boolean[LENGTH];
+        for (int i = 0; i < LENGTH; i++) {
+            mask_in[i] = (i & 3) == 0;
+        }
+    }
+
+    @DontInline
+    private static void verifyResult(int vlen) {
+        for (int i = 0; i < vlen; i++) {
+            Asserts.assertEquals(mask_in[i], mask_out[i], "index " + i);
+        }
+    }
+
+    @Test
+    @IR(counts = { IRNode.LOAD_VECTOR_Z, IRNode.VECTOR_SIZE_8, ">= 1",
+                   IRNode.VECTOR_LOAD_MASK, "= 0",
+                   IRNode.VECTOR_STORE_MASK, "= 0",
+                   IRNode.VECTOR_MASK_CAST, "= 0" },
+        applyIfCPUFeatureOr = { "asimd", "true", "avx", "true" },
+        applyIf = { "MaxVectorSize", ">= 16" })
+    public static void testVectorMaskStoreIdentityByte() {
+        VectorMask mask_byte_64 = VectorMask.fromArray(B64, mask_in, 0);
+
+        mask_byte_64.cast(S128).intoArray(mask_out, 0);
+        verifyResult(B64.length());
+
+        mask_byte_64.cast(S128).cast(B64).intoArray(mask_out, 0);
+        verifyResult(B64.length());
+
+        mask_byte_64.cast(S128).cast(B64).cast(S128).intoArray(mask_out, 0);
+        verifyResult(B64.length());
+    }
+
+    @Test
+    @IR(counts = { IRNode.LOAD_VECTOR_Z, IRNode.VECTOR_SIZE_8, ">= 1",
+                   IRNode.VECTOR_LOAD_MASK, "= 0",
+                   IRNode.VECTOR_STORE_MASK, "= 0",
+                   IRNode.VECTOR_MASK_CAST, "= 0" },
+        applyIfCPUFeatureOr = { "sve", "true", "avx2", "true" },
+        applyIf = { "MaxVectorSize", "> 16" })
+    public static void testVectorMaskStoreIdentityByte256() {
+        VectorMask mask_byte_64 = VectorMask.fromArray(B64, mask_in, 0);
+
+        mask_byte_64.cast(I256).intoArray(mask_out, 0);
+        verifyResult(B64.length());
+
+        mask_byte_64.cast(S128).cast(F256).intoArray(mask_out, 0);
+        verifyResult(B64.length());
+
+        mask_byte_64.cast(F256).cast(S128).cast(I256).intoArray(mask_out, 0);
+        verifyResult(B64.length());
+    }
+
+    @Test
+    @IR(counts = { IRNode.LOAD_VECTOR_Z, IRNode.VECTOR_SIZE_8, ">= 1",
+                   IRNode.VECTOR_LOAD_MASK, "= 0",
+                   IRNode.VECTOR_STORE_MASK, "= 0",
+                   IRNode.VECTOR_MASK_CAST, "= 0" },
+        applyIfCPUFeatureOr = { "asimd", "true", "avx", "true" },
+        applyIf = { "MaxVectorSize", ">= 16" })
+    public static void testVectorMaskStoreIdentityShort() {
+        VectorMask mask_short_128 = VectorMask.fromArray(S128, mask_in, 0);
+
+        mask_short_128.cast(B64).intoArray(mask_out, 0);
+        verifyResult(S128.length());
+
+        mask_short_128.cast(B64).cast(S128).intoArray(mask_out, 0);
+        verifyResult(S128.length());
+
+        mask_short_128.cast(B64).cast(S128).cast(B64).intoArray(mask_out, 0);
+        verifyResult(S128.length());
+    }
+
+    @Test
+    @IR(counts = { IRNode.LOAD_VECTOR_Z, IRNode.VECTOR_SIZE_8, ">= 1",
+                   IRNode.VECTOR_LOAD_MASK, "= 0",
+                   IRNode.VECTOR_STORE_MASK, "= 0",
+                   IRNode.VECTOR_MASK_CAST, "= 0" },
+        applyIfCPUFeatureOr = { "sve", "true", "avx2", "true" },
+        applyIf = { "MaxVectorSize", "> 16" })
+    public static void testVectorMaskStoreIdentityShort256() {
+        VectorMask mask_short_128 = VectorMask.fromArray(S128, mask_in, 0);
+
+        mask_short_128.cast(I256).intoArray(mask_out, 0);
+        verifyResult(S128.length());
+
+        mask_short_128.cast(B64).cast(I256).intoArray(mask_out, 0);
+        verifyResult(S128.length());
+
+        mask_short_128.cast(F256).cast(B64).cast(I256).intoArray(mask_out, 0);
+        verifyResult(S128.length());
+    }
+
+    @Test
+    @IR(counts = { IRNode.LOAD_VECTOR_Z, IRNode.VECTOR_SIZE_4, ">= 1",
+                   IRNode.VECTOR_LOAD_MASK, "= 0",
+                   IRNode.VECTOR_STORE_MASK, "= 0",
+                   IRNode.VECTOR_MASK_CAST, "= 0" },
+        applyIfCPUFeatureOr = { "asimd", "true", "avx", "true" },
+        applyIf = { "MaxVectorSize", ">= 16" })
+    public static void testVectorMaskStoreIdentityInt() {
+        VectorMask mask_int_128 = VectorMask.fromArray(I128, mask_in, 0);
+
+        mask_int_128.cast(F128).intoArray(mask_out, 0);
+        verifyResult(I128.length());
+
+        mask_int_128.cast(S64).cast(F128).intoArray(mask_out, 0);
+        verifyResult(I128.length());
+
+        mask_int_128.cast(F128).cast(I128).cast(S64).intoArray(mask_out, 0);
+        verifyResult(I128.length());
+    }
+
+    @Test
+    @IR(counts = { IRNode.LOAD_VECTOR_Z, IRNode.VECTOR_SIZE_4, ">= 1",
+                   IRNode.VECTOR_LOAD_MASK, "= 0",
+                   IRNode.VECTOR_STORE_MASK, "= 0",
+                   IRNode.VECTOR_MASK_CAST, "= 0" },
+        applyIfCPUFeatureOr = { "sve", "true", "avx2", "true" },
+        applyIf = { "MaxVectorSize", "> 16" })
+    public static void testVectorMaskStoreIdentityInt256() {
+        VectorMask mask_int_128 = VectorMask.fromArray(I128, mask_in, 0);
+
+        mask_int_128.cast(F128).intoArray(mask_out, 0);
+        verifyResult(I128.length());
+
+        mask_int_128.cast(S64).cast(L256).intoArray(mask_out, 0);
+        verifyResult(I128.length());
+
+        mask_int_128.cast(L256).cast(S64).cast(F128).intoArray(mask_out, 0);
+        verifyResult(I128.length());
+    }
+
+    @Test
+    @IR(counts = { IRNode.LOAD_VECTOR_Z, IRNode.VECTOR_SIZE_2, ">= 1",
+                   IRNode.VECTOR_LOAD_MASK, "= 0",
+                   IRNode.VECTOR_STORE_MASK, "= 0",
+                   IRNode.VECTOR_MASK_CAST, "= 0" },
+        applyIfCPUFeatureOr = { "asimd", "true" },
+        applyIf = { "MaxVectorSize", ">= 16" })
+    public static void testVectorMaskStoreIdentityLong() {
+        VectorMask mask_long_128 = VectorMask.fromArray(L128, mask_in, 0);
+
+        mask_long_128.cast(D128).intoArray(mask_out, 0);
+        verifyResult(L128.length());
+
+        mask_long_128.cast(I64).cast(D128).intoArray(mask_out, 0);
+        verifyResult(L128.length());
+
+        mask_long_128.cast(I64).cast(D128).cast(I64).intoArray(mask_out, 0);
+        verifyResult(L128.length());
+    }
+
+    @Test
+    @IR(counts = { IRNode.LOAD_VECTOR_Z, IRNode.VECTOR_SIZE_4, ">= 1",
+                   IRNode.VECTOR_LOAD_MASK, "= 0",
+                   IRNode.VECTOR_STORE_MASK, "= 0",
+                   IRNode.VECTOR_MASK_CAST, "= 0" },
+        applyIfCPUFeatureOr = { "sve", "true", "avx2", "true" },
+        applyIf = { "MaxVectorSize", "> 16" })
+    public static void testVectorMaskStoreIdentityLong256() {
+        VectorMask mask_long_256 = VectorMask.fromArray(L256, mask_in, 0);
+
+        mask_long_256.cast(I128).intoArray(mask_out, 0);
+        verifyResult(L256.length());
+
+        mask_long_256.cast(S64).cast(I128).intoArray(mask_out, 0);
+        verifyResult(L256.length());
+
+        mask_long_256.cast(F128).cast(I128).cast(S64).intoArray(mask_out, 0);
+        verifyResult(L256.length());
+    }
+
+    @Test
+    @IR(counts = { IRNode.LOAD_VECTOR_Z, IRNode.VECTOR_SIZE_4, ">= 1",
+                   IRNode.VECTOR_LOAD_MASK, "= 0",
+                   IRNode.VECTOR_STORE_MASK, "= 0",
+                   IRNode.VECTOR_MASK_CAST, "= 0" },
+        applyIfCPUFeatureOr = { "asimd", "true", "avx", "true" },
+        applyIf = { "MaxVectorSize", ">= 16" })
+    public static void testVectorMaskStoreIdentityFloat() {
+        VectorMask mask_float_128 = VectorMask.fromArray(F128, mask_in, 0);
+
+        mask_float_128.cast(I128).intoArray(mask_out, 0);
+        verifyResult(F128.length());
+
+        mask_float_128.cast(S64).cast(I128).intoArray(mask_out, 0);
+        verifyResult(F128.length());
+
+        mask_float_128.cast(S64).cast(I128).cast(S64).intoArray(mask_out, 0);
+        verifyResult(F128.length());
+    }
+
+    @Test
+    @IR(counts = { IRNode.LOAD_VECTOR_Z, IRNode.VECTOR_SIZE_4, ">= 1",
+                   IRNode.VECTOR_LOAD_MASK, "= 0",
+                   IRNode.VECTOR_STORE_MASK, "= 0",
+                   IRNode.VECTOR_MASK_CAST, "= 0" },
+        applyIfCPUFeatureOr = { "sve", "true", "avx2", "true" },
+        applyIf = { "MaxVectorSize", "> 16" })
+    public static void testVectorMaskStoreIdentityFloat256() {
+        VectorMask mask_float_128 = VectorMask.fromArray(F128, mask_in, 0);
+
+        mask_float_128.cast(I128).intoArray(mask_out, 0);
+        verifyResult(F128.length());
+
+        mask_float_128.cast(S64).cast(L256).intoArray(mask_out, 0);
+        verifyResult(F128.length());
+
+        mask_float_128.cast(L256).cast(S64).cast(I128).intoArray(mask_out, 0);
+        verifyResult(F128.length());
+    }
+
+    @Test
+    @IR(counts = { IRNode.LOAD_VECTOR_Z, IRNode.VECTOR_SIZE_2, ">= 1",
+                   IRNode.VECTOR_LOAD_MASK, "= 0",
+                   IRNode.VECTOR_STORE_MASK, "= 0",
+                   IRNode.VECTOR_MASK_CAST, "= 0" },
+        applyIfCPUFeatureOr = { "asimd", "true" },
+        applyIf = { "MaxVectorSize", ">= 16" })
+    public static void testVectorMaskStoreIdentityDouble() {
+        VectorMask mask_double_128 = VectorMask.fromArray(D128, mask_in, 0);
+
+        mask_double_128.cast(L128).intoArray(mask_out, 0);
+        verifyResult(D128.length());
+
+        mask_double_128.cast(I64).cast(L128).intoArray(mask_out, 0);
+        verifyResult(D128.length());
+
+        mask_double_128.cast(I64).cast(L128).cast(I64).intoArray(mask_out, 0);
+        verifyResult(D128.length());
+    }
+
+    @Test
+    @IR(counts = { IRNode.LOAD_VECTOR_Z, IRNode.VECTOR_SIZE_4, ">= 1",
+                   IRNode.VECTOR_LOAD_MASK, "= 0",
+                   IRNode.VECTOR_STORE_MASK, "= 0",
+                   IRNode.VECTOR_MASK_CAST, "= 0" },
+        applyIfCPUFeatureOr = { "sve", "true", "avx2", "true" },
+        applyIf = { "MaxVectorSize", "> 16" })
+    public static void testVectorMaskStoreIdentityDouble256() {
+        VectorMask mask_double_256 = VectorMask.fromArray(D256, mask_in, 0);
+
+        mask_double_256.cast(F128).intoArray(mask_out, 0);
+        verifyResult(D256.length());
+
+        mask_double_256.cast(S64).cast(I128).intoArray(mask_out, 0);
+        verifyResult(D256.length());
+
+        mask_double_256.cast(I128).cast(S64).cast(L256).intoArray(mask_out, 0);
+        verifyResult(D256.length());
+    }
+
+    public static void main(String[] args) {
+        TestFramework testFramework = new TestFramework();
+        testFramework.setDefaultWarmup(10000)
+                     .addFlags("--add-modules=jdk.incubator.vector")
+                     .start();
+    }
+}
\ No newline at end of file
diff --git a/test/micro/org/openjdk/bench/jdk/incubator/vector/VectorStoreMaskBenchmark.java b/test/micro/org/openjdk/bench/jdk/incubator/vector/VectorStoreMaskBenchmark.java
new file mode 100644
index 00000000000..d4dc321ccba
--- /dev/null
+++ b/test/micro/org/openjdk/bench/jdk/incubator/vector/VectorStoreMaskBenchmark.java
@@ -0,0 +1,84 @@
+/*
+ *  Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ *  DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ *  This code is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 only, as
+ *  published by the Free Software Foundation.
+ *
+ *  This code is distributed in the hope that it will be useful, but WITHOUT
+ *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ *  version 2 for more details (a copy is included in the LICENSE file that
+ *  accompanied this code).
+ *
+ *  You should have received a copy of the GNU General Public License version
+ *  2 along with this work; if not, write to the Free Software Foundation,
+ *  Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *  Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ *  or visit www.oracle.com if you need additional information or have any
+ *  questions.
+ *
+ */
+
+package org.openjdk.bench.jdk.incubator.vector;
+
+import jdk.incubator.vector.*;
+import java.util.concurrent.TimeUnit;
+import org.openjdk.jmh.annotations.*;
+
+@OutputTimeUnit(TimeUnit.MICROSECONDS)
+@State(Scope.Thread)
+@Warmup(iterations = 10, time = 1)
+@Measurement(iterations = 10, time = 1)
+@Fork(value = 1, jvmArgs = {"--add-modules=jdk.incubator.vector"})
+public class VectorStoreMaskBenchmark {
+    static final int LENGTH = 256;
+    static final boolean[] mask_arr_input = new boolean[LENGTH];
+    static final boolean[] mask_arr_output = new boolean[LENGTH];
+    static {
+        for (int i = 0; i < LENGTH; i++) {
+            mask_arr_input[i] = (i & 1) == 0;
+        }
+    }
+
+    @CompilerControl(CompilerControl.Mode.INLINE)
+    public  void maskLoadCastStoreKernel(VectorSpecies species_from, VectorSpecies species_to) {
+        for (int i = 0; i < LENGTH; i += species_from.length()) {
+            VectorMask mask_from = VectorMask.fromArray(species_from, mask_arr_input, i);
+            VectorMask mask_to = mask_from.cast(species_to);
+            mask_to.intoArray(mask_arr_output, i);
+        }
+    }
+
+    @Benchmark
+    public void microMaskLoadCastStoreByte64() {
+        maskLoadCastStoreKernel(ByteVector.SPECIES_64, ShortVector.SPECIES_128);
+    }
+
+    @Benchmark
+    public void microMaskLoadCastStoreShort64() {
+        maskLoadCastStoreKernel(ShortVector.SPECIES_64, IntVector.SPECIES_128);
+    }
+
+    @Benchmark
+    public void microMaskLoadCastStoreInt128() {
+        maskLoadCastStoreKernel(IntVector.SPECIES_128, ShortVector.SPECIES_64);
+    }
+
+    @Benchmark
+    public void microMaskLoadCastStoreLong128() {
+        maskLoadCastStoreKernel(LongVector.SPECIES_128, IntVector.SPECIES_64);
+    }
+
+    @Benchmark
+    public void microMaskLoadCastStoreFloat128() {
+        maskLoadCastStoreKernel(FloatVector.SPECIES_128, ShortVector.SPECIES_64);
+    }
+
+    @Benchmark
+    public void microMaskLoadCastStoreDouble128() {
+        maskLoadCastStoreKernel(DoubleVector.SPECIES_128, IntVector.SPECIES_64);
+    }
+}
\ No newline at end of file

From 23a08ee81e2cf9427cc569089f6d20ac210397a1 Mon Sep 17 00:00:00 2001
From: Andrew Dinn 
Date: Wed, 15 Apr 2026 09:19:40 +0000
Subject: [PATCH 289/359] 8382039: Add support do_arch_array_entry() template

Reviewed-by: kvn, asmehra
---
 src/hotspot/cpu/aarch64/aarch64_vector.ad     |  8 +-
 .../cpu/aarch64/c2_MacroAssembler_aarch64.cpp | 43 +++++++---
 .../cpu/aarch64/c2_MacroAssembler_aarch64.hpp |  1 +
 .../cpu/aarch64/stubDeclarations_aarch64.hpp  | 22 +++--
 .../cpu/aarch64/stubGenerator_aarch64.cpp     | 32 +++++--
 .../cpu/aarch64/stubRoutines_aarch64.cpp      |  6 +-
 .../cpu/aarch64/stubRoutines_aarch64.hpp      | 17 +++-
 src/hotspot/cpu/arm/stubDeclarations_arm.hpp  | 15 ++--
 src/hotspot/cpu/arm/stubRoutines_arm.cpp      |  2 +-
 src/hotspot/cpu/arm/stubRoutines_arm.hpp      | 14 ++-
 src/hotspot/cpu/ppc/stubDeclarations_ppc.hpp  | 15 ++--
 .../cpu/riscv/stubDeclarations_riscv.hpp      | 15 ++--
 src/hotspot/cpu/riscv/stubRoutines_riscv.cpp  |  6 +-
 src/hotspot/cpu/riscv/stubRoutines_riscv.hpp  | 14 ++-
 .../cpu/s390/stubDeclarations_s390.hpp        | 15 ++--
 src/hotspot/cpu/s390/stubRoutines_s390.cpp    |  6 +-
 src/hotspot/cpu/s390/stubRoutines_s390.hpp    | 14 ++-
 src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp | 29 +++++--
 src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp |  1 +
 src/hotspot/cpu/x86/stubDeclarations_x86.hpp  | 22 +++--
 src/hotspot/cpu/x86/stubGenerator_x86_64.cpp  | 32 +++++--
 src/hotspot/cpu/x86/stubGenerator_x86_64.hpp  |  2 +-
 src/hotspot/cpu/x86/stubRoutines_x86.cpp      |  6 +-
 src/hotspot/cpu/x86/stubRoutines_x86.hpp      | 16 +++-
 .../cpu/zero/stubDeclarations_zero.hpp        | 15 ++--
 .../share/runtime/stubDeclarations.hpp        | 85 +++++++++++++------
 src/hotspot/share/runtime/stubInfo.cpp        | 16 +++-
 src/hotspot/share/runtime/stubInfo.hpp        | 15 +++-
 28 files changed, 355 insertions(+), 129 deletions(-)

diff --git a/src/hotspot/cpu/aarch64/aarch64_vector.ad b/src/hotspot/cpu/aarch64/aarch64_vector.ad
index 19f03d97a72..30b0c9c799b 100644
--- a/src/hotspot/cpu/aarch64/aarch64_vector.ad
+++ b/src/hotspot/cpu/aarch64/aarch64_vector.ad
@@ -597,13 +597,9 @@ instruct vloadcon(vReg dst, immI0 src) %{
     BasicType bt = Matcher::vector_element_basic_type(this);
     if (UseSVE == 0) {
       uint length_in_bytes = Matcher::vector_length_in_bytes(this);
+      int entry_idx = __ vector_iota_entry_index(bt);
       assert(length_in_bytes <= 16, "must be");
-      // The iota indices are ordered by type B/S/I/L/F/D, and the offset between two types is 16.
-      int offset = exact_log2(type2aelembytes(bt)) << 4;
-      if (is_floating_point_type(bt)) {
-        offset += 32;
-      }
-      __ lea(rscratch1, ExternalAddress(StubRoutines::aarch64::vector_iota_indices() + offset));
+      __ lea(rscratch1, ExternalAddress(StubRoutines::aarch64::vector_iota_indices(entry_idx)));
       if (length_in_bytes == 16) {
         __ ldrq($dst$$FloatRegister, rscratch1);
       } else {
diff --git a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp
index 7aab7d389e1..bba37a7a390 100644
--- a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp
@@ -2414,17 +2414,17 @@ void C2_MacroAssembler::neon_rearrange_hsd(FloatRegister dst, FloatRegister src,
       break;
     case T_LONG:
     case T_DOUBLE:
-      // Load the iota indices for Long type. The indices are ordered by
-      // type B/S/I/L/F/D, and the offset between two types is 16; Hence
-      // the offset for L is 48.
-      lea(rscratch1,
-          ExternalAddress(StubRoutines::aarch64::vector_iota_indices() + 48));
-      ldrq(tmp, rscratch1);
-      // Check whether the input "shuffle" is the same with iota indices.
-      // Return "src" if true, otherwise swap the two elements of "src".
-      cm(EQ, dst, size2, shuffle, tmp);
-      ext(tmp, size1, src, src, 8);
-      bsl(dst, size1, src, tmp);
+      {
+        int idx = vector_iota_entry_index(T_LONG);
+        lea(rscratch1,
+            ExternalAddress(StubRoutines::aarch64::vector_iota_indices(idx)));
+        ldrq(tmp, rscratch1);
+        // Check whether the input "shuffle" is the same with iota indices.
+        // Return "src" if true, otherwise swap the two elements of "src".
+        cm(EQ, dst, size2, shuffle, tmp);
+        ext(tmp, size1, src, src, 8);
+        bsl(dst, size1, src, tmp);
+      }
       break;
     default:
       assert(false, "unsupported element type");
@@ -2896,3 +2896,24 @@ void C2_MacroAssembler::sve_cpy(FloatRegister dst, SIMD_RegVariant T,
   }
   Assembler::sve_cpy(dst, T, pg, imm8, isMerge);
 }
+
+int C2_MacroAssembler::vector_iota_entry_index(BasicType bt) {
+  // The vector iota entries array is ordered by type B/S/I/L/F/D, and
+  // the offset between two types is 16.
+  switch(bt) {
+  case T_BYTE:
+    return 0;
+  case T_SHORT:
+    return 1;
+  case T_INT:
+    return 2;
+  case T_LONG:
+    return 3;
+  case T_FLOAT:
+    return 4;
+  case T_DOUBLE:
+    return 5;
+  default:
+    ShouldNotReachHere();
+  }
+}
diff --git a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp
index 5c05832afbe..5964bb60d4f 100644
--- a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp
+++ b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp
@@ -249,4 +249,5 @@
 
   void sve_cpy(FloatRegister dst, SIMD_RegVariant T, PRegister pg, int imm8,
                bool isMerge);
+  int vector_iota_entry_index(BasicType bt);
 #endif // CPU_AARCH64_C2_MACROASSEMBLER_AARCH64_HPP
diff --git a/src/hotspot/cpu/aarch64/stubDeclarations_aarch64.hpp b/src/hotspot/cpu/aarch64/stubDeclarations_aarch64.hpp
index 9dac6a39b82..d1f59e479db 100644
--- a/src/hotspot/cpu/aarch64/stubDeclarations_aarch64.hpp
+++ b/src/hotspot/cpu/aarch64/stubDeclarations_aarch64.hpp
@@ -29,32 +29,39 @@
 #define STUBGEN_PREUNIVERSE_BLOBS_ARCH_DO(do_stub,                      \
                                           do_arch_blob,                 \
                                           do_arch_entry,                \
-                                          do_arch_entry_init)           \
+                                          do_arch_entry_init,           \
+                                          do_arch_entry_array)          \
   do_arch_blob(preuniverse, 0)                                          \
 
 
 #define STUBGEN_INITIAL_BLOBS_ARCH_DO(do_stub,                          \
                                       do_arch_blob,                     \
                                       do_arch_entry,                    \
-                                      do_arch_entry_init)               \
+                                      do_arch_entry_init,               \
+                                      do_arch_entry_array)              \
   do_arch_blob(initial, 10000)                                          \
 
 
 #define STUBGEN_CONTINUATION_BLOBS_ARCH_DO(do_stub,                     \
                                            do_arch_blob,                \
                                            do_arch_entry,               \
-                                           do_arch_entry_init)          \
+                                           do_arch_entry_init,          \
+                                           do_arch_entry_array)         \
   do_arch_blob(continuation, 2000)                                      \
 
+// count needed for declaration of vector_iota_indices stub
+#define VECTOR_IOTA_COUNT 6
 
 #define STUBGEN_COMPILER_BLOBS_ARCH_DO(do_stub,                         \
                                        do_arch_blob,                    \
                                        do_arch_entry,                   \
-                                       do_arch_entry_init)              \
+                                       do_arch_entry_init,              \
+                                       do_arch_entry_array)             \
   do_arch_blob(compiler, 70000)                                         \
   do_stub(compiler, vector_iota_indices)                                \
-  do_arch_entry(aarch64, compiler, vector_iota_indices,                 \
-                vector_iota_indices, vector_iota_indices)               \
+  do_arch_entry_array(aarch64, compiler, vector_iota_indices,           \
+                      vector_iota_indices, vector_iota_indices,         \
+                      VECTOR_IOTA_COUNT)                                \
   do_stub(compiler, large_array_equals)                                 \
   do_arch_entry(aarch64, compiler, large_array_equals,                  \
                 large_array_equals, large_array_equals)                 \
@@ -115,7 +122,8 @@
 #define STUBGEN_FINAL_BLOBS_ARCH_DO(do_stub,                            \
                                     do_arch_blob,                       \
                                     do_arch_entry,                      \
-                                    do_arch_entry_init)                 \
+                                    do_arch_entry_init,                 \
+                                    do_arch_entry_array)                \
   do_arch_blob(final, 20000 ZGC_ONLY(+85000))                           \
   do_stub(final, copy_byte_f)                                           \
   do_arch_entry(aarch64, final, copy_byte_f, copy_byte_f,               \
diff --git a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp
index 32fd8afb268..5d9b2f1d826 100644
--- a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp
@@ -819,12 +819,19 @@ class StubGenerator: public StubCodeGenerator {
   }
 
   // Generate indices for iota vector.
-  address generate_iota_indices(StubId stub_id) {
+  void generate_iota_indices(StubId stub_id) {
+    GrowableArray
entries; int entry_count = StubInfo::entry_count(stub_id); - assert(entry_count == 1, "sanity check"); - address start = load_archive_data(stub_id); + assert(entry_count == VECTOR_IOTA_COUNT, "sanity check"); + address start = load_archive_data(stub_id, &entries); if (start != nullptr) { - return start; + assert(entries.length() == entry_count - 1, + "unexpected entries count %d", entries.length()); + StubRoutines::aarch64::_vector_iota_indices[0] = start; + for (int i = 1; i < VECTOR_IOTA_COUNT; i++) { + StubRoutines::aarch64::_vector_iota_indices[i] = entries.at(i - 1); + } + return; } __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); @@ -832,26 +839,37 @@ class StubGenerator: public StubCodeGenerator { // B __ emit_data64(0x0706050403020100, relocInfo::none); __ emit_data64(0x0F0E0D0C0B0A0908, relocInfo::none); + entries.append(__ pc()); // H __ emit_data64(0x0003000200010000, relocInfo::none); __ emit_data64(0x0007000600050004, relocInfo::none); + entries.append(__ pc()); // S __ emit_data64(0x0000000100000000, relocInfo::none); __ emit_data64(0x0000000300000002, relocInfo::none); + entries.append(__ pc()); // D __ emit_data64(0x0000000000000000, relocInfo::none); __ emit_data64(0x0000000000000001, relocInfo::none); + entries.append(__ pc()); // S - FP __ emit_data64(0x3F80000000000000, relocInfo::none); // 0.0f, 1.0f __ emit_data64(0x4040000040000000, relocInfo::none); // 2.0f, 3.0f + entries.append(__ pc()); // D - FP __ emit_data64(0x0000000000000000, relocInfo::none); // 0.0d __ emit_data64(0x3FF0000000000000, relocInfo::none); // 1.0d // record the stub entry and end - store_archive_data(stub_id, start, __ pc()); + store_archive_data(stub_id, start, __ pc(), &entries); - return start; + // install the entry addresses in the entry array + assert(entries.length() == entry_count - 1, + "unexpected entries count %d", entries.length()); + StubRoutines::aarch64::_vector_iota_indices[0] = start; + for (int i = 1; i < VECTOR_IOTA_COUNT; i++) { + StubRoutines::aarch64::_vector_iota_indices[i] = entries.at(i - 1); + } } // The inner part of zero_words(). This is the bulk operation, @@ -12621,7 +12639,7 @@ class StubGenerator: public StubCodeGenerator { #if COMPILER2_OR_JVMCI if (UseSVE == 0) { - StubRoutines::aarch64::_vector_iota_indices = generate_iota_indices(StubId::stubgen_vector_iota_indices_id); + generate_iota_indices(StubId::stubgen_vector_iota_indices_id); } // array equals stub for large arrays. diff --git a/src/hotspot/cpu/aarch64/stubRoutines_aarch64.cpp b/src/hotspot/cpu/aarch64/stubRoutines_aarch64.cpp index 35ec22b0897..aaf31d4f911 100644 --- a/src/hotspot/cpu/aarch64/stubRoutines_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/stubRoutines_aarch64.cpp @@ -41,8 +41,12 @@ static void empty_spin_wait() { } #define DEFINE_ARCH_ENTRY_INIT(arch, blob_name, stub_name, field_name, getter_name, init_function) \ address StubRoutines:: arch :: STUB_FIELD_NAME(field_name) = CAST_FROM_FN_PTR(address, init_function); -STUBGEN_ARCH_ENTRIES_DO(DEFINE_ARCH_ENTRY, DEFINE_ARCH_ENTRY_INIT) +#define DEFINE_ARCH_ENTRY_ARRAY(arch, blob_name, stub_name, field_name, getter_name, count) \ + address StubRoutines:: arch :: STUB_FIELD_NAME(field_name) [count]; +STUBGEN_ARCH_ENTRIES_DO(DEFINE_ARCH_ENTRY, DEFINE_ARCH_ENTRY_INIT, DEFINE_ARCH_ENTRY_ARRAY) + +#undef DEFINE_ARCH_ENTRY_ARARAY #undef DEFINE_ARCH_ENTRY_INIT #undef DEFINE_ARCH_ENTRY diff --git a/src/hotspot/cpu/aarch64/stubRoutines_aarch64.hpp b/src/hotspot/cpu/aarch64/stubRoutines_aarch64.hpp index f77192a3741..6067408ef13 100644 --- a/src/hotspot/cpu/aarch64/stubRoutines_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/stubRoutines_aarch64.hpp @@ -60,9 +60,13 @@ class aarch64 { #define DECLARE_ARCH_ENTRY_INIT(arch, blob_name, stub_name, field_name, getter_name, init_function) \ DECLARE_ARCH_ENTRY(arch, blob_name, stub_name, field_name, getter_name) -private: - STUBGEN_ARCH_ENTRIES_DO(DECLARE_ARCH_ENTRY, DECLARE_ARCH_ENTRY_INIT) +#define DECLARE_ARCH_ENTRY_ARRAY(arch, blob_name, stub_name, field_name, getter_name, count) \ + static address STUB_FIELD_NAME(field_name) [count]; +private: + STUBGEN_ARCH_ENTRIES_DO(DECLARE_ARCH_ENTRY, DECLARE_ARCH_ENTRY_INIT, DECLARE_ARCH_ENTRY_ARRAY) + +#undef DECLARE_ARCH_ENTRY_ARRAY #undef DECLARE_ARCH_ENTRY_INIT #undef DECLARE_ARCH_ENTRY @@ -78,8 +82,15 @@ private: #define DEFINE_ARCH_ENTRY_GETTER_INIT(arch, blob_name, stub_name, field_name, getter_name, init_function) \ DEFINE_ARCH_ENTRY_GETTER(arch, blob_name, stub_name, field_name, getter_name) - STUBGEN_ARCH_ENTRIES_DO(DEFINE_ARCH_ENTRY_GETTER, DEFINE_ARCH_ENTRY_GETTER_INIT) +#define DEFINE_ARCH_ENTRY_GETTER_ARRAY(arch, blob_name, stub_name, field_name, getter_name, count) \ + static address getter_name(int idx) { \ + assert(0 <= idx && idx < count, "entry array index out of range"); \ + return STUB_FIELD_NAME(field_name) [idx]; \ + } + STUBGEN_ARCH_ENTRIES_DO(DEFINE_ARCH_ENTRY_GETTER, DEFINE_ARCH_ENTRY_GETTER_INIT, DEFINE_ARCH_ENTRY_GETTER_ARRAY) + +#undef DEFINE_ARCH_ENTRY_GETTER_ARRAY #undef DEFINE_ARCH_ENTRY_GETTER_INIT #undef DEFINE_ARCH_ENTRY_GETTER diff --git a/src/hotspot/cpu/arm/stubDeclarations_arm.hpp b/src/hotspot/cpu/arm/stubDeclarations_arm.hpp index 5f768a205a5..5fb0d4e901f 100644 --- a/src/hotspot/cpu/arm/stubDeclarations_arm.hpp +++ b/src/hotspot/cpu/arm/stubDeclarations_arm.hpp @@ -29,7 +29,8 @@ #define STUBGEN_PREUNIVERSE_BLOBS_ARCH_DO(do_stub, \ do_arch_blob, \ do_arch_entry, \ - do_arch_entry_init) \ + do_arch_entry_init, \ + do_arch_entry_array) \ do_arch_blob(preuniverse, 500) \ do_stub(preuniverse, atomic_load_long) \ do_arch_entry(Arm, preuniverse, atomic_load_long, \ @@ -42,7 +43,8 @@ #define STUBGEN_INITIAL_BLOBS_ARCH_DO(do_stub, \ do_arch_blob, \ do_arch_entry, \ - do_arch_entry_init) \ + do_arch_entry_init, \ + do_arch_entry_array) \ do_arch_blob(initial, 9000) \ do_stub(initial, idiv_irem) \ do_arch_entry(Arm, initial, idiv_irem, \ @@ -51,14 +53,16 @@ #define STUBGEN_CONTINUATION_BLOBS_ARCH_DO(do_stub, \ do_arch_blob, \ do_arch_entry, \ - do_arch_entry_init) \ + do_arch_entry_init, \ + do_arch_entry_array) \ do_arch_blob(continuation, 2000) \ #define STUBGEN_COMPILER_BLOBS_ARCH_DO(do_stub, \ do_arch_blob, \ do_arch_entry, \ - do_arch_entry_init) \ + do_arch_entry_init, \ + do_arch_entry_array) \ do_arch_blob(compiler, 22000) \ do_stub(compiler, partial_subtype_check) \ do_arch_entry(Arm, compiler, partial_subtype_check, \ @@ -68,7 +72,8 @@ #define STUBGEN_FINAL_BLOBS_ARCH_DO(do_stub, \ do_arch_blob, \ do_arch_entry, \ - do_arch_entry_init) \ + do_arch_entry_init, \ + do_arch_entry_array) \ do_arch_blob(final, 22000) \ diff --git a/src/hotspot/cpu/arm/stubRoutines_arm.cpp b/src/hotspot/cpu/arm/stubRoutines_arm.cpp index 3ed747ea11a..38a9b298562 100644 --- a/src/hotspot/cpu/arm/stubRoutines_arm.cpp +++ b/src/hotspot/cpu/arm/stubRoutines_arm.cpp @@ -32,7 +32,7 @@ #define DEFINE_ARCH_ENTRY_INIT(arch, blob_name, stub_name, field_name, getter_name, init_function) \ address StubRoutines:: arch :: STUB_FIELD_NAME(field_name) = CAST_FROM_FN_PTR(address, init_function); -STUBGEN_ARCH_ENTRIES_DO(DEFINE_ARCH_ENTRY, DEFINE_ARCH_ENTRY_INIT) +STUBGEN_ARCH_ENTRIES_DO(DEFINE_ARCH_ENTRY, DEFINE_ARCH_ENTRY_INIT, DEFINE_ARCH_ENTRY_ARRAY) #undef DEFINE_ARCH_ENTRY_INIT #undef DEFINE_ARCH_ENTRY diff --git a/src/hotspot/cpu/arm/stubRoutines_arm.hpp b/src/hotspot/cpu/arm/stubRoutines_arm.hpp index 45ab10d14f9..29d96d0e653 100644 --- a/src/hotspot/cpu/arm/stubRoutines_arm.hpp +++ b/src/hotspot/cpu/arm/stubRoutines_arm.hpp @@ -55,9 +55,13 @@ class Arm { #define DECLARE_ARCH_ENTRY_INIT(arch, blob_name, stub_name, field_name, getter_name, init_function) \ DECLARE_ARCH_ENTRY(arch, blob_name, stub_name, field_name, getter_name) -private: - STUBGEN_ARCH_ENTRIES_DO(DECLARE_ARCH_ENTRY, DECLARE_ARCH_ENTRY_INIT) +#define DECLARE_ARCH_ENTRY_ARRAY(arch, blob_name, stub_name, field_name, getter_name, count) \ + static address STUB_FIELD_NAME(field_name) [count] ; +private: + STUBGEN_ARCH_ENTRIES_DO(DECLARE_ARCH_ENTRY, DECLARE_ARCH_ENTRY_INIT, DECLARE_ARCH_ENTRY_ARRAY) + +#undef DECLARE_ARCH_ENTRY_ARRAY #undef DECLARE_ARCH_ENTRY_INIT #undef DECLARE_ARCH_ENTRY @@ -71,8 +75,12 @@ public: #define DEFINE_ARCH_ENTRY_GETTER_INIT(arch, blob_name, stub_name, field_name, getter_name, init_function) \ DEFINE_ARCH_ENTRY_GETTER(arch, blob_name, stub_name, field_name, getter_name) - STUBGEN_ARCH_ENTRIES_DO(DEFINE_ARCH_ENTRY_GETTER, DEFINE_ARCH_ENTRY_GETTER_INIT) +#define DEFINE_ARCH_ENTRY_GETTER_ARRAY(arch, blob_name, stub_name, field_name, getter_name, count) \ + static address getter_name(int idx) { return STUB_FIELD_NAME(field_name) [idx] ; } + STUBGEN_ARCH_ENTRIES_DO(DEFINE_ARCH_ENTRY_GETTER, DEFINE_ARCH_ENTRY_GETTER_INIT, DEFINE_ARCH_ENTRY_GETTER_ARRAY) + +#undef DEFINE_ARCH_ENTRY_GETTER_ARRAY #undef DEFINE_ARCH_ENTRY_GETTER_INIT #undef DEFINE_ARCH_ENTRY_GETTER diff --git a/src/hotspot/cpu/ppc/stubDeclarations_ppc.hpp b/src/hotspot/cpu/ppc/stubDeclarations_ppc.hpp index be51afe42a4..41b8b71486d 100644 --- a/src/hotspot/cpu/ppc/stubDeclarations_ppc.hpp +++ b/src/hotspot/cpu/ppc/stubDeclarations_ppc.hpp @@ -29,35 +29,40 @@ #define STUBGEN_PREUNIVERSE_BLOBS_ARCH_DO(do_stub, \ do_arch_blob, \ do_arch_entry, \ - do_arch_entry_init) \ + do_arch_entry_init, \ + do_arch_entry_array) \ do_arch_blob(preuniverse, 0) \ #define STUBGEN_INITIAL_BLOBS_ARCH_DO(do_stub, \ do_arch_blob, \ do_arch_entry, \ - do_arch_entry_init) \ + do_arch_entry_init, \ + do_arch_entry_array) \ do_arch_blob(initial, 20000) \ #define STUBGEN_CONTINUATION_BLOBS_ARCH_DO(do_stub, \ do_arch_blob, \ do_arch_entry, \ - do_arch_entry_init) \ + do_arch_entry_init, \ + do_arch_entry_array) \ do_arch_blob(continuation, 2000) \ #define STUBGEN_COMPILER_BLOBS_ARCH_DO(do_stub, \ do_arch_blob, \ do_arch_entry, \ - do_arch_entry_init) \ + do_arch_entry_init, \ + do_arch_entry_array) \ do_arch_blob(compiler, 24000) \ #define STUBGEN_FINAL_BLOBS_ARCH_DO(do_stub, \ do_arch_blob, \ do_arch_entry, \ - do_arch_entry_init) \ + do_arch_entry_init, \ + do_arch_entry_array) \ do_arch_blob(final, 24000) \ diff --git a/src/hotspot/cpu/riscv/stubDeclarations_riscv.hpp b/src/hotspot/cpu/riscv/stubDeclarations_riscv.hpp index f977d759d20..890e354fd27 100644 --- a/src/hotspot/cpu/riscv/stubDeclarations_riscv.hpp +++ b/src/hotspot/cpu/riscv/stubDeclarations_riscv.hpp @@ -29,28 +29,32 @@ #define STUBGEN_PREUNIVERSE_BLOBS_ARCH_DO(do_stub, \ do_arch_blob, \ do_arch_entry, \ - do_arch_entry_init) \ + do_arch_entry_init, \ + do_arch_entry_array) \ do_arch_blob(preuniverse, 0) \ #define STUBGEN_INITIAL_BLOBS_ARCH_DO(do_stub, \ do_arch_blob, \ do_arch_entry, \ - do_arch_entry_init) \ + do_arch_entry_init, \ + do_arch_entry_array) \ do_arch_blob(initial, 10000) \ #define STUBGEN_CONTINUATION_BLOBS_ARCH_DO(do_stub, \ do_arch_blob, \ do_arch_entry, \ - do_arch_entry_init) \ + do_arch_entry_init, \ + do_arch_entry_array) \ do_arch_blob(continuation, 2000) \ #define STUBGEN_COMPILER_BLOBS_ARCH_DO(do_stub, \ do_arch_blob, \ do_arch_entry, \ - do_arch_entry_init) \ + do_arch_entry_init, \ + do_arch_entry_array) \ do_arch_blob(compiler, 45000) \ do_stub(compiler, compare_long_string_LL) \ do_arch_entry(riscv, compiler, compare_long_string_LL, \ @@ -81,7 +85,8 @@ #define STUBGEN_FINAL_BLOBS_ARCH_DO(do_stub, \ do_arch_blob, \ do_arch_entry, \ - do_arch_entry_init) \ + do_arch_entry_init, \ + do_arch_entry_array) \ do_arch_blob(final, 20000 ZGC_ONLY(+10000)) \ do_stub(final, copy_byte_f) \ do_arch_entry(riscv, final, copy_byte_f, copy_byte_f, \ diff --git a/src/hotspot/cpu/riscv/stubRoutines_riscv.cpp b/src/hotspot/cpu/riscv/stubRoutines_riscv.cpp index 51e31aa3672..b7f69eff9fa 100644 --- a/src/hotspot/cpu/riscv/stubRoutines_riscv.cpp +++ b/src/hotspot/cpu/riscv/stubRoutines_riscv.cpp @@ -42,8 +42,12 @@ #define DEFINE_ARCH_ENTRY_INIT(arch, blob_name, stub_name, field_name, getter_name, init_function) \ address StubRoutines:: arch :: STUB_FIELD_NAME(field_name) = CAST_FROM_FN_PTR(address, init_function); -STUBGEN_ARCH_ENTRIES_DO(DEFINE_ARCH_ENTRY, DEFINE_ARCH_ENTRY_INIT) +#define DEFINE_ARCH_ENTRY_ARRAY(arch, blob_name, stub_name, field_name, getter_name, count) \ + address StubRoutines:: arch :: STUB_FIELD_NAME(field_name) [count] ; +STUBGEN_ARCH_ENTRIES_DO(DEFINE_ARCH_ENTRY, DEFINE_ARCH_ENTRY_INIT, DEFINE_ARCH_ENTRY_ARRAY) + +#undef DEFINE_ARCH_ENTRY_ARRAY #undef DEFINE_ARCH_ENTRY_INIT #undef DEFINE_ARCH_ENTRY diff --git a/src/hotspot/cpu/riscv/stubRoutines_riscv.hpp b/src/hotspot/cpu/riscv/stubRoutines_riscv.hpp index 2c4e7210413..ec67a338052 100644 --- a/src/hotspot/cpu/riscv/stubRoutines_riscv.hpp +++ b/src/hotspot/cpu/riscv/stubRoutines_riscv.hpp @@ -61,9 +61,13 @@ class riscv { #define DECLARE_ARCH_ENTRY_INIT(arch, blob_name, stub_name, field_name, getter_name, init_function) \ DECLARE_ARCH_ENTRY(arch, blob_name, stub_name, field_name, getter_name) -private: - STUBGEN_ARCH_ENTRIES_DO(DECLARE_ARCH_ENTRY, DECLARE_ARCH_ENTRY_INIT) +#define DECLARE_ARCH_ENTRY_ARRAY(arch, blob_name, stub_name, field_name, getter_name, count) \ + static address STUB_FIELD_NAME(field_name) [count] ; +private: + STUBGEN_ARCH_ENTRIES_DO(DECLARE_ARCH_ENTRY, DECLARE_ARCH_ENTRY_INIT, DECLARE_ARCH_ENTRY_ARRAY) + +#undef DECLARE_ARCH_ENTRY_ARRAY #undef DECLARE_ARCH_ENTRY_INIT #undef DECLARE_ARCH_ENTRY @@ -79,8 +83,12 @@ private: #define DEFINE_ARCH_ENTRY_GETTER_INIT(arch, blob_name, stub_name, field_name, getter_name, init_function) \ DEFINE_ARCH_ENTRY_GETTER(arch, blob_name, stub_name, field_name, getter_name) - STUBGEN_ARCH_ENTRIES_DO(DEFINE_ARCH_ENTRY_GETTER, DEFINE_ARCH_ENTRY_GETTER_INIT) +#define DEFINE_ARCH_ENTRY_GETTER_ARRAY(arch, blob_name, stub_name, field_name, getter_name, count) \ + static address getter_name(int idx) { return STUB_FIELD_NAME(field_name) [idx] ; } + STUBGEN_ARCH_ENTRIES_DO(DEFINE_ARCH_ENTRY_GETTER, DEFINE_ARCH_ENTRY_GETTER_INIT, DEFINE_ARCH_ENTRY_GETTER_ARRAY) + +#undef DEFINE_ARCH_ENTRY_GETTER_ARRAY #undef DEFINE_ARCH_ENTRY_GETTER_INIT #undef DEFINE_ARCH_ENTRY_GETTER diff --git a/src/hotspot/cpu/s390/stubDeclarations_s390.hpp b/src/hotspot/cpu/s390/stubDeclarations_s390.hpp index c3ad3cefeb9..d0e26beedab 100644 --- a/src/hotspot/cpu/s390/stubDeclarations_s390.hpp +++ b/src/hotspot/cpu/s390/stubDeclarations_s390.hpp @@ -29,28 +29,32 @@ #define STUBGEN_PREUNIVERSE_BLOBS_ARCH_DO(do_stub, \ do_arch_blob, \ do_arch_entry, \ - do_arch_entry_init) \ + do_arch_entry_init, \ + do_arch_entry_array) \ do_arch_blob(preuniverse, 0) \ #define STUBGEN_INITIAL_BLOBS_ARCH_DO(do_stub, \ do_arch_blob, \ do_arch_entry, \ - do_arch_entry_init) \ + do_arch_entry_init, \ + do_arch_entry_array) \ do_arch_blob(initial, 20000) \ #define STUBGEN_CONTINUATION_BLOBS_ARCH_DO(do_stub, \ do_arch_blob, \ do_arch_entry, \ - do_arch_entry_init) \ + do_arch_entry_init, \ + do_arch_entry_array) \ do_arch_blob(continuation, 2000) \ #define STUBGEN_COMPILER_BLOBS_ARCH_DO(do_stub, \ do_arch_blob, \ do_arch_entry, \ - do_arch_entry_init) \ + do_arch_entry_init, \ + do_arch_entry_array) \ do_arch_blob(compiler, 20000 ) \ do_stub(compiler, partial_subtype_check) \ do_arch_entry(zarch, compiler, partial_subtype_check, \ @@ -60,7 +64,8 @@ #define STUBGEN_FINAL_BLOBS_ARCH_DO(do_stub, \ do_arch_blob, \ do_arch_entry, \ - do_arch_entry_init) \ + do_arch_entry_init, \ + do_arch_entry_array) \ do_arch_blob(final, 20000) \ diff --git a/src/hotspot/cpu/s390/stubRoutines_s390.cpp b/src/hotspot/cpu/s390/stubRoutines_s390.cpp index 3db4995338d..eda0ebfdecc 100644 --- a/src/hotspot/cpu/s390/stubRoutines_s390.cpp +++ b/src/hotspot/cpu/s390/stubRoutines_s390.cpp @@ -40,8 +40,12 @@ #define DEFINE_ARCH_ENTRY_INIT(arch, blob_name, stub_name, field_name, getter_name, init_function) \ address StubRoutines:: arch :: STUB_FIELD_NAME(field_name) = CAST_FROM_FN_PTR(address, init_function); -STUBGEN_ARCH_ENTRIES_DO(DEFINE_ARCH_ENTRY, DEFINE_ARCH_ENTRY_INIT) +#define DEFINE_ARCH_ENTRY_ARRAY(arch, blob_name, stub_name, field_name, getter_name, count) \ + address StubRoutines:: arch :: STUB_FIELD_NAME(field_name) [idx] ; +STUBGEN_ARCH_ENTRIES_DO(DEFINE_ARCH_ENTRY, DEFINE_ARCH_ENTRY_INIT, DEFINE_ARCH_ENTRY_ARRAY) + +#undef DEFINE_ARCH_ENTRY_ARRAY #undef DEFINE_ARCH_ENTRY_INIT #undef DEFINE_ARCH_ENTRY diff --git a/src/hotspot/cpu/s390/stubRoutines_s390.hpp b/src/hotspot/cpu/s390/stubRoutines_s390.hpp index 0a07efae46c..e575115b731 100644 --- a/src/hotspot/cpu/s390/stubRoutines_s390.hpp +++ b/src/hotspot/cpu/s390/stubRoutines_s390.hpp @@ -81,9 +81,13 @@ class zarch { #define DECLARE_ARCH_ENTRY_INIT(arch, blob_name, stub_name, field_name, getter_name, init_function) \ DECLARE_ARCH_ENTRY(arch, blob_name, stub_name, field_name, getter_name) -private: - STUBGEN_ARCH_ENTRIES_DO(DECLARE_ARCH_ENTRY, DECLARE_ARCH_ENTRY_INIT) +#define DECLARE_ARCH_ENTRY_ARRAY(arch, blob_name, stub_name, field_name, getter_name, count) \ + static address STUB_FIELD_NAME(field_name) [count] ; +private: + STUBGEN_ARCH_ENTRIES_DO(DECLARE_ARCH_ENTRY, DECLARE_ARCH_ENTRY_INIT, DECLARE_ARCH_ENTRY_ARRAY) + +#undef DECLARE_ARCH_ENTRY_ARRAY #undef DECLARE_ARCH_ENTRY_INIT #undef DECLARE_ARCH_ENTRY @@ -108,8 +112,12 @@ private: #define DEFINE_ARCH_ENTRY_GETTER_INIT(arch, blob_name, stub_name, field_name, getter_name, init_function) \ DEFINE_ARCH_ENTRY_GETTER(arch, blob_name, stub_name, field_name, getter_name) - STUBGEN_ARCH_ENTRIES_DO(DEFINE_ARCH_ENTRY_GETTER, DEFINE_ARCH_ENTRY_GETTER_INIT) +#define DEFINE_ARCH_ENTRY_GETTER_ARRAY(arch, blob_name, stub_name, field_name, getter_name, count) \ + static address getter_name(int idx) { return STUB_FIELD_NAME(field_name) [idx] ; } + STUBGEN_ARCH_ENTRIES_DO(DEFINE_ARCH_ENTRY_GETTER, DEFINE_ARCH_ENTRY_GETTER_INIT, DEFINE_ARCH_ENTRY_GETTER_ARRAY) + +#undef DEFINE_ARCH_ENTRY_GETTER_ARRAY #undef DEFINE_ARCH_ENTRY_GETTER_INIT #undef DEFINE_ARCH_ENTRY_GETTER diff --git a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp index f36c816dd5e..b4d8aa10de2 100644 --- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp @@ -1706,12 +1706,8 @@ void C2_MacroAssembler::load_constant_vector(BasicType bt, XMMRegister dst, Inte } void C2_MacroAssembler::load_iota_indices(XMMRegister dst, int vlen_in_bytes, BasicType bt) { - // The iota indices are ordered by type B/S/I/L/F/D, and the offset between two types is 64. - int offset = exact_log2(type2aelembytes(bt)) << 6; - if (is_floating_point_type(bt)) { - offset += 128; - } - ExternalAddress addr(StubRoutines::x86::vector_iota_indices() + offset); + int entry_idx = vector_iota_entry_index(bt); + ExternalAddress addr(StubRoutines::x86::vector_iota_indices(entry_idx)); load_vector(T_BYTE, dst, addr, vlen_in_bytes); } @@ -7164,3 +7160,24 @@ void C2_MacroAssembler::vminmax_fp16_avx10_2(int opcode, XMMRegister dst, XMMReg evminmaxph(dst, ktmp, src1, src2, true, AVX10_2_MINMAX_MIN_COMPARE_SIGN, vlen_enc); } } + +int C2_MacroAssembler::vector_iota_entry_index(BasicType bt) { + // The vector iota entries array is ordered by type B/S/I/L/F/D, and + // the offset between two types is 16. + switch(bt) { + case T_BYTE: + return 0; + case T_SHORT: + return 1; + case T_INT: + return 2; + case T_LONG: + return 3; + case T_FLOAT: + return 4; + case T_DOUBLE: + return 5; + default: + ShouldNotReachHere(); + } +} diff --git a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp index 4e77f8a5f6f..9b229ad7221 100644 --- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp @@ -596,4 +596,5 @@ public: void reconstruct_frame_pointer(Register rtmp); + int vector_iota_entry_index(BasicType bt); #endif // CPU_X86_C2_MACROASSEMBLER_X86_HPP diff --git a/src/hotspot/cpu/x86/stubDeclarations_x86.hpp b/src/hotspot/cpu/x86/stubDeclarations_x86.hpp index 07a1ab622ed..24886deb3c5 100644 --- a/src/hotspot/cpu/x86/stubDeclarations_x86.hpp +++ b/src/hotspot/cpu/x86/stubDeclarations_x86.hpp @@ -29,14 +29,16 @@ #define STUBGEN_PREUNIVERSE_BLOBS_ARCH_DO(do_stub, \ do_arch_blob, \ do_arch_entry, \ - do_arch_entry_init) \ + do_arch_entry_init, \ + do_arch_entry_array) \ do_arch_blob(preuniverse, 500) \ #define STUBGEN_INITIAL_BLOBS_ARCH_DO(do_stub, \ do_arch_blob, \ do_arch_entry, \ - do_arch_entry_init) \ + do_arch_entry_init, \ + do_arch_entry_array) \ do_arch_blob(initial, PRODUCT_ONLY(20000) NOT_PRODUCT(21000) WINDOWS_ONLY(+1000)) \ do_stub(initial, verify_mxcsr) \ do_arch_entry(x86, initial, verify_mxcsr, verify_mxcsr_entry, \ @@ -65,14 +67,18 @@ #define STUBGEN_CONTINUATION_BLOBS_ARCH_DO(do_stub, \ do_arch_blob, \ do_arch_entry, \ - do_arch_entry_init) \ + do_arch_entry_init, \ + do_arch_entry_array) \ do_arch_blob(continuation, 3000) \ +// count needed for declaration of vector_iota_indices stub +#define VECTOR_IOTA_COUNT 6 #define STUBGEN_COMPILER_BLOBS_ARCH_DO(do_stub, \ do_arch_blob, \ do_arch_entry, \ - do_arch_entry_init) \ + do_arch_entry_init, \ + do_arch_entry_array) \ do_arch_blob(compiler, 120000 WINDOWS_ONLY(+2000)) \ do_stub(compiler, vector_float_sign_mask) \ do_arch_entry(x86, compiler, vector_float_sign_mask, \ @@ -126,8 +132,9 @@ do_arch_entry(x86, compiler, vector_long_sign_mask, \ vector_long_sign_mask, vector_long_sign_mask) \ do_stub(compiler, vector_iota_indices) \ - do_arch_entry(x86, compiler, vector_iota_indices, \ - vector_iota_indices, vector_iota_indices) \ + do_arch_entry_array(x86, compiler, vector_iota_indices, \ + vector_iota_indices, vector_iota_indices, \ + VECTOR_IOTA_COUNT) \ do_stub(compiler, vector_count_leading_zeros_lut) \ do_arch_entry(x86, compiler, vector_count_leading_zeros_lut, \ vector_count_leading_zeros_lut, \ @@ -250,7 +257,8 @@ #define STUBGEN_FINAL_BLOBS_ARCH_DO(do_stub, \ do_arch_blob, \ do_arch_entry, \ - do_arch_entry_init) \ + do_arch_entry_init, \ + do_arch_entry_array) \ do_arch_blob(final, 33000 \ WINDOWS_ONLY(+22000) ZGC_ONLY(+20000)) \ diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp index 40be816fbf0..993d1964034 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp @@ -893,13 +893,20 @@ address StubGenerator::generate_popcount_avx_lut() { return start; } -address StubGenerator::generate_iota_indices() { +void StubGenerator::generate_iota_indices() { StubId stub_id = StubId::stubgen_vector_iota_indices_id; + GrowableArray
entries; int entry_count = StubInfo::entry_count(stub_id); - assert(entry_count == 1, "sanity check"); - address start = load_archive_data(stub_id); + assert(entry_count == VECTOR_IOTA_COUNT, "sanity check"); + address start = load_archive_data(stub_id, &entries); if (start != nullptr) { - return start; + assert(entries.length() == VECTOR_IOTA_COUNT - 1, + "unexpected extra entry count %d", entries.length()); + StubRoutines::x86::_vector_iota_indices[0] = start; + for (int i = 1; i < VECTOR_IOTA_COUNT; i++) { + StubRoutines::x86::_vector_iota_indices[i] = entries.at(i - 1); + } + return; } __ align(CodeEntryAlignment); StubCodeMark mark(this, stub_id); @@ -913,6 +920,7 @@ address StubGenerator::generate_iota_indices() { __ emit_data64(0x2F2E2D2C2B2A2928, relocInfo::none); __ emit_data64(0x3736353433323130, relocInfo::none); __ emit_data64(0x3F3E3D3C3B3A3938, relocInfo::none); + entries.append(__ pc()); // W __ emit_data64(0x0003000200010000, relocInfo::none); __ emit_data64(0x0007000600050004, relocInfo::none); @@ -922,6 +930,7 @@ address StubGenerator::generate_iota_indices() { __ emit_data64(0x0017001600150014, relocInfo::none); __ emit_data64(0x001B001A00190018, relocInfo::none); __ emit_data64(0x001F001E001D001C, relocInfo::none); + entries.append(__ pc()); // D __ emit_data64(0x0000000100000000, relocInfo::none); __ emit_data64(0x0000000300000002, relocInfo::none); @@ -931,6 +940,7 @@ address StubGenerator::generate_iota_indices() { __ emit_data64(0x0000000B0000000A, relocInfo::none); __ emit_data64(0x0000000D0000000C, relocInfo::none); __ emit_data64(0x0000000F0000000E, relocInfo::none); + entries.append(__ pc()); // Q __ emit_data64(0x0000000000000000, relocInfo::none); __ emit_data64(0x0000000000000001, relocInfo::none); @@ -940,6 +950,7 @@ address StubGenerator::generate_iota_indices() { __ emit_data64(0x0000000000000005, relocInfo::none); __ emit_data64(0x0000000000000006, relocInfo::none); __ emit_data64(0x0000000000000007, relocInfo::none); + entries.append(__ pc()); // D - FP __ emit_data64(0x3F80000000000000, relocInfo::none); // 0.0f, 1.0f __ emit_data64(0x4040000040000000, relocInfo::none); // 2.0f, 3.0f @@ -949,6 +960,7 @@ address StubGenerator::generate_iota_indices() { __ emit_data64(0x4130000041200000, relocInfo::none); // 10.0f, 11.0f __ emit_data64(0x4150000041400000, relocInfo::none); // 12.0f, 13.0f __ emit_data64(0x4170000041600000, relocInfo::none); // 14.0f, 15.0f + entries.append(__ pc()); // Q - FP __ emit_data64(0x0000000000000000, relocInfo::none); // 0.0d __ emit_data64(0x3FF0000000000000, relocInfo::none); // 1.0d @@ -960,9 +972,15 @@ address StubGenerator::generate_iota_indices() { __ emit_data64(0x401c000000000000, relocInfo::none); // 7.0d // record the stub entry and end - store_archive_data(stub_id, start, __ pc()); + store_archive_data(stub_id, start, __ pc(), &entries); - return start; + // install the entry addresses in the entry array + assert(entries.length() == entry_count - 1, + "unexpected entries count %d", entries.length()); + StubRoutines::x86::_vector_iota_indices[0] = start; + for (int i = 1; i < VECTOR_IOTA_COUNT; i++) { + StubRoutines::x86::_vector_iota_indices[i] = entries.at(i - 1); + } } address StubGenerator::generate_vector_reverse_bit_lut() { @@ -4837,7 +4855,7 @@ void StubGenerator::generate_compiler_stubs() { StubRoutines::x86::_vector_short_shuffle_mask = generate_vector_mask(StubId::stubgen_vector_short_shuffle_mask_id, 0x0100010001000100); StubRoutines::x86::_vector_long_shuffle_mask = generate_vector_mask(StubId::stubgen_vector_long_shuffle_mask_id, 0x0000000100000000); StubRoutines::x86::_vector_long_sign_mask = generate_vector_mask(StubId::stubgen_vector_long_sign_mask_id, 0x8000000000000000); - StubRoutines::x86::_vector_iota_indices = generate_iota_indices(); + generate_iota_indices(); StubRoutines::x86::_vector_count_leading_zeros_lut = generate_count_leading_zeros_lut(); StubRoutines::x86::_vector_reverse_bit_lut = generate_vector_reverse_bit_lut(); StubRoutines::x86::_vector_reverse_byte_perm_mask_long = generate_vector_reverse_byte_perm_mask_long(); diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp b/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp index 05e8384d636..d3823cb559f 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp @@ -84,7 +84,7 @@ class StubGenerator: public StubCodeGenerator { address generate_count_leading_zeros_lut(); address generate_popcount_avx_lut(); - address generate_iota_indices(); + void generate_iota_indices(); address generate_vector_reverse_bit_lut(); address generate_vector_reverse_byte_perm_mask_long(); diff --git a/src/hotspot/cpu/x86/stubRoutines_x86.cpp b/src/hotspot/cpu/x86/stubRoutines_x86.cpp index 8696180c512..aaee01437af 100644 --- a/src/hotspot/cpu/x86/stubRoutines_x86.cpp +++ b/src/hotspot/cpu/x86/stubRoutines_x86.cpp @@ -44,8 +44,12 @@ #define DEFINE_ARCH_ENTRY_INIT(arch, blob_name, stub_name, field_name, getter_name, init_function) \ address StubRoutines:: arch :: STUB_FIELD_NAME(field_name) = CAST_FROM_FN_PTR(address, init_function); -STUBGEN_ARCH_ENTRIES_DO(DEFINE_ARCH_ENTRY, DEFINE_ARCH_ENTRY_INIT) +#define DEFINE_ARCH_ENTRY_ARRAY(arch, blob_name, stub_name, field_name, getter_name, count) \ + address StubRoutines:: arch :: STUB_FIELD_NAME(field_name) [count]; +STUBGEN_ARCH_ENTRIES_DO(DEFINE_ARCH_ENTRY, DEFINE_ARCH_ENTRY_INIT, DEFINE_ARCH_ENTRY_ARRAY) + +#undef DEFINE_ARCH_ENTRY_ARRAY #undef DEFINE_ARCH_ENTRY_INIT #undef DEFINE_ARCH_ENTRY diff --git a/src/hotspot/cpu/x86/stubRoutines_x86.hpp b/src/hotspot/cpu/x86/stubRoutines_x86.hpp index 3c6d75c1d4e..7283798888b 100644 --- a/src/hotspot/cpu/x86/stubRoutines_x86.hpp +++ b/src/hotspot/cpu/x86/stubRoutines_x86.hpp @@ -55,9 +55,13 @@ class x86 { #define DECLARE_ARCH_ENTRY_INIT(arch, blob_name, stub_name, field_name, getter_name, init_function) \ DECLARE_ARCH_ENTRY(arch, blob_name, stub_name, field_name, getter_name) -private: - STUBGEN_ARCH_ENTRIES_DO(DECLARE_ARCH_ENTRY, DECLARE_ARCH_ENTRY_INIT) +#define DECLARE_ARCH_ENTRY_ARRAY(arch, blob_name, stub_name, field_name, getter_name, count) \ + static address STUB_FIELD_NAME(field_name) [count] ; +private: + STUBGEN_ARCH_ENTRIES_DO(DECLARE_ARCH_ENTRY, DECLARE_ARCH_ENTRY_INIT, DECLARE_ARCH_ENTRY_ARRAY) + +#undef DECLARE_ARCH_ENTRY_ARRAY #undef DECLARE_ARCH_ENTRY_INIT #undef DECLARE_ARCH_ENTRY @@ -70,9 +74,13 @@ private: #define DEFINE_ARCH_ENTRY_GETTER_INIT(arch, blob_name, stub_name, field_name, getter_name, init_function) \ DEFINE_ARCH_ENTRY_GETTER(arch, blob_name, stub_name, field_name, getter_name) -public: - STUBGEN_ARCH_ENTRIES_DO(DEFINE_ARCH_ENTRY_GETTER, DEFINE_ARCH_ENTRY_GETTER_INIT) +#define DEFINE_ARCH_ENTRY_GETTER_ARRAY(arch, blob_name, stub_name, field_name, getter_name, count) \ + static address getter_name(int idx) { return STUB_FIELD_NAME(field_name) [idx]; } +public: + STUBGEN_ARCH_ENTRIES_DO(DEFINE_ARCH_ENTRY_GETTER, DEFINE_ARCH_ENTRY_GETTER_INIT, DEFINE_ARCH_ENTRY_GETTER_ARRAY) + +#undef DEFINE_ARCH_ENTRY_GETTER_ARRAY #undef DEFINE_ARCH_ENTRY_GETTER_INIT #undef DEFINE_ARCH_GETTER_ENTRY diff --git a/src/hotspot/cpu/zero/stubDeclarations_zero.hpp b/src/hotspot/cpu/zero/stubDeclarations_zero.hpp index 2357bbb5169..9abe313b3a7 100644 --- a/src/hotspot/cpu/zero/stubDeclarations_zero.hpp +++ b/src/hotspot/cpu/zero/stubDeclarations_zero.hpp @@ -29,35 +29,40 @@ #define STUBGEN_PREUNIVERSE_BLOBS_ARCH_DO(do_stub, \ do_arch_blob, \ do_arch_entry, \ - do_arch_entry_init) \ + do_arch_entry_init, \ + do_arch_entry_array) \ do_arch_blob(preuniverse, 0) \ #define STUBGEN_INITIAL_BLOBS_ARCH_DO(do_stub, \ do_arch_blob, \ do_arch_entry, \ - do_arch_entry_init) \ + do_arch_entry_init, \ + do_arch_entry_array) \ do_arch_blob(initial, 0) \ #define STUBGEN_CONTINUATION_BLOBS_ARCH_DO(do_stub, \ do_arch_blob, \ do_arch_entry, \ - do_arch_entry_init) \ + do_arch_entry_init, \ + do_arch_entry_array) \ do_arch_blob(continuation, 0) \ #define STUBGEN_COMPILER_BLOBS_ARCH_DO(do_stub, \ do_arch_blob, \ do_arch_entry, \ - do_arch_entry_init) \ + do_arch_entry_init, \ + do_arch_entry_array) \ do_arch_blob(compiler, 0) \ #define STUBGEN_FINAL_BLOBS_ARCH_DO(do_stub, \ do_arch_blob, \ do_arch_entry, \ - do_arch_entry_init) \ + do_arch_entry_init, \ + do_arch_entry_array) \ do_arch_blob(final, 0) \ diff --git a/src/hotspot/share/runtime/stubDeclarations.hpp b/src/hotspot/share/runtime/stubDeclarations.hpp index d1ce378ee20..ed1b3ea2e78 100644 --- a/src/hotspot/share/runtime/stubDeclarations.hpp +++ b/src/hotspot/share/runtime/stubDeclarations.hpp @@ -539,18 +539,19 @@ // generated. // // Architecture-specific entries need to be declared using the -// do_arch_entry template +// do_arch_entry templates // // do_arch_entry(arch, blob_name, stub_name, field_name, getter_name) // // do_arch_entry_init(arch, blob_name, stub_name, field_name, // getter_name, init_function) // +// do_arch_entry_array(arch, blob_name, stub_name, field_name, +// getter_name, count) +// // The only difference between these templates and the generic ones is // that they receive an extra argument which identifies the current // architecture e.g. x86, aarch64 etc. -// -// 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 have been defined @@ -598,7 +599,8 @@ do_entry, do_entry_init, \ do_entry_array, \ do_arch_blob, \ - do_arch_entry, do_arch_entry_init) \ + do_arch_entry, do_arch_entry_init, \ + do_arch_entry_array) \ do_blob(preuniverse) \ do_stub(preuniverse, fence) \ do_entry(preuniverse, fence, fence_entry, fence_entry) \ @@ -615,7 +617,8 @@ atomic_cmpxchg_long_entry) \ /* merge in stubs and entries declared in arch header */ \ STUBGEN_PREUNIVERSE_BLOBS_ARCH_DO(do_stub, do_arch_blob, \ - do_arch_entry, do_arch_entry_init) \ + do_arch_entry, do_arch_entry_init, \ + do_arch_entry_array) \ end_blob(preuniverse) \ #define STUBGEN_INITIAL_BLOBS_DO(do_blob, end_blob, \ @@ -623,7 +626,8 @@ do_entry, do_entry_init, \ do_entry_array, \ do_arch_blob, \ - do_arch_entry, do_arch_entry_init) \ + do_arch_entry, do_arch_entry_init, \ + do_arch_entry_array) \ do_blob(initial) \ do_stub(initial, call_stub) \ do_entry(initial, call_stub, call_stub_entry, call_stub_entry) \ @@ -669,7 +673,8 @@ do_entry(initial, fmod, fmod, fmod) \ /* merge in stubs and entries declared in arch header */ \ STUBGEN_INITIAL_BLOBS_ARCH_DO(do_stub, do_arch_blob, \ - do_arch_entry, do_arch_entry_init) \ + do_arch_entry, do_arch_entry_init, \ + do_arch_entry_array) \ end_blob(initial) \ @@ -679,7 +684,8 @@ do_entry_array, \ do_arch_blob, \ do_arch_entry, \ - do_arch_entry_init) \ + do_arch_entry_init, \ + do_arch_entry_array) \ do_blob(continuation) \ do_stub(continuation, cont_thaw) \ do_entry(continuation, cont_thaw, cont_thaw, cont_thaw) \ @@ -694,7 +700,8 @@ cont_returnBarrierExc) \ /* merge in stubs and entries declared in arch header */ \ STUBGEN_CONTINUATION_BLOBS_ARCH_DO(do_stub, do_arch_blob, \ - do_arch_entry, do_arch_entry_init) \ + do_arch_entry, do_arch_entry_init, \ + do_arch_entry_array) \ end_blob(continuation) \ @@ -703,7 +710,8 @@ do_entry, do_entry_init, \ do_entry_array, \ do_arch_blob, \ - do_arch_entry, do_arch_entry_init) \ + do_arch_entry, do_arch_entry_init, \ + do_arch_entry_array) \ do_blob(compiler) \ do_stub(compiler, array_sort) \ do_entry(compiler, array_sort, array_sort, select_arraysort_function) \ @@ -848,7 +856,8 @@ bigIntegerLeftShiftWorker, bigIntegerLeftShift) \ /* merge in stubs and entries declared in arch header */ \ STUBGEN_COMPILER_BLOBS_ARCH_DO(do_stub, do_arch_blob, \ - do_arch_entry, do_arch_entry_init) \ + do_arch_entry, do_arch_entry_init, \ + do_arch_entry_array) \ end_blob(compiler) \ @@ -857,7 +866,8 @@ do_entry, do_entry_init, \ do_entry_array, \ do_arch_blob, \ - do_arch_entry, do_arch_entry_init) \ + do_arch_entry, do_arch_entry_init, \ + do_arch_entry_array) \ do_blob(final) \ do_stub(final, verify_oop) \ do_entry(final, verify_oop, verify_oop_subroutine_entry, \ @@ -1069,7 +1079,8 @@ lookup_secondary_supers_table_slow_path_stub) \ /* merge in stubs and entries declared in arch header */ \ STUBGEN_FINAL_BLOBS_ARCH_DO(do_stub, do_arch_blob, \ - do_arch_entry, do_arch_entry_init) \ + do_arch_entry, do_arch_entry_init, \ + do_arch_entry_array) \ end_blob(final) \ @@ -1082,37 +1093,43 @@ do_entry, do_entry_init, \ do_entry_array, \ do_arch_blob, \ - do_arch_entry, do_arch_entry_init) \ + do_arch_entry, do_arch_entry_init, \ + do_arch_entry_array) \ STUBGEN_PREUNIVERSE_BLOBS_DO(do_blob, end_blob, \ do_stub, \ do_entry, do_entry_init, \ do_entry_array, \ do_arch_blob, \ - do_arch_entry, do_arch_entry_init) \ + do_arch_entry, do_arch_entry_init, \ + do_arch_entry_array) \ STUBGEN_INITIAL_BLOBS_DO(do_blob, end_blob, \ do_stub, \ do_entry, do_entry_init, \ do_entry_array, \ do_arch_blob, \ - do_arch_entry, do_arch_entry_init) \ + do_arch_entry, do_arch_entry_init, \ + do_arch_entry_array) \ STUBGEN_CONTINUATION_BLOBS_DO(do_blob, end_blob, \ do_stub, \ do_entry, do_entry_init, \ do_entry_array, \ do_arch_blob, \ - do_arch_entry, do_arch_entry_init) \ + do_arch_entry, do_arch_entry_init, \ + do_arch_entry_array) \ STUBGEN_COMPILER_BLOBS_DO(do_blob, end_blob, \ do_stub, \ do_entry, do_entry_init, \ do_entry_array, \ do_arch_blob, \ - do_arch_entry, do_arch_entry_init) \ + do_arch_entry, do_arch_entry_init, \ + do_arch_entry_array) \ STUBGEN_FINAL_BLOBS_DO(do_blob, end_blob, \ do_stub, \ do_entry, do_entry_init, \ do_entry_array, \ do_arch_blob, \ - do_arch_entry, do_arch_entry_init) \ + do_arch_entry, do_arch_entry_init, \ + do_arch_entry_array) \ // Convenience macros for use by template implementations @@ -1162,6 +1179,9 @@ #define STUBGEN_COUNT5(_1, _2, _3, _4, count) \ + count +#define STUBGEN_COUNT6(_1, _2, _3, _4, _5, count) \ + + count + // Convenience templates that emit nothing // ignore do_blob(blob_name, type) declarations @@ -1200,7 +1220,8 @@ DO_ENTRY_EMPTY4, DO_ENTRY_EMPTY5, \ DO_ENTRY_EMPTY5, \ DO_ARCH_BLOB_EMPTY2, \ - DO_ARCH_ENTRY_EMPTY5, DO_ARCH_ENTRY_EMPTY6) \ + DO_ARCH_ENTRY_EMPTY5, DO_ARCH_ENTRY_EMPTY6, \ + DO_ARCH_ENTRY_EMPTY6) \ // client macro to operate only on StubGenerator stubs @@ -1210,7 +1231,8 @@ DO_ENTRY_EMPTY4, DO_ENTRY_EMPTY5, \ DO_ENTRY_EMPTY5, \ DO_ARCH_BLOB_EMPTY2, \ - DO_ARCH_ENTRY_EMPTY5, DO_ARCH_ENTRY_EMPTY6) \ + DO_ARCH_ENTRY_EMPTY5, DO_ARCH_ENTRY_EMPTY6, \ + DO_ARCH_ENTRY_EMPTY6) \ // client macros to operate only on StubGenerator blobs and stubs @@ -1220,18 +1242,21 @@ DO_ENTRY_EMPTY4, DO_ENTRY_EMPTY5, \ DO_ENTRY_EMPTY5, \ DO_ARCH_BLOB_EMPTY2, \ - DO_ARCH_ENTRY_EMPTY5,DO_ARCH_ENTRY_EMPTY6) \ + DO_ARCH_ENTRY_EMPTY5,DO_ARCH_ENTRY_EMPTY6, \ + DO_ARCH_ENTRY_EMPTY6) \ // client macro to operate only on StubGenerator generci and arch entries #define STUBGEN_ALL_ENTRIES_DO(do_entry, do_entry_init, do_entry_array, \ - do_arch_entry, do_arch_entry_init) \ + do_arch_entry, do_arch_entry_init, \ + do_arch_entry_array) \ STUBGEN_ALL_DO(DO_BLOB_EMPTY1, DO_BLOB_EMPTY1, \ DO_STUB_EMPTY2, \ do_entry, do_entry_init, \ do_entry_array, \ DO_ARCH_BLOB_EMPTY2, \ - do_arch_entry, do_arch_entry_init) \ + do_arch_entry, do_arch_entry_init, \ + do_arch_entry_array) \ // client macro to operate only on StubGenerator entries @@ -1241,7 +1266,8 @@ do_entry, do_entry_init, \ do_entry_array, \ DO_ARCH_BLOB_EMPTY2, \ - DO_ARCH_ENTRY_EMPTY5, DO_ARCH_ENTRY_EMPTY6) \ + DO_ARCH_ENTRY_EMPTY5, DO_ARCH_ENTRY_EMPTY6, \ + DO_ARCH_ENTRY_EMPTY6) \ // client macro to operate only on StubGenerator arch blobs @@ -1251,16 +1277,19 @@ DO_ENTRY_EMPTY4, DO_ENTRY_EMPTY5, \ DO_ENTRY_EMPTY5, \ do_arch_blob, \ - DO_ARCH_ENTRY_EMPTY5, DO_ARCH_ENTRY_EMPTY6) \ + DO_ARCH_ENTRY_EMPTY5, DO_ARCH_ENTRY_EMPTY6, \ + DO_ARCH_ENTRY_EMPTY6) \ // client macro to operate only on StubGenerator arch entries -#define STUBGEN_ARCH_ENTRIES_DO(do_arch_entry, do_arch_entry_init) \ +#define STUBGEN_ARCH_ENTRIES_DO(do_arch_entry, do_arch_entry_init, \ + do_arch_entry_array) \ STUBGEN_ALL_DO(DO_BLOB_EMPTY1, DO_BLOB_EMPTY1, \ DO_STUB_EMPTY2, \ DO_ENTRY_EMPTY4, DO_ENTRY_EMPTY5, \ DO_ENTRY_EMPTY5, \ DO_ARCH_BLOB_EMPTY2, \ - do_arch_entry, do_arch_entry_init) \ + do_arch_entry, do_arch_entry_init, \ + do_arch_entry_array) \ #endif // SHARE_RUNTIME_STUBDECLARATIONS_HPP diff --git a/src/hotspot/share/runtime/stubInfo.cpp b/src/hotspot/share/runtime/stubInfo.cpp index c07c0298f2b..4d4d865cf95 100644 --- a/src/hotspot/share/runtime/stubInfo.cpp +++ b/src/hotspot/share/runtime/stubInfo.cpp @@ -574,6 +574,18 @@ void StubInfo::process_stubgen_entry(StubGroup& group_cursor, field_name, id), \ 0); \ +#define PROCESS_STUBGEN_ENTRY_ARCH_ARRAY(arch_name, blob, stub, \ + field_name, getter_name, \ + count) \ + process_stubgen_entry(_group_cursor, _blob_cursor, \ + _stub_cursor, _entry_cursor, \ + #arch_name "_" # field_name "_entry (stub gen)", \ + BlobId:: JOIN3(stubgen, blob, id), \ + StubId:: JOIN3(stubgen, stub, id), \ + EntryId:: JOIN4(stubgen, arch_name, \ + field_name, id), \ + count); \ + void StubInfo::populate_stub_tables() { StubGroup _group_cursor; BlobId _blob_cursor = BlobId::NO_BLOBID; @@ -615,7 +627,8 @@ void StubInfo::populate_stub_tables() { PROCESS_STUBGEN_ENTRY, PROCESS_STUBGEN_ENTRY_INIT, PROCESS_STUBGEN_ENTRY_ARRAY, DO_ARCH_BLOB_EMPTY2, - PROCESS_STUBGEN_ENTRY_ARCH, PROCESS_STUBGEN_ENTRY_ARCH_INIT); + PROCESS_STUBGEN_ENTRY_ARCH, PROCESS_STUBGEN_ENTRY_ARCH_INIT, + PROCESS_STUBGEN_ENTRY_ARCH_ARRAY); assert(next(_blob_cursor) == BlobId::NUM_BLOBIDS, "should have exhausted all blob ids!"); assert(next(_stub_cursor) == StubId::NUM_STUBIDS, "should have exhausted all stub ids!"); assert(next(_entry_cursor) == EntryId::NUM_ENTRYIDS, "should have exhausted all entry ids!"); @@ -636,6 +649,7 @@ void StubInfo::populate_stub_tables() { #undef PROCESS_STUBGEN_ENTRY_ARRAY #undef PROCESS_STUBGEN_ENTRY_ARCH #undef PROCESS_STUBGEN_ENTRY_ARCH_INIT +#undef PROCESS_STUBGEN_ENTRY_ARCH_ARRAY #ifdef ASSERT diff --git a/src/hotspot/share/runtime/stubInfo.hpp b/src/hotspot/share/runtime/stubInfo.hpp index 447f7d3a582..2fe503a8d0e 100644 --- a/src/hotspot/share/runtime/stubInfo.hpp +++ b/src/hotspot/share/runtime/stubInfo.hpp @@ -349,6 +349,14 @@ enum class StubId : int { init_function) \ JOIN4(stubgen, arch_name, field_name, id), \ +#define STUBGEN_DECLARE_ARCH_ARRAY_TAG(arch_name, blob_name, stub_name, \ + field_name, getter_name, \ + count) \ + JOIN4(stubgen, arch_name, field_name, id), \ + JOIN4(stubgen, arch_name, field_name, max) = \ + JOIN4(stubgen, arch_name, field_name, id) + \ + count - 1, \ + // the above macros are enough to declare the enum enum class EntryId : int { @@ -366,7 +374,8 @@ enum class EntryId : int { STUBGEN_DECLARE_INIT_TAG, STUBGEN_DECLARE_ARRAY_TAG, STUBGEN_DECLARE_ARCH_TAG, - STUBGEN_DECLARE_ARCH_INIT_TAG) + STUBGEN_DECLARE_ARCH_INIT_TAG, + STUBGEN_DECLARE_ARCH_ARRAY_TAG) NUM_ENTRYIDS }; @@ -379,6 +388,7 @@ enum class EntryId : int { #undef STUBGEN_DECLARE_ARRAY_TAG #undef STUBGEN_DECLARE_ARCH_TAG #undef STUBGEN_DECLARE_ARCH_INIT_TAG +#undef STUBGEN_DECLARE_ARCH_ARRAY_TAG // we need static init expressions for blob, stub and entry counts in // each stubgroup @@ -404,7 +414,8 @@ enum class EntryId : int { #define STUBGEN_ENTRY_COUNT_INITIALIZER \ 0 STUBGEN_ALL_ENTRIES_DO(COUNT4, COUNT5, \ STUBGEN_COUNT5, \ - COUNT5, COUNT6) + COUNT5, COUNT6, \ + STUBGEN_COUNT6) // Declare management class StubInfo From d114e8d05827d3e4756aeb8bbe115ec02b066da7 Mon Sep 17 00:00:00 2001 From: David Beaumont Date: Wed, 15 Apr 2026 09:22:34 +0000 Subject: [PATCH 290/359] 8375649: idea.sh script adds source paths in a single, enormous, line to jdk.iml Reviewed-by: erikj, liach --- bin/idea.sh | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/bin/idea.sh b/bin/idea.sh index a184884b61a..d9a18956e3b 100644 --- a/bin/idea.sh +++ b/bin/idea.sh @@ -187,14 +187,18 @@ fi SOURCE_PREFIX="" +# SOURCES is a single string containing embeded newlines. for root in $MODULE_ROOTS; do if [ "x$CYGPATH" != "x" ]; then root=`$CYGPATH -am $root` elif [ "x$WSL_DISTRO_NAME" != "x" ]; then root=`wslpath -am $root` fi - - SOURCES=$SOURCES" $SOURCE_PREFIX""$root""$SOURCE_POSTFIX" + # Add line termination/indentation for everything after the first entry. + if [ "x$SOURCES" != "x" ]; then + SOURCES="${SOURCES}\n " + fi + SOURCES="${SOURCES}${SOURCE_PREFIX}${root}${SOURCE_POSTFIX}" done add_replacement "###SOURCE_ROOTS###" "$SOURCES" From aece6f483250d14af3c8a728de6817bb98f10436 Mon Sep 17 00:00:00 2001 From: Daniel Fuchs Date: Wed, 15 Apr 2026 11:21:07 +0000 Subject: [PATCH 291/359] 8381842: Refactor remaining TestNG tests under java/net/ to use JUnit Reviewed-by: vyazici --- .../java/net/DatagramPacket/Constructor.java | 65 +++--- test/jdk/java/net/DatagramPacket/Getters.java | 12 +- test/jdk/java/net/DatagramPacket/Setters.java | 52 +++-- .../InetAddress/HostsFileOrderingTest.java | 48 ++-- .../java/net/InetSocketAddress/ToString.java | 103 ++++----- .../net/NetworkInterface/NullMacAddress.java | 30 ++- .../jdk/java/net/SocketOption/AfterClose.java | 101 ++++---- .../net/SocketOption/CachedImplOptions.java | 53 +++-- .../net/SocketOption/ImmutableOptions.java | 67 +++--- .../net/SocketOption/NullsAndBadValues.java | 215 +++++++++--------- .../net/SocketOption/RequiredOptions.java | 13 +- test/jdk/java/net/SocketPermission/Ctor.java | 63 ++--- test/jdk/java/net/Socks/SocksIPv6Test.java | 55 ++--- .../java/net/Socks/SocksSocketImplTest.java | 39 ++-- .../UnixDomainSocketAddress/AddressTest.java | 12 +- .../UnixDomainSocketAddress/LengthTest.java | 69 +++--- ...xDomainSocketAddressSerializationTest.java | 38 ++-- 17 files changed, 527 insertions(+), 508 deletions(-) diff --git a/test/jdk/java/net/DatagramPacket/Constructor.java b/test/jdk/java/net/DatagramPacket/Constructor.java index ff77d51b798..9f108a263e9 100644 --- a/test/jdk/java/net/DatagramPacket/Constructor.java +++ b/test/jdk/java/net/DatagramPacket/Constructor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,18 +25,19 @@ * @bug 4091803 7021373 * @summary this tests that the constructor of DatagramPacket rejects * bogus arguments properly. - * @run testng Constructor + * @run junit ${test.main.class} */ import java.net.DatagramPacket; import java.net.InetAddress; import java.net.InetSocketAddress; -import org.testng.annotations.Test; - -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.expectThrows; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; public class Constructor { @@ -48,35 +49,33 @@ public class Constructor { @Test public void testNullPacket() { - expectThrows(NPE, + assertThrows(NPE, () -> new DatagramPacket(null, 100)); } @Test public void testNull() throws Exception { - expectThrows(NPE, () -> new DatagramPacket(null, 100)); - expectThrows(NPE, () -> new DatagramPacket(null, 0, 10)); - expectThrows(NPE, () -> new DatagramPacket(null, 0, 10, LOOPBACK, 80)); - expectThrows(NPE, () -> new DatagramPacket(null, 10, LOOPBACK, 80)); - expectThrows(NPE, () -> new DatagramPacket(null, 0, 10, new InetSocketAddress(80))); - expectThrows(NPE, () -> new DatagramPacket(null, 10, new InetSocketAddress(80))); + assertThrows(NPE, () -> new DatagramPacket(null, 100)); + assertThrows(NPE, () -> new DatagramPacket(null, 0, 10)); + assertThrows(NPE, () -> new DatagramPacket(null, 0, 10, LOOPBACK, 80)); + assertThrows(NPE, () -> new DatagramPacket(null, 10, LOOPBACK, 80)); + assertThrows(NPE, () -> new DatagramPacket(null, 0, 10, new InetSocketAddress(80))); + assertThrows(NPE, () -> new DatagramPacket(null, 10, new InetSocketAddress(80))); // no Exception expected for null addresses - new DatagramPacket(buf, 10, null, 0); - new DatagramPacket(buf, 10, 10, null, 0); + assertDoesNotThrow(() -> new DatagramPacket(buf, 10, null, 0)); + assertDoesNotThrow(() -> new DatagramPacket(buf, 10, 10, null, 0)); } @Test public void testNegativeBufferLength() { /* length lesser than buffer length */ - expectThrows(IAE, - () -> new DatagramPacket(buf, -128)); + assertThrows(IAE, () -> new DatagramPacket(buf, -128)); } @Test public void testPacketLengthTooLarge() { /* length greater than buffer length */ - expectThrows(IAE, - () -> new DatagramPacket(buf, 256)); + assertThrows(IAE, () -> new DatagramPacket(buf, 256)); } @Test @@ -84,14 +83,14 @@ public class Constructor { /* negative port */ InetAddress addr = InetAddress.getLocalHost(); - expectThrows(IAE, + assertThrows(IAE, () -> new DatagramPacket(buf, 100, addr, -1)); } @Test public void testPortValueTooLarge() { /* invalid port value */ - expectThrows(IAE, + assertThrows(IAE, () -> new DatagramPacket(buf, 128, LOOPBACK, Integer.MAX_VALUE)); } @@ -101,8 +100,9 @@ public class Constructor { int length = 50; DatagramPacket pkt = new DatagramPacket(buf, offset, length); - assertFalse((pkt.getData() != buf || pkt.getOffset() != offset || - pkt.getLength() != length), "simple constructor failed"); + assertSame(buf, pkt.getData()); + assertEquals(offset, pkt.getOffset()); + assertEquals(length, pkt.getLength()); } @Test @@ -112,20 +112,21 @@ public class Constructor { int port = 8080; DatagramPacket packet = new DatagramPacket(buf, offset, length, LOOPBACK, port); - assertFalse((packet.getData() != buf || packet.getOffset() != offset || - packet.getLength() != length || - packet.getAddress() != LOOPBACK || - packet.getPort() != port), "full constructor failed"); + assertSame(buf, packet.getData()); + assertEquals(offset, packet.getOffset()); + assertEquals(length, packet.getLength()); + assertSame(LOOPBACK, packet.getAddress()); + assertEquals(port, packet.getPort()); } @Test public void testDefaultValues() { DatagramPacket packet = new DatagramPacket(buf, 0); - assertTrue(packet.getAddress() == null); - assertTrue(packet.getPort() == 0); + assertNull(packet.getAddress()); + assertEquals(0, packet.getPort()); DatagramPacket packet1 = new DatagramPacket(buf, 0, 0); - assertTrue(packet1.getAddress() == null); - assertTrue(packet1.getPort() == 0); + assertNull(packet1.getAddress()); + assertEquals(0, packet1.getPort()); } } diff --git a/test/jdk/java/net/DatagramPacket/Getters.java b/test/jdk/java/net/DatagramPacket/Getters.java index f2e1c40603c..c66f7966267 100644 --- a/test/jdk/java/net/DatagramPacket/Getters.java +++ b/test/jdk/java/net/DatagramPacket/Getters.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * 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,15 +24,15 @@ /* @test * @bug 8237890 * @summary Check that DatagramPacket's get methods perform as expected - * @run testng Getters + * @run junit ${test.main.class} */ -import org.testng.annotations.Test; - import java.net.DatagramPacket; import java.net.InetSocketAddress; -import static org.testng.Assert.assertTrue; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; public class Getters { @@ -42,6 +42,6 @@ public class Getters { InetSocketAddress addr = (InetSocketAddress)packet.getSocketAddress(); assertTrue(addr.getAddress().isAnyLocalAddress()); - assertTrue(addr.getPort() == 0); + assertEquals(0, addr.getPort()); } } diff --git a/test/jdk/java/net/DatagramPacket/Setters.java b/test/jdk/java/net/DatagramPacket/Setters.java index 0e950c4f7f2..74424339a18 100644 --- a/test/jdk/java/net/DatagramPacket/Setters.java +++ b/test/jdk/java/net/DatagramPacket/Setters.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,17 +25,19 @@ * @bug 7021373 * @summary check that the DatagramPacket setter methods * throw the correct exceptions - * @run testng Setters + * @run junit ${test.main.class} */ import java.net.DatagramPacket; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.expectThrows; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; public class Setters { @@ -50,11 +52,10 @@ public class Setters { // No Exception expected for null addresses pkt.setAddress(null); - assertTrue(pkt.getAddress() == null); + assertNull(pkt.getAddress()); } - @DataProvider - Object[][] data() { // add checks for setAddress with null - add getAddress to verify + static Object[][] data() { // add checks for setAddress with null - add getAddress to verify return new Object[][]{ { buf, 0, -1, IAE }, { buf, -1, 1, IAE }, @@ -66,24 +67,24 @@ public class Setters { }; } - @Test(dataProvider = "data") + @ParameterizedTest + @MethodSource("data") public void testSetData(byte[] buf, int offset, int length, Class exception) { DatagramPacket pkt = new DatagramPacket(new byte[8], 8); + if (exception != null) { - expectThrows(exception, () -> pkt.setData(buf, offset, length)); - } else if (buf == null) { - expectThrows(exception, () -> pkt.setData(buf)); + assertThrows(exception, () -> pkt.setData(buf, offset, length)); + if (buf == null) assertThrows(exception, () -> pkt.setData(buf)); } else { - pkt.setData(buf, offset, length); + assertDoesNotThrow(() -> pkt.setData(buf, offset, length)); } } - @DataProvider - Object[][] lengths() { + static Object[][] lengths() { return new Object[][]{ { 0, -1, IAE }, { 8, 1, IAE }, @@ -94,20 +95,20 @@ public class Setters { }; } - @Test(dataProvider = "lengths") + @ParameterizedTest + @MethodSource("lengths") public void testSetLength(int offset, int length, Class exception) { DatagramPacket pkt = new DatagramPacket(new byte[8], offset, 0); if (exception != null) { - expectThrows(exception, () -> pkt.setLength(length)); + assertThrows(exception, () -> pkt.setLength(length)); } else { - pkt.setLength(length); + assertDoesNotThrow(() -> pkt.setLength(length)); } } - @DataProvider - Object[][] ports() { + static Object[][] ports() { return new Object[][]{ { -1, IAE }, { -666, IAE }, @@ -122,14 +123,15 @@ public class Setters { }; } - @Test(dataProvider = "ports") + @ParameterizedTest + @MethodSource("ports") public void testSetPort(int port, Class exception) { DatagramPacket pkt = new DatagramPacket(new byte[8], 0); if (exception != null) { - expectThrows(exception, () -> pkt.setPort(port)); + assertThrows(exception, () -> pkt.setPort(port)); } else { - pkt.setPort(port); + assertDoesNotThrow(() -> pkt.setPort(port)); } } } diff --git a/test/jdk/java/net/InetAddress/HostsFileOrderingTest.java b/test/jdk/java/net/InetAddress/HostsFileOrderingTest.java index 304180b6c48..56b52b2a264 100644 --- a/test/jdk/java/net/InetAddress/HostsFileOrderingTest.java +++ b/test/jdk/java/net/InetAddress/HostsFileOrderingTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * 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,9 +34,9 @@ import java.util.stream.Stream; import jdk.test.lib.net.IPSupport; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.Test; -import org.testng.Assert; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.fail; /* @test @@ -46,23 +46,23 @@ import org.testng.Assert; * @summary Test that "jdk.net.hosts.file" NameService implementation returns addresses * with respect to "java.net.preferIPv4Stack" and "java.net.preferIPv6Addresses" system * property values - * @run testng/othervm -Djdk.net.hosts.file=TestHostsFile.txt - * -Djava.net.preferIPv4Stack=true -Djava.net.preferIPv6Addresses=true HostsFileOrderingTest - * @run testng/othervm -Djdk.net.hosts.file=TestHostsFile.txt - * -Djava.net.preferIPv4Stack=true -Djava.net.preferIPv6Addresses=false HostsFileOrderingTest - * @run testng/othervm -Djdk.net.hosts.file=TestHostsFile.txt - * -Djava.net.preferIPv4Stack=true -Djava.net.preferIPv6Addresses=system HostsFileOrderingTest - * @run testng/othervm -Djdk.net.hosts.file=TestHostsFile.txt - * -Djava.net.preferIPv4Stack=true -Djava.net.preferIPv6Addresses=notVALID HostsFileOrderingTest - * @run testng/othervm -Djdk.net.hosts.file=TestHostsFile.txt - * -Djava.net.preferIPv4Stack=false -Djava.net.preferIPv6Addresses=true HostsFileOrderingTest - * @run testng/othervm -Djdk.net.hosts.file=TestHostsFile.txt - * -Djava.net.preferIPv4Stack=false -Djava.net.preferIPv6Addresses=false HostsFileOrderingTest - * @run testng/othervm -Djdk.net.hosts.file=TestHostsFile.txt - * -Djava.net.preferIPv4Stack=false -Djava.net.preferIPv6Addresses=system HostsFileOrderingTest - * @run testng/othervm -Djdk.net.hosts.file=TestHostsFile.txt - * -Djava.net.preferIPv4Stack=false -Djava.net.preferIPv6Addresses=notVALID HostsFileOrderingTest - * @run testng/othervm -Djdk.net.hosts.file=TestHostsFile.txt HostsFileOrderingTest + * @run junit/othervm -Djdk.net.hosts.file=TestHostsFile.txt + * -Djava.net.preferIPv4Stack=true -Djava.net.preferIPv6Addresses=true ${test.main.class} + * @run junit/othervm -Djdk.net.hosts.file=TestHostsFile.txt + * -Djava.net.preferIPv4Stack=true -Djava.net.preferIPv6Addresses=false ${test.main.class} + * @run junit/othervm -Djdk.net.hosts.file=TestHostsFile.txt + * -Djava.net.preferIPv4Stack=true -Djava.net.preferIPv6Addresses=system ${test.main.class} + * @run junit/othervm -Djdk.net.hosts.file=TestHostsFile.txt + * -Djava.net.preferIPv4Stack=true -Djava.net.preferIPv6Addresses=notVALID ${test.main.class} + * @run junit/othervm -Djdk.net.hosts.file=TestHostsFile.txt + * -Djava.net.preferIPv4Stack=false -Djava.net.preferIPv6Addresses=true ${test.main.class} + * @run junit/othervm -Djdk.net.hosts.file=TestHostsFile.txt + * -Djava.net.preferIPv4Stack=false -Djava.net.preferIPv6Addresses=false ${test.main.class} + * @run junit/othervm -Djdk.net.hosts.file=TestHostsFile.txt + * -Djava.net.preferIPv4Stack=false -Djava.net.preferIPv6Addresses=system ${test.main.class} + * @run junit/othervm -Djdk.net.hosts.file=TestHostsFile.txt + * -Djava.net.preferIPv4Stack=false -Djava.net.preferIPv6Addresses=notVALID ${test.main.class} + * @run junit/othervm -Djdk.net.hosts.file=TestHostsFile.txt ${test.main.class} */ public class HostsFileOrderingTest { @@ -70,8 +70,8 @@ public class HostsFileOrderingTest { /* * Generate hosts file with the predefined list of IP addresses */ - @BeforeClass - public void generateHostsFile() throws Exception { + @BeforeAll + public static void generateHostsFile() throws Exception { String content = ADDRESSES_LIST.stream() .map(addr -> addr + " " + TEST_HOST_NAME) .collect( @@ -97,7 +97,7 @@ public class HostsFileOrderingTest { } else { System.err.printf("Expected addresses:%n%s%n", Arrays.deepToString(expectedAddresses)); System.err.printf("Resolved addresses:%n%s%n", Arrays.deepToString(resolvedAddresses)); - Assert.fail("Wrong host resolution result is returned"); + fail("Wrong host resolution result is returned"); } } diff --git a/test/jdk/java/net/InetSocketAddress/ToString.java b/test/jdk/java/net/InetSocketAddress/ToString.java index 12eb599b872..a86e6c714f0 100644 --- a/test/jdk/java/net/InetSocketAddress/ToString.java +++ b/test/jdk/java/net/InetSocketAddress/ToString.java @@ -26,21 +26,27 @@ * @bug 8225499 4464064 * @library /test/lib * @summary InetSocketAddress::toString not friendly to IPv6 literal addresses - * @run testng/othervm ToString - * @run testng/othervm -Djava.net.preferIPv4Stack=true ToString - * @run testng/othervm -Djava.net.preferIPv6Addresses=true ToString + * @run junit/othervm ${test.main.class} + * @run junit/othervm -Djava.net.preferIPv4Stack=true ${test.main.class} + * @run junit/othervm -Djava.net.preferIPv6Addresses=true ${test.main.class} */ -import java.net.*; -import java.util.Optional; - -import org.testng.SkipException; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.UnknownHostException; import static jdk.test.lib.net.IPSupport.diagnoseConfigurationIssue; +import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; + public class ToString { private static final String loopbackAddr; @@ -75,22 +81,19 @@ public class ToString { } } - @BeforeTest - public void setup() { - Optional configurationIssue = diagnoseConfigurationIssue(); - configurationIssue.map(SkipException::new).ifPresent(x -> { - throw x; - }); + @BeforeAll + public static void setup() { + diagnoseConfigurationIssue().ifPresent(Assumptions::abort); } @Test - // InetSocketAddress.toString() throws NPE with unresolved address - public static void NPETest() { - System.out.println(new InetSocketAddress("unresolved", 12345)); + public void NPETest() { + // Test that InetSocketAddress.toString() does not throw NPE with unresolved address + assertDoesNotThrow(() -> System.out.println( + new InetSocketAddress("unresolved", 12345))); } - @DataProvider(name = "hostPortArgs") - public Object[][] createArgs1() { + public static Object[][] fromHostStringAndPort() { return new Object[][]{ // hostname, port number, expected string in format // /: or @@ -106,44 +109,34 @@ public class ToString { }; } - @Test(dataProvider = "hostPortArgs") - public static void testConstructor(String host, int port, String string) { + @ParameterizedTest + @MethodSource("fromHostStringAndPort") + public void testConstructor(String host, int port, String string) { String received = new InetSocketAddress(host, port).toString(); - - if (!string.equals(received)) { - throw new RuntimeException("Expected: " + string + " Received: " + received); - } + assertEquals(string, received); } - @DataProvider(name = "addrPortArgs") - public Object[][] createArgs2() { + public static Object[][] fromInetAddressAndPort() throws UnknownHostException { InetAddress nullAddr = null; - try { - return new Object[][]{ - // InetAddress, port number, expected string - {InetAddress.getLoopbackAddress(), 80, "localhost/" + loopbackAddr + ":80"}, - {InetAddress.getLocalHost(), 80, localAddr + ":80"}, - {InetAddress.getByAddress(new byte[]{1, 1, 1, 1}), 80, "/1.1.1.1:80"}, - {InetAddress.getByAddress(new byte[]{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}), 80, "/[101:101:101:101:101:101:101:101]:80"}, - {InetAddress.getByName("225.225.225.0"), 80, "/225.225.225.0:80"}, - {nullAddr, 80, wildcardAddr + ":80"} - }; - } catch (UnknownHostException uhe) { - throw new RuntimeException("Data provider creation failed: " + uhe, uhe); - } + return new Object[][]{ + // InetAddress, port number, expected string + {InetAddress.getLoopbackAddress(), 80, "localhost/" + loopbackAddr + ":80"}, + {InetAddress.getLocalHost(), 80, localAddr + ":80"}, + {InetAddress.getByAddress(new byte[]{1, 1, 1, 1}), 80, "/1.1.1.1:80"}, + {InetAddress.getByAddress(new byte[]{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}), 80, "/[101:101:101:101:101:101:101:101]:80"}, + {InetAddress.getByName("225.225.225.0"), 80, "/225.225.225.0:80"}, + {nullAddr, 80, wildcardAddr + ":80"} + }; } - @Test(dataProvider = "addrPortArgs") - public static void testConstructor(InetAddress addr, int port, String string) { + @ParameterizedTest + @MethodSource("fromInetAddressAndPort") + public void testConstructor(InetAddress addr, int port, String string) { String received = new InetSocketAddress(addr, port).toString(); - - if (!string.equals(received)) { - throw new RuntimeException("Expected: " + string + " Received: " + received); - } + assertEquals(string, received); } - @DataProvider(name = "unresolved") - public Object[][] createArgs3() { + public static Object[][] unresolvedFromHostStringAndPort() { return new Object[][]{ // hostname, port number, expected string {"::1", 80, "::1/:80"}, @@ -158,12 +151,10 @@ public class ToString { }; } - @Test(dataProvider = "unresolved") - public static void testCreateUnresolved(String host, int port, String string) { + @ParameterizedTest + @MethodSource("unresolvedFromHostStringAndPort") + public void testCreateUnresolved(String host, int port, String string) { String received = InetSocketAddress.createUnresolved(host, port).toString(); - - if (!string.equals(received)) { - throw new RuntimeException("Expected: " + string + " Received: " + received); - } + assertEquals(string, received); } } diff --git a/test/jdk/java/net/NetworkInterface/NullMacAddress.java b/test/jdk/java/net/NetworkInterface/NullMacAddress.java index 8161670860e..8edb447e44e 100644 --- a/test/jdk/java/net/NetworkInterface/NullMacAddress.java +++ b/test/jdk/java/net/NetworkInterface/NullMacAddress.java @@ -26,34 +26,30 @@ * @summary Test that querrying the mac address of the loopback interface * returns null and doesn't throw a SocketException. * @library /test/lib - * @run testng/othervm NullMacAddress - * @run testng/othervm -Djava.net.preferIPv6Addresses=true NullMacAddress - * @run testng/othervm -Djava.net.preferIPv4Stack=true NullMacAddress + * @run junit/othervm ${test.main.class} + * @run junit/othervm -Djava.net.preferIPv6Addresses=true ${test.main.class} + * @run junit/othervm -Djava.net.preferIPv4Stack=true ${test.main.class} */ -import org.testng.SkipException; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.Test; - import static jdk.test.lib.net.IPSupport.diagnoseConfigurationIssue; -import static org.testng.Assert.*; import java.io.UncheckedIOException; import java.math.BigInteger; import java.net.NetworkInterface; import java.net.SocketException; import java.util.Locale; -import java.util.Optional; + +import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertNull; public class NullMacAddress { - @BeforeTest - void setup() { - Optional configurationIssue = diagnoseConfigurationIssue(); - configurationIssue.map(SkipException::new).ifPresent(x -> { - throw x; - }); + @BeforeAll + public static void setup() { + diagnoseConfigurationIssue().ifPresent(Assumptions::abort); } @Test @@ -64,13 +60,13 @@ public class NullMacAddress { private void testMacAddress(NetworkInterface ni) { try { var name = ni.getDisplayName(); - System.out.println("Testing: " + name); + System.err.println("Testing: " + name); var loopback = ni.isLoopback(); var macAddress = ni.getHardwareAddress(); var hdr = macAddress == null ? "null" : "0x" + new BigInteger(1, macAddress) .toString(16).toUpperCase(Locale.ROOT); - System.out.println(" MAC address: " + hdr + (loopback ? " (loopback)" : "")); + System.err.println(" MAC address: " + hdr + (loopback ? " (loopback)" : "")); if (loopback) { assertNull(macAddress, "Loopback interface \"" + name + "\" doesn't have a null MAC Address"); diff --git a/test/jdk/java/net/SocketOption/AfterClose.java b/test/jdk/java/net/SocketOption/AfterClose.java index 825f344c662..e8cedab7dad 100644 --- a/test/jdk/java/net/SocketOption/AfterClose.java +++ b/test/jdk/java/net/SocketOption/AfterClose.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * 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,12 +25,11 @@ * @test * @bug 8224477 * @summary Ensures that IOException is thrown after the socket is closed - * @run testng AfterClose + * @run junit ${test.main.class} */ import java.io.IOException; import java.lang.reflect.Field; -import java.lang.reflect.Method; import java.net.DatagramSocket; import java.net.MulticastSocket; import java.net.NetworkInterface; @@ -48,11 +47,12 @@ import java.util.List; import java.util.Map; import java.util.stream.Collectors; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import static java.lang.Boolean.*; import static java.net.StandardSocketOptions.*; -import static org.testng.Assert.expectThrows; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import static org.junit.jupiter.api.Assertions.assertThrows; public class AfterClose { @@ -117,8 +117,7 @@ public class AfterClose { // -- Socket - @DataProvider(name = "socketOptionValues") - public Object[][] socketOptionValues() throws Exception { + public static Object[][] socketOptionValues() throws Exception { try (Socket s = new Socket()) { return s.supportedOptions().stream() .map(so -> new Object[] {so, OPTION_VALUES_MAP.get(so)}) @@ -126,49 +125,51 @@ public class AfterClose { } } - @Test(dataProvider = "socketOptionValues") + @ParameterizedTest + @MethodSource("socketOptionValues") public void closedSocketImplUncreated(SocketOption option, List values) throws IOException { Socket socket = createClosedSocketImplUncreated(); for (int i=0; i<3; i++); { for (T value : values) { - expectThrows(IOE, () -> socket.setOption(option, value)); - expectThrows(IOE, () -> socket.getOption(option)); + assertThrows(IOE, () -> socket.setOption(option, value)); + assertThrows(IOE, () -> socket.getOption(option)); } } } - @Test(dataProvider = "socketOptionValues") + @ParameterizedTest + @MethodSource("socketOptionValues") public void closedSocketImplCreated(SocketOption option, List values) throws IOException { Socket socket = createClosedSocketImplCreated(); for (int i=0; i<3; i++); { for (T value : values) { - expectThrows(IOE, () -> socket.setOption(option, value)); - expectThrows(IOE, () -> socket.getOption(option)); + assertThrows(IOE, () -> socket.setOption(option, value)); + assertThrows(IOE, () -> socket.getOption(option)); } } } - @Test(dataProvider = "socketOptionValues") + @ParameterizedTest + @MethodSource("socketOptionValues") public void closedSocketAdapter(SocketOption option, List values) throws IOException { Socket socket = createClosedSocketFromAdapter(); for (int i=0; i<3; i++); { for (T value : values) { - if (!RO.equals(value)) expectThrows(IOE, () -> socket.setOption(option, value)); - expectThrows(IOE, () -> socket.getOption(option)); + if (!RO.equals(value)) assertThrows(IOE, () -> socket.setOption(option, value)); + assertThrows(IOE, () -> socket.getOption(option)); } } } // -- ServerSocket - @DataProvider(name = "serverSocketOptionValues") - public Object[][] serverSocketOptionValues() throws Exception { + public static Object[][] serverSocketOptionValues() throws Exception { try (ServerSocket ss = new ServerSocket()) { return ss.supportedOptions().stream() .map(so -> new Object[] {so, OPTION_VALUES_MAP.get(so)}) @@ -176,33 +177,36 @@ public class AfterClose { } } - @Test(dataProvider = "serverSocketOptionValues") + @ParameterizedTest + @MethodSource("serverSocketOptionValues") public void closedServerSocketImplUncreated(SocketOption option, List values) throws IOException { ServerSocket serverSocket = createClosedServerSocketImplUncreated(); for (int i=0; i<3; i++); { for (T value : values) { - expectThrows(IOE, () -> serverSocket.setOption(option, value)); - expectThrows(IOE, () -> serverSocket.getOption(option)); + assertThrows(IOE, () -> serverSocket.setOption(option, value)); + assertThrows(IOE, () -> serverSocket.getOption(option)); } } } - @Test(dataProvider = "serverSocketOptionValues") + @ParameterizedTest + @MethodSource("serverSocketOptionValues") public void closedServerSocketImplCreated(SocketOption option, List values) throws IOException { ServerSocket serverSocket = createClosedServerSocketImplCreated(); for (int i=0; i<3; i++); { for (T value : values) { - expectThrows(IOE, () -> serverSocket.setOption(option, value)); - expectThrows(IOE, () -> serverSocket.getOption(option)); + assertThrows(IOE, () -> serverSocket.setOption(option, value)); + assertThrows(IOE, () -> serverSocket.getOption(option)); } } } - @Test(dataProvider = "serverSocketOptionValues") + @ParameterizedTest + @MethodSource("serverSocketOptionValues") public void closedServerSocketAdapter(SocketOption option, List values) throws IOException { @@ -212,16 +216,15 @@ public class AfterClose { ServerSocket serverSocket = createClosedServerSocketFromAdapter(); for (int i=0; i<3; i++); { for (T value : values) { - if (!RO.equals(value)) expectThrows(IOE, () -> serverSocket.setOption(option, value)); - expectThrows(IOE, () -> serverSocket.getOption(option)); + if (!RO.equals(value)) assertThrows(IOE, () -> serverSocket.setOption(option, value)); + assertThrows(IOE, () -> serverSocket.getOption(option)); } } } // -- DatagramSocket - @DataProvider(name = "datagramSocketOptionValues") - public Object[][] datagramSocketOptionValues() throws Exception { + public static Object[][] datagramSocketOptionValues() throws Exception { try (DatagramSocket ds = new DatagramSocket()) { return ds.supportedOptions().stream() .map(so -> new Object[] {so, OPTION_VALUES_MAP.get(so)}) @@ -229,49 +232,51 @@ public class AfterClose { } } - @Test(dataProvider = "datagramSocketOptionValues") + @ParameterizedTest + @MethodSource("datagramSocketOptionValues") public void closedUnboundDatagramSocket(SocketOption option, List values) throws IOException { DatagramSocket datagramSocket = createClosedUnboundDatagramSocket(); for (int i=0; i<3; i++); { for (T value : values) { - if (!RO.equals(value)) expectThrows(IOE, () -> datagramSocket.setOption(option, value)); - expectThrows(IOE, () -> datagramSocket.getOption(option)); + if (!RO.equals(value)) assertThrows(IOE, () -> datagramSocket.setOption(option, value)); + assertThrows(IOE, () -> datagramSocket.getOption(option)); } } } - @Test(dataProvider = "datagramSocketOptionValues") + @ParameterizedTest + @MethodSource("datagramSocketOptionValues") public void closedBoundDatagramSocket(SocketOption option, List values) throws IOException { DatagramSocket datagramSocket = createClosedBoundDatagramSocket(); for (int i=0; i<3; i++); { for (T value : values) { - if (!RO.equals(value)) expectThrows(IOE, () -> datagramSocket.setOption(option, value)); - expectThrows(IOE, () -> datagramSocket.getOption(option)); + if (!RO.equals(value)) assertThrows(IOE, () -> datagramSocket.setOption(option, value)); + assertThrows(IOE, () -> datagramSocket.getOption(option)); } } } - @Test(dataProvider = "datagramSocketOptionValues") + @ParameterizedTest + @MethodSource("datagramSocketOptionValues") public void closedDatagramAdapter(SocketOption option, List values) throws IOException { DatagramSocket datagramSocket = createClosedBoundDatagramSocket(); for (int i=0; i<3; i++); { for (T value : values) { - if (!RO.equals(value)) expectThrows(IOE, () -> datagramSocket.setOption(option, value)); - expectThrows(IOE, () -> datagramSocket.getOption(option)); + if (!RO.equals(value)) assertThrows(IOE, () -> datagramSocket.setOption(option, value)); + assertThrows(IOE, () -> datagramSocket.getOption(option)); } } } // -- MulticastSocket - @DataProvider(name = "multicastSocketOptionValues") - public Object[][] multicastSocketOptionValues() throws Exception { + public static Object[][] multicastSocketOptionValues() throws Exception { try (MulticastSocket ms = new MulticastSocket()) { return ms.supportedOptions().stream() .map(so -> new Object[] {so, OPTION_VALUES_MAP.get(so)}) @@ -279,28 +284,30 @@ public class AfterClose { } } - @Test(dataProvider = "multicastSocketOptionValues") + @ParameterizedTest + @MethodSource("multicastSocketOptionValues") public void closedUnboundMulticastSocket(SocketOption option, List values) throws IOException { MulticastSocket multicastSocket = createClosedUnboundMulticastSocket(); for (int i=0; i<3; i++); { for (T value : values) { - if (!RO.equals(value)) expectThrows(IOE, () -> multicastSocket.setOption(option, value)); - expectThrows(IOE, () -> multicastSocket.getOption(option)); + if (!RO.equals(value)) assertThrows(IOE, () -> multicastSocket.setOption(option, value)); + assertThrows(IOE, () -> multicastSocket.getOption(option)); } } } - @Test(dataProvider = "multicastSocketOptionValues") + @ParameterizedTest + @MethodSource("multicastSocketOptionValues") public void closedBoundMulticastSocket(SocketOption option, List values) throws IOException { MulticastSocket multicastSocket = createClosedBoundMulticastSocket(); for (int i=0; i<3; i++); { for (T value : values) { - if (!RO.equals(value)) expectThrows(IOE, () -> multicastSocket.setOption(option, value)); - expectThrows(IOE, () -> multicastSocket.getOption(option)); + if (!RO.equals(value)) assertThrows(IOE, () -> multicastSocket.setOption(option, value)); + assertThrows(IOE, () -> multicastSocket.getOption(option)); } } } diff --git a/test/jdk/java/net/SocketOption/CachedImplOptions.java b/test/jdk/java/net/SocketOption/CachedImplOptions.java index 955414559c2..a5e3ec8f67c 100644 --- a/test/jdk/java/net/SocketOption/CachedImplOptions.java +++ b/test/jdk/java/net/SocketOption/CachedImplOptions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,8 +25,8 @@ * @test * @bug 8241988 * @summary Checks that the caching of options does not affect other impls - * @run testng/othervm CachedImplOptions - * @run testng/othervm -Djava.net.preferIPv4Stack=true CachedImplOptions + * @run junit/othervm ${test.main.class} + * @run junit/othervm -Djava.net.preferIPv4Stack=true ${test.main.class} */ import java.io.IOException; @@ -46,8 +46,11 @@ import java.net.SocketImpl; import java.net.SocketOption; import java.net.StandardSocketOptions; import java.util.Set; -import org.testng.annotations.Test; -import static org.testng.Assert.*; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; public class CachedImplOptions { @@ -58,16 +61,16 @@ public class CachedImplOptions { assertTrue(impl.supportedOptions().contains(StandardSocketOptions.SO_SNDBUF)); } try (var impl = new DatagramSocket(new FooDatagramSocketImpl()) {}) { - assertEquals(impl.supportedOptions(), Set.of(FooDatagramSocketImpl.FOO_OPTION)); - assertEquals(impl.supportedOptions(), Set.of(FooDatagramSocketImpl.FOO_OPTION)); + assertEquals(Set.of(FooDatagramSocketImpl.FOO_OPTION), impl.supportedOptions()); + assertEquals(Set.of(FooDatagramSocketImpl.FOO_OPTION), impl.supportedOptions()); } try (var impl = new DatagramSocket(new BarDatagramSocketImpl()) {}) { - assertEquals(impl.supportedOptions(), Set.of(BarDatagramSocketImpl.BAR_OPTION)); - assertEquals(impl.supportedOptions(), Set.of(BarDatagramSocketImpl.BAR_OPTION)); + assertEquals(Set.of(BarDatagramSocketImpl.BAR_OPTION), impl.supportedOptions()); + assertEquals(Set.of(BarDatagramSocketImpl.BAR_OPTION), impl.supportedOptions()); } try (var impl = new DatagramSocket(new BazDatagramSocketImpl()) {}) { - assertEquals(impl.supportedOptions(), Set.of(BazDatagramSocketImpl.BAZ_OPTION)); - assertEquals(impl.supportedOptions(), Set.of(BazDatagramSocketImpl.BAZ_OPTION)); + assertEquals(Set.of(BazDatagramSocketImpl.BAZ_OPTION), impl.supportedOptions()); + assertEquals(Set.of(BazDatagramSocketImpl.BAZ_OPTION), impl.supportedOptions()); } try (var impl = new DatagramSocket()) { assertTrue(impl.supportedOptions().contains(StandardSocketOptions.SO_SNDBUF)); @@ -86,8 +89,8 @@ public class CachedImplOptions { DatagramSocket.setDatagramSocketImplFactory(() -> new FooDatagramSocketImpl()); try (var impl = new MulticastSocket()) { - assertEquals(impl.supportedOptions(), Set.of(FooDatagramSocketImpl.FOO_OPTION)); - assertEquals(impl.supportedOptions(), Set.of(FooDatagramSocketImpl.FOO_OPTION)); + assertEquals(Set.of(FooDatagramSocketImpl.FOO_OPTION), impl.supportedOptions()); + assertEquals(Set.of(FooDatagramSocketImpl.FOO_OPTION), impl.supportedOptions()); } } @@ -144,16 +147,16 @@ public class CachedImplOptions { assertTrue(impl.supportedOptions().contains(StandardSocketOptions.SO_SNDBUF)); } try (var impl = new Socket(new LarrySocketImpl()) {}) { - assertEquals(impl.supportedOptions(), Set.of(LarrySocketImpl.LARRY_OPTION)); - assertEquals(impl.supportedOptions(), Set.of(LarrySocketImpl.LARRY_OPTION)); + assertEquals(Set.of(LarrySocketImpl.LARRY_OPTION), impl.supportedOptions()); + assertEquals(Set.of(LarrySocketImpl.LARRY_OPTION), impl.supportedOptions()); } try (var impl = new Socket(new CurlySocketImpl()) {}) { - assertEquals(impl.supportedOptions(), Set.of(CurlySocketImpl.CURLY_OPTION)); - assertEquals(impl.supportedOptions(), Set.of(CurlySocketImpl.CURLY_OPTION)); + assertEquals(Set.of(CurlySocketImpl.CURLY_OPTION), impl.supportedOptions()); + assertEquals(Set.of(CurlySocketImpl.CURLY_OPTION), impl.supportedOptions()); } try (var impl = new Socket(new MoeSocketImpl()) {}) { - assertEquals(impl.supportedOptions(), Set.of(MoeSocketImpl.MOE_OPTION)); - assertEquals(impl.supportedOptions(), Set.of(MoeSocketImpl.MOE_OPTION)); + assertEquals(Set.of(MoeSocketImpl.MOE_OPTION), impl.supportedOptions()); + assertEquals(Set.of(MoeSocketImpl.MOE_OPTION), impl.supportedOptions()); } try (var impl = new Socket()) { assertTrue(impl.supportedOptions().contains(StandardSocketOptions.SO_SNDBUF)); @@ -168,16 +171,16 @@ public class CachedImplOptions { assertTrue(impl.supportedOptions().contains(StandardSocketOptions.SO_RCVBUF)); } try (var impl = new ServerSocket(new LarrySocketImpl()) {}) { - assertEquals(impl.supportedOptions(), Set.of(LarrySocketImpl.LARRY_OPTION)); - assertEquals(impl.supportedOptions(), Set.of(LarrySocketImpl.LARRY_OPTION)); + assertEquals(Set.of(LarrySocketImpl.LARRY_OPTION), impl.supportedOptions()); + assertEquals(Set.of(LarrySocketImpl.LARRY_OPTION), impl.supportedOptions()); } try (var impl = new ServerSocket(new CurlySocketImpl()) {}) { - assertEquals(impl.supportedOptions(), Set.of(CurlySocketImpl.CURLY_OPTION)); - assertEquals(impl.supportedOptions(), Set.of(CurlySocketImpl.CURLY_OPTION)); + assertEquals(Set.of(CurlySocketImpl.CURLY_OPTION), impl.supportedOptions()); + assertEquals(Set.of(CurlySocketImpl.CURLY_OPTION), impl.supportedOptions()); } try (var impl = new ServerSocket(new MoeSocketImpl()) {}) { - assertEquals(impl.supportedOptions(), Set.of(MoeSocketImpl.MOE_OPTION)); - assertEquals(impl.supportedOptions(), Set.of(MoeSocketImpl.MOE_OPTION)); + assertEquals(Set.of(MoeSocketImpl.MOE_OPTION), impl.supportedOptions()); + assertEquals(Set.of(MoeSocketImpl.MOE_OPTION), impl.supportedOptions()); } try (var impl = new ServerSocket()) { assertTrue(impl.supportedOptions().contains(StandardSocketOptions.SO_RCVBUF)); diff --git a/test/jdk/java/net/SocketOption/ImmutableOptions.java b/test/jdk/java/net/SocketOption/ImmutableOptions.java index 372a0322a35..14b50afa8d3 100644 --- a/test/jdk/java/net/SocketOption/ImmutableOptions.java +++ b/test/jdk/java/net/SocketOption/ImmutableOptions.java @@ -26,69 +26,84 @@ * @bug 8148609 * @library /test/lib * @summary Assert that the set of socket options are immutable - * @run testng/othervm ImmutableOptions - * @run testng/othervm -Djava.net.preferIPv4Stack=true ImmutableOptions + * @run junit/othervm ${test.main.class} + * @run junit/othervm -Djava.net.preferIPv4Stack=true ${test.main.class} */ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.net.*; -import java.util.Optional; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.DatagramSocketImpl; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketAddress; +import java.net.SocketException; +import java.net.SocketImpl; +import java.net.SocketImplFactory; +import java.net.SocketOption; import java.util.Set; -import org.testng.SkipException; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.Test; - import static jdk.test.lib.net.IPSupport.diagnoseConfigurationIssue; +import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertThrows; + public class ImmutableOptions { - @BeforeTest - void setupServerSocketFactory() throws IOException { - Optional configurationIssue = diagnoseConfigurationIssue(); - configurationIssue.map(SkipException::new).ifPresent(x -> { - throw x; - }); + @BeforeAll + public static void setupServerSocketFactory() throws IOException { + diagnoseConfigurationIssue().ifPresent(Assumptions::abort); ServerSocket.setSocketFactory(new ServerSocketImplFactory()); } - @Test(expectedExceptions = UnsupportedOperationException.class) + @Test public void socketThrows() throws IOException { CustomSocketImpl impl = new CustomSocketImpl(); Socket socket = new CustomSocket(impl); - socket.supportedOptions().clear(); + Set> options = socket.supportedOptions(); + assertThrows(UnsupportedOperationException.class, options::clear); } - @Test(expectedExceptions = UnsupportedOperationException.class) + @Test public void socketImplThrows() throws IOException { CustomSocketImpl impl = new CustomSocketImpl(); - impl.supportedOptions().clear(); + var options = impl.supportedOptions(); + assertThrows(UnsupportedOperationException.class, options::clear); } - @Test(expectedExceptions = UnsupportedOperationException.class) + @Test public void serverSocketThrows() throws IOException { ServerSocket ss = new ServerSocket(); - ss.supportedOptions().clear(); + Set> options = ss.supportedOptions(); + assertThrows(UnsupportedOperationException.class, options::clear); } - @Test(expectedExceptions = UnsupportedOperationException.class) + @Test public void serverSocketImplThrows() throws IOException { ServerSocket ss = new ServerSocket(); - ServerSocketImplFactory.mostRecentlyCreated.supportedOptions().clear(); + Set> options = + ServerSocketImplFactory.mostRecentlyCreated.supportedOptions(); + assertThrows(UnsupportedOperationException.class, options::clear); } - @Test(expectedExceptions = UnsupportedOperationException.class) + @Test public void datagramSocketThrows() throws IOException { CustomDatagramSocketImpl impl = new CustomDatagramSocketImpl(); DatagramSocket socket = new CustomDatagramSocket(impl); - socket.supportedOptions().clear(); + Set> options = socket.supportedOptions(); + assertThrows(UnsupportedOperationException.class, options::clear); } - @Test(expectedExceptions = UnsupportedOperationException.class) + @Test public void datagramSocketImplThrows() throws IOException { CustomDatagramSocketImpl impl = new CustomDatagramSocketImpl(); - impl.supportedOptions().clear(); + Set> options = impl.supportedOptions(); + assertThrows(UnsupportedOperationException.class, options::clear); } diff --git a/test/jdk/java/net/SocketOption/NullsAndBadValues.java b/test/jdk/java/net/SocketOption/NullsAndBadValues.java index 842fd4bc229..d6dab5fa327 100644 --- a/test/jdk/java/net/SocketOption/NullsAndBadValues.java +++ b/test/jdk/java/net/SocketOption/NullsAndBadValues.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,8 +25,8 @@ * @test * @bug 8224477 * @summary Basic test for NPE, UOE, and IAE for get/setOption - * @run testng NullsAndBadValues - * @run testng/othervm -Dsun.net.useExclusiveBind=false NullsAndBadValues + * @run junit ${test.main.class} + * @run junit/othervm -Dsun.net.useExclusiveBind=false ${test.main.class} */ import java.net.DatagramSocket; @@ -43,11 +43,13 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Stream; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import static java.lang.Boolean.*; import static java.net.StandardSocketOptions.*; -import static org.testng.Assert.expectThrows; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import static org.junit.jupiter.api.Assertions.assertThrows; public class NullsAndBadValues { @@ -58,46 +60,46 @@ public class NullsAndBadValues { @Test public void nulls() throws Exception { try (Socket s = new Socket()) { - expectThrows(NPE, () -> s.setOption(null, null)); - expectThrows(NPE, () -> s.setOption(null, "")); - expectThrows(NPE, () -> s.setOption(null, 1)); - expectThrows(NPE, () -> s.getOption(null)); + assertThrows(NPE, () -> s.setOption(null, null)); + assertThrows(NPE, () -> s.setOption(null, "")); + assertThrows(NPE, () -> s.setOption(null, 1)); + assertThrows(NPE, () -> s.getOption(null)); } try (ServerSocket ss = new ServerSocket()) { - expectThrows(NPE, () -> ss.setOption(null, null)); - expectThrows(NPE, () -> ss.setOption(null, "")); - expectThrows(NPE, () -> ss.setOption(null, 1)); - expectThrows(NPE, () -> ss.getOption(null)); + assertThrows(NPE, () -> ss.setOption(null, null)); + assertThrows(NPE, () -> ss.setOption(null, "")); + assertThrows(NPE, () -> ss.setOption(null, 1)); + assertThrows(NPE, () -> ss.getOption(null)); } try (DatagramSocket ds = new DatagramSocket()) { - expectThrows(NPE, () -> ds.setOption(null, null)); - expectThrows(NPE, () -> ds.setOption(null, "")); - expectThrows(NPE, () -> ds.setOption(null, 1)); - expectThrows(NPE, () -> ds.getOption(null)); + assertThrows(NPE, () -> ds.setOption(null, null)); + assertThrows(NPE, () -> ds.setOption(null, "")); + assertThrows(NPE, () -> ds.setOption(null, 1)); + assertThrows(NPE, () -> ds.getOption(null)); } try (MulticastSocket ms = new MulticastSocket()) { - expectThrows(NPE, () -> ms.setOption(null, null)); - expectThrows(NPE, () -> ms.setOption(null, "")); - expectThrows(NPE, () -> ms.setOption(null, 1)); - expectThrows(NPE, () -> ms.getOption(null)); + assertThrows(NPE, () -> ms.setOption(null, null)); + assertThrows(NPE, () -> ms.setOption(null, "")); + assertThrows(NPE, () -> ms.setOption(null, 1)); + assertThrows(NPE, () -> ms.getOption(null)); } try (Socket sa = SocketChannel.open().socket()) { - expectThrows(NPE, () -> sa.setOption(null, null)); - expectThrows(NPE, () -> sa.setOption(null, "")); - expectThrows(NPE, () -> sa.setOption(null, 1)); - expectThrows(NPE, () -> sa.getOption(null)); + assertThrows(NPE, () -> sa.setOption(null, null)); + assertThrows(NPE, () -> sa.setOption(null, "")); + assertThrows(NPE, () -> sa.setOption(null, 1)); + assertThrows(NPE, () -> sa.getOption(null)); } try (ServerSocket ssa = ServerSocketChannel.open().socket()) { - expectThrows(NPE, () -> ssa.setOption(null, null)); - expectThrows(NPE, () -> ssa.setOption(null, "")); - expectThrows(NPE, () -> ssa.setOption(null, 1)); - expectThrows(NPE, () -> ssa.getOption(null)); + assertThrows(NPE, () -> ssa.setOption(null, null)); + assertThrows(NPE, () -> ssa.setOption(null, "")); + assertThrows(NPE, () -> ssa.setOption(null, 1)); + assertThrows(NPE, () -> ssa.getOption(null)); } try (DatagramSocket dsa = DatagramChannel.open().socket()) { - expectThrows(NPE, () -> dsa.setOption(null, null)); - expectThrows(NPE, () -> dsa.setOption(null, "")); - expectThrows(NPE, () -> dsa.setOption(null, 1)); - expectThrows(NPE, () -> dsa.getOption(null)); + assertThrows(NPE, () -> dsa.setOption(null, null)); + assertThrows(NPE, () -> dsa.setOption(null, "")); + assertThrows(NPE, () -> dsa.setOption(null, 1)); + assertThrows(NPE, () -> dsa.getOption(null)); } } @@ -114,67 +116,67 @@ public class NullsAndBadValues { @Test public void uoe() throws Exception { try (Socket s = new Socket()) { - expectThrows(UOE, () -> s.setOption(FAKE_SOCK_OPT, null)); - expectThrows(UOE, () -> s.setOption(FAKE_SOCK_OPT, TRUE)); - expectThrows(UOE, () -> s.setOption(FAKE_SOCK_OPT, FALSE)); - expectThrows(UOE, () -> s.setOption(RAW_SOCK_OPT, "")); - expectThrows(UOE, () -> s.setOption(RAW_SOCK_OPT, 1)); - expectThrows(UOE, () -> s.getOption(FAKE_SOCK_OPT)); - expectThrows(UOE, () -> s.getOption(RAW_SOCK_OPT)); + assertThrows(UOE, () -> s.setOption(FAKE_SOCK_OPT, null)); + assertThrows(UOE, () -> s.setOption(FAKE_SOCK_OPT, TRUE)); + assertThrows(UOE, () -> s.setOption(FAKE_SOCK_OPT, FALSE)); + assertThrows(UOE, () -> s.setOption(RAW_SOCK_OPT, "")); + assertThrows(UOE, () -> s.setOption(RAW_SOCK_OPT, 1)); + assertThrows(UOE, () -> s.getOption(FAKE_SOCK_OPT)); + assertThrows(UOE, () -> s.getOption(RAW_SOCK_OPT)); } try (ServerSocket ss = new ServerSocket()) { - expectThrows(UOE, () -> ss.setOption(FAKE_SOCK_OPT, null)); - expectThrows(UOE, () -> ss.setOption(FAKE_SOCK_OPT, TRUE)); - expectThrows(UOE, () -> ss.setOption(FAKE_SOCK_OPT, FALSE)); - expectThrows(UOE, () -> ss.setOption(RAW_SOCK_OPT, "")); - expectThrows(UOE, () -> ss.setOption(RAW_SOCK_OPT, 1)); - expectThrows(UOE, () -> ss.getOption(FAKE_SOCK_OPT)); - expectThrows(UOE, () -> ss.getOption(RAW_SOCK_OPT)); + assertThrows(UOE, () -> ss.setOption(FAKE_SOCK_OPT, null)); + assertThrows(UOE, () -> ss.setOption(FAKE_SOCK_OPT, TRUE)); + assertThrows(UOE, () -> ss.setOption(FAKE_SOCK_OPT, FALSE)); + assertThrows(UOE, () -> ss.setOption(RAW_SOCK_OPT, "")); + assertThrows(UOE, () -> ss.setOption(RAW_SOCK_OPT, 1)); + assertThrows(UOE, () -> ss.getOption(FAKE_SOCK_OPT)); + assertThrows(UOE, () -> ss.getOption(RAW_SOCK_OPT)); } try (DatagramSocket ds = new DatagramSocket()) { - expectThrows(UOE, () -> ds.setOption(FAKE_SOCK_OPT, null)); - expectThrows(UOE, () -> ds.setOption(FAKE_SOCK_OPT, TRUE)); - expectThrows(UOE, () -> ds.setOption(FAKE_SOCK_OPT, FALSE)); - expectThrows(UOE, () -> ds.setOption(RAW_SOCK_OPT, "")); - expectThrows(UOE, () -> ds.setOption(RAW_SOCK_OPT, 1)); - expectThrows(UOE, () -> ds.getOption(FAKE_SOCK_OPT)); - expectThrows(UOE, () -> ds.getOption(RAW_SOCK_OPT)); + assertThrows(UOE, () -> ds.setOption(FAKE_SOCK_OPT, null)); + assertThrows(UOE, () -> ds.setOption(FAKE_SOCK_OPT, TRUE)); + assertThrows(UOE, () -> ds.setOption(FAKE_SOCK_OPT, FALSE)); + assertThrows(UOE, () -> ds.setOption(RAW_SOCK_OPT, "")); + assertThrows(UOE, () -> ds.setOption(RAW_SOCK_OPT, 1)); + assertThrows(UOE, () -> ds.getOption(FAKE_SOCK_OPT)); + assertThrows(UOE, () -> ds.getOption(RAW_SOCK_OPT)); } try (MulticastSocket ms = new MulticastSocket()) { - expectThrows(UOE, () -> ms.setOption(FAKE_SOCK_OPT, null)); - expectThrows(UOE, () -> ms.setOption(FAKE_SOCK_OPT, TRUE)); - expectThrows(UOE, () -> ms.setOption(FAKE_SOCK_OPT, FALSE)); - expectThrows(UOE, () -> ms.setOption(RAW_SOCK_OPT, "")); - expectThrows(UOE, () -> ms.setOption(RAW_SOCK_OPT, 1)); - expectThrows(UOE, () -> ms.getOption(FAKE_SOCK_OPT)); - expectThrows(UOE, () -> ms.getOption(RAW_SOCK_OPT)); + assertThrows(UOE, () -> ms.setOption(FAKE_SOCK_OPT, null)); + assertThrows(UOE, () -> ms.setOption(FAKE_SOCK_OPT, TRUE)); + assertThrows(UOE, () -> ms.setOption(FAKE_SOCK_OPT, FALSE)); + assertThrows(UOE, () -> ms.setOption(RAW_SOCK_OPT, "")); + assertThrows(UOE, () -> ms.setOption(RAW_SOCK_OPT, 1)); + assertThrows(UOE, () -> ms.getOption(FAKE_SOCK_OPT)); + assertThrows(UOE, () -> ms.getOption(RAW_SOCK_OPT)); } try (Socket sa = SocketChannel.open().socket()) { - expectThrows(UOE, () -> sa.setOption(FAKE_SOCK_OPT, null)); - expectThrows(UOE, () -> sa.setOption(FAKE_SOCK_OPT, TRUE)); - expectThrows(UOE, () -> sa.setOption(FAKE_SOCK_OPT, FALSE)); - expectThrows(UOE, () -> sa.setOption(RAW_SOCK_OPT, "")); - expectThrows(UOE, () -> sa.setOption(RAW_SOCK_OPT, 1)); - expectThrows(UOE, () -> sa.getOption(FAKE_SOCK_OPT)); - expectThrows(UOE, () -> sa.getOption(RAW_SOCK_OPT)); + assertThrows(UOE, () -> sa.setOption(FAKE_SOCK_OPT, null)); + assertThrows(UOE, () -> sa.setOption(FAKE_SOCK_OPT, TRUE)); + assertThrows(UOE, () -> sa.setOption(FAKE_SOCK_OPT, FALSE)); + assertThrows(UOE, () -> sa.setOption(RAW_SOCK_OPT, "")); + assertThrows(UOE, () -> sa.setOption(RAW_SOCK_OPT, 1)); + assertThrows(UOE, () -> sa.getOption(FAKE_SOCK_OPT)); + assertThrows(UOE, () -> sa.getOption(RAW_SOCK_OPT)); } try (ServerSocket ssa = ServerSocketChannel.open().socket()) { - expectThrows(UOE, () -> ssa.setOption(FAKE_SOCK_OPT, null)); - expectThrows(UOE, () -> ssa.setOption(FAKE_SOCK_OPT, TRUE)); - expectThrows(UOE, () -> ssa.setOption(FAKE_SOCK_OPT, FALSE)); - expectThrows(UOE, () -> ssa.setOption(RAW_SOCK_OPT, "")); - expectThrows(UOE, () -> ssa.setOption(RAW_SOCK_OPT, 1)); - expectThrows(UOE, () -> ssa.getOption(FAKE_SOCK_OPT)); - expectThrows(UOE, () -> ssa.getOption(RAW_SOCK_OPT)); + assertThrows(UOE, () -> ssa.setOption(FAKE_SOCK_OPT, null)); + assertThrows(UOE, () -> ssa.setOption(FAKE_SOCK_OPT, TRUE)); + assertThrows(UOE, () -> ssa.setOption(FAKE_SOCK_OPT, FALSE)); + assertThrows(UOE, () -> ssa.setOption(RAW_SOCK_OPT, "")); + assertThrows(UOE, () -> ssa.setOption(RAW_SOCK_OPT, 1)); + assertThrows(UOE, () -> ssa.getOption(FAKE_SOCK_OPT)); + assertThrows(UOE, () -> ssa.getOption(RAW_SOCK_OPT)); } try (DatagramSocket dsa = DatagramChannel.open().socket()) { - expectThrows(UOE, () -> dsa.setOption(FAKE_SOCK_OPT, null)); - expectThrows(UOE, () -> dsa.setOption(FAKE_SOCK_OPT, TRUE)); - expectThrows(UOE, () -> dsa.setOption(FAKE_SOCK_OPT, FALSE)); - expectThrows(UOE, () -> dsa.setOption(RAW_SOCK_OPT, "")); - expectThrows(UOE, () -> dsa.setOption(RAW_SOCK_OPT, 1)); - expectThrows(UOE, () -> dsa.getOption(FAKE_SOCK_OPT)); - expectThrows(UOE, () -> dsa.getOption(RAW_SOCK_OPT)); + assertThrows(UOE, () -> dsa.setOption(FAKE_SOCK_OPT, null)); + assertThrows(UOE, () -> dsa.setOption(FAKE_SOCK_OPT, TRUE)); + assertThrows(UOE, () -> dsa.setOption(FAKE_SOCK_OPT, FALSE)); + assertThrows(UOE, () -> dsa.setOption(RAW_SOCK_OPT, "")); + assertThrows(UOE, () -> dsa.setOption(RAW_SOCK_OPT, 1)); + assertThrows(UOE, () -> dsa.getOption(FAKE_SOCK_OPT)); + assertThrows(UOE, () -> dsa.getOption(RAW_SOCK_OPT)); } } @@ -200,8 +202,7 @@ public class NullsAndBadValues { // -- Socket - @DataProvider(name = "socketBadOptionValues") - public Object[][] socketBadOptionValues() throws Exception { + public static Object[][] socketBadOptionValues() throws Exception { try (Socket s = new Socket()) { return s.supportedOptions().stream() .flatMap(NullsAndBadValues::socketOptionToBadValues) @@ -209,28 +210,29 @@ public class NullsAndBadValues { } } - @Test(dataProvider = "socketBadOptionValues") + @ParameterizedTest + @MethodSource("socketBadOptionValues") public void socket(SocketOption option, T value) throws Exception { try (Socket s = new Socket()) { - expectThrows(IAE, () -> s.setOption(option, value)); + assertThrows(IAE, () -> s.setOption(option, value)); } } - @Test(dataProvider = "socketBadOptionValues") + @ParameterizedTest + @MethodSource("socketBadOptionValues") public void socketAdapter(SocketOption option, T value) throws Exception { try (Socket s = SocketChannel.open().socket()) { - expectThrows(IAE, () -> s.setOption(option, value)); + assertThrows(IAE, () -> s.setOption(option, value)); } } // -- ServerSocket - @DataProvider(name = "serverSocketBadOptionValues") - public Object[][] serverSocketBadOptionValues() throws Exception { + public static Object[][] serverSocketBadOptionValues() throws Exception { try (ServerSocket ss = new ServerSocket()) { return ss.supportedOptions().stream() .flatMap(NullsAndBadValues::socketOptionToBadValues) @@ -238,16 +240,18 @@ public class NullsAndBadValues { } } - @Test(dataProvider = "serverSocketBadOptionValues") + @ParameterizedTest + @MethodSource("serverSocketBadOptionValues") public void serverSocket(SocketOption option, T value) throws Exception { try (ServerSocket ss = new ServerSocket()) { - expectThrows(IAE, () -> ss.setOption(option, value)); + assertThrows(IAE, () -> ss.setOption(option, value)); } } - @Test(dataProvider = "serverSocketBadOptionValues") + @ParameterizedTest + @MethodSource("serverSocketBadOptionValues") public void serverSocketAdapter(SocketOption option, T value) throws Exception { @@ -255,14 +259,13 @@ public class NullsAndBadValues { return; // SSC does not support IP_TOS try (ServerSocket ss = ServerSocketChannel.open().socket()) { - expectThrows(IAE, () -> ss.setOption(option, value)); + assertThrows(IAE, () -> ss.setOption(option, value)); } } // -- DatagramSocket - @DataProvider(name = "datagramSocketBadOptionValues") - public Object[][] datagramSocketBadOptionValues() throws Exception { + public static Object[][] datagramSocketBadOptionValues() throws Exception { try (DatagramSocket ds = new DatagramSocket()) { return ds.supportedOptions().stream() .flatMap(NullsAndBadValues::socketOptionToBadValues) @@ -270,28 +273,29 @@ public class NullsAndBadValues { } } - @Test(dataProvider = "datagramSocketBadOptionValues") + @ParameterizedTest + @MethodSource("datagramSocketBadOptionValues") public void datagramSocket(SocketOption option, T value) throws Exception { try (DatagramSocket ds = new DatagramSocket()) { - expectThrows(IAE, () -> ds.setOption(option, value)); + assertThrows(IAE, () -> ds.setOption(option, value)); } } - @Test(dataProvider = "datagramSocketBadOptionValues") + @ParameterizedTest + @MethodSource("datagramSocketBadOptionValues") public void datagramSocketAdapter(SocketOption option, T value) throws Exception { try (DatagramSocket ds = DatagramChannel.open().socket()) { - expectThrows(IAE, () -> ds.setOption(option, value)); + assertThrows(IAE, () -> ds.setOption(option, value)); } } // -- MulticastSocket - @DataProvider(name = "multicastSocketBadOptionValues") - public Object[][] multicastSocketBadOptionValues() throws Exception { + public static Object[][] multicastSocketBadOptionValues() throws Exception { try (MulticastSocket ms = new MulticastSocket()) { return ms.supportedOptions().stream() .flatMap(NullsAndBadValues::socketOptionToBadValues) @@ -299,12 +303,13 @@ public class NullsAndBadValues { } } - @Test(dataProvider = "multicastSocketBadOptionValues") + @ParameterizedTest + @MethodSource("multicastSocketBadOptionValues") public void multicastSocket(SocketOption option, T value) throws Exception { try (MulticastSocket ms = new MulticastSocket()) { - expectThrows(IAE, () -> ms.setOption(option, value)); + assertThrows(IAE, () -> ms.setOption(option, value)); } } diff --git a/test/jdk/java/net/SocketOption/RequiredOptions.java b/test/jdk/java/net/SocketOption/RequiredOptions.java index 3074d8fd274..2a1c689cae7 100644 --- a/test/jdk/java/net/SocketOption/RequiredOptions.java +++ b/test/jdk/java/net/SocketOption/RequiredOptions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * 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,17 +33,18 @@ import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.util.Set; import java.util.stream.Stream; -import org.testng.annotations.Test; -import org.testng.annotations.DataProvider; import static java.net.StandardSocketOptions.*; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + /* * @test * @bug 8235141 * @summary verifies that our implementation supports the set * of SocketOptions that are required by the API documentation. - * @run testng/othervm RequiredOptions + * @run junit/othervm ${test.main.class} */ public class RequiredOptions { @@ -60,7 +61,6 @@ public class RequiredOptions { return Set.of(Stream.of(options).flatMap(Set::stream).distinct().toArray(SocketOption[]::new)); } - @DataProvider(name = "sockets") static Object[][] provider() throws IOException { return new Object[][] { // UDP @@ -76,7 +76,8 @@ public class RequiredOptions { }; } - @Test(dataProvider = "sockets") + @ParameterizedTest + @MethodSource("provider") public void test(Configurable socket, Set> options) throws E { try (var s = socket) { diff --git a/test/jdk/java/net/SocketPermission/Ctor.java b/test/jdk/java/net/SocketPermission/Ctor.java index dde7596c052..20c194be847 100644 --- a/test/jdk/java/net/SocketPermission/Ctor.java +++ b/test/jdk/java/net/SocketPermission/Ctor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,13 +26,14 @@ * @bug 4391898 8230407 * @summary SocketPermission(":",...) throws ArrayIndexOutOfBoundsException * SocketPermission constructor argument checks - * @run testng Ctor + * @run junit ${test.main.class} */ import java.net.SocketPermission; -import org.testng.annotations.Test; -import static java.lang.System.out; -import static org.testng.Assert.*; +import static java.lang.System.err; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertThrows; public class Ctor { @@ -48,39 +49,39 @@ public class Ctor { @Test public void npe() { NullPointerException e; - e = expectThrows(NPE, () -> new SocketPermission(null, null)); - out.println("caught expected NPE: " + e); - e = expectThrows(NPE, () -> new SocketPermission("foo", null)); - out.println("caught expected NPE: " + e); - e = expectThrows(NPE, () -> new SocketPermission(null, "connect")); - out.println("caught expected NPE: " + e); + e = assertThrows(NPE, () -> new SocketPermission(null, null)); + err.println("caught expected NPE: " + e); + e = assertThrows(NPE, () -> new SocketPermission("foo", null)); + err.println("caught expected NPE: " + e); + e = assertThrows(NPE, () -> new SocketPermission(null, "connect")); + err.println("caught expected NPE: " + e); } @Test public void iae() { IllegalArgumentException e; // host - e = expectThrows(IAE, () -> new SocketPermission("1:2:3:4", "connect")); - out.println("caught expected IAE: " + e); - e = expectThrows(IAE, () -> new SocketPermission("foo:5-4", "connect")); - out.println("caught expected IAE: " + e); + e = assertThrows(IAE, () -> new SocketPermission("1:2:3:4", "connect")); + err.println("caught expected IAE: " + e); + e = assertThrows(IAE, () -> new SocketPermission("foo:5-4", "connect")); + err.println("caught expected IAE: " + e); // actions - e = expectThrows(IAE, () -> new SocketPermission("foo", "")); - out.println("caught expected IAE: " + e); - e = expectThrows(IAE, () -> new SocketPermission("foo", "badAction")); - out.println("caught expected IAE: " + e); - e = expectThrows(IAE, () -> new SocketPermission("foo", "badAction,connect")); - out.println("caught expected IAE: " + e); - e = expectThrows(IAE, () -> new SocketPermission("foo", "badAction,,connect")); - out.println("caught expected IAE: " + e); - e = expectThrows(IAE, () -> new SocketPermission("foo", ",connect")); - out.println("caught expected IAE: " + e); - e = expectThrows(IAE, () -> new SocketPermission("foo", ",,connect")); - out.println("caught expected IAE: " + e); - e = expectThrows(IAE, () -> new SocketPermission("foo", "connect,")); - out.println("caught expected IAE: " + e); - e = expectThrows(IAE, () -> new SocketPermission("foo", "connect,,")); - out.println("caught expected IAE: " + e); + e = assertThrows(IAE, () -> new SocketPermission("foo", "")); + err.println("caught expected IAE: " + e); + e = assertThrows(IAE, () -> new SocketPermission("foo", "badAction")); + err.println("caught expected IAE: " + e); + e = assertThrows(IAE, () -> new SocketPermission("foo", "badAction,connect")); + err.println("caught expected IAE: " + e); + e = assertThrows(IAE, () -> new SocketPermission("foo", "badAction,,connect")); + err.println("caught expected IAE: " + e); + e = assertThrows(IAE, () -> new SocketPermission("foo", ",connect")); + err.println("caught expected IAE: " + e); + e = assertThrows(IAE, () -> new SocketPermission("foo", ",,connect")); + err.println("caught expected IAE: " + e); + e = assertThrows(IAE, () -> new SocketPermission("foo", "connect,")); + err.println("caught expected IAE: " + e); + e = assertThrows(IAE, () -> new SocketPermission("foo", "connect,,")); + err.println("caught expected IAE: " + e); } } diff --git a/test/jdk/java/net/Socks/SocksIPv6Test.java b/test/jdk/java/net/Socks/SocksIPv6Test.java index 1b277bb24fc..a8794724c54 100644 --- a/test/jdk/java/net/Socks/SocksIPv6Test.java +++ b/test/jdk/java/net/Socks/SocksIPv6Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,8 +25,9 @@ * @bug 7100957 * @modules jdk.httpserver * @library /test/lib + * @build SocksServer * @summary Java doesn't correctly handle the SOCKS protocol when used over IPv6. - * @run testng SocksIPv6Test + * @run junit ${test.main.class} */ import java.io.BufferedReader; @@ -45,28 +46,28 @@ import java.net.SocketException; import java.net.NetworkInterface; import java.util.Collections; import java.util.List; -import com.sun.net.httpserver.*; import java.io.BufferedWriter; -import org.testng.SkipException; -import org.testng.annotations.AfterClass; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.Test; +import com.sun.net.httpserver.HttpServer; import jdk.test.lib.NetworkConfiguration; -import static org.testng.Assert.*; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; public class SocksIPv6Test { - private HttpServer server; - private SocksServer socks; - private String response = "Hello."; + private static HttpServer server; + private static SocksServer socks; + private static final String response = "Hello."; - @BeforeClass - public void setUp() throws Exception { + @BeforeAll + public static void setUp() throws Exception { if (!ensureInet6AddressFamily() || !ensureIPv6OnLoopback()) { NetworkConfiguration.printSystemConfiguration(System.out); - throw new SkipException("Host does not support IPv6"); + Assumptions.abort("Host does not support IPv6"); } server = HttpServer.create(new InetSocketAddress("::1", 0), 0); @@ -93,7 +94,7 @@ public class SocksIPv6Test { }); } - private boolean ensureIPv6OnLoopback() throws Exception { + private static boolean ensureIPv6OnLoopback() throws Exception { boolean ipv6 = false; List nics = Collections.list(NetworkInterface.getNetworkInterfaces()); @@ -114,7 +115,7 @@ public class SocksIPv6Test { return ipv6; } - private boolean ensureInet6AddressFamily() throws IOException { + private static boolean ensureInet6AddressFamily() throws IOException { try (ServerSocket s = new ServerSocket()) { s.bind(new InetSocketAddress("::1", 0)); return true; @@ -124,7 +125,7 @@ public class SocksIPv6Test { return false; } - @Test(groups = "unit") + @Test public void testSocksOverIPv6() throws Exception { Proxy proxy = new Proxy(Proxy.Type.SOCKS, new InetSocketAddress("::1", socks.getPort())); @@ -135,10 +136,10 @@ public class SocksIPv6Test { new InputStreamReader(conn.getInputStream()))) { actual = reader.readLine(); } - assertEquals(actual, response); + assertEquals(response, actual); } - @Test(groups = "unit") + @Test public void testSocksOverIPv6Hostname() throws Exception { InetAddress ipv6Loopback = InetAddress.getByName("::1"); String ipv6Hostname = ipv6Loopback.getHostName(); @@ -155,24 +156,24 @@ public class SocksIPv6Test { ipv4HostAddress = null; } - System.out.println("ipv6Hostname: " + ipv6Hostname + " / " + ipv6HostAddress); - System.out.println("ipv4Hostname: " + ipv4Hostname + " / " + ipv4HostAddress); + System.err.println("ipv6Hostname: " + ipv6Hostname + " / " + ipv6HostAddress); + System.err.println("ipv4Hostname: " + ipv4Hostname + " / " + ipv4HostAddress); if (ipv6Hostname.equals(ipv6HostAddress)) { - System.out.println("Unable to get the hostname of the IPv6 loopback " + Assumptions.abort("Unable to get the hostname of the IPv6 loopback " + "address. Skipping test case."); return; } if (ipv4Hostname != null && ipv6Hostname.equals(ipv4Hostname)) { - System.out.println("IPv6 and IPv4 loopback addresses map to the" + Assumptions.abort("IPv6 and IPv4 loopback addresses map to the" + " same hostname. Skipping test case."); return; } if (!InetAddress.getByName(ipv6Hostname).getHostAddress() .equals(ipv6HostAddress)) { - System.out.println(ipv6Hostname + " resolves to \"" + Assumptions.abort(ipv6Hostname + " resolves to \"" + InetAddress.getByName(ipv6Hostname).getHostAddress() + "\", not \"" + ipv6HostAddress + "\". Skipping test case."); @@ -188,11 +189,11 @@ public class SocksIPv6Test { new InputStreamReader(conn.getInputStream()))) { actual = reader.readLine(); } - assertEquals(actual, response); + assertEquals(response, actual); } - @AfterClass - public void tearDown() { + @AfterAll + public static void tearDown() { if (server != null) { server.stop(1); } diff --git a/test/jdk/java/net/Socks/SocksSocketImplTest.java b/test/jdk/java/net/Socks/SocksSocketImplTest.java index 57d54defda3..05792aad784 100644 --- a/test/jdk/java/net/Socks/SocksSocketImplTest.java +++ b/test/jdk/java/net/Socks/SocksSocketImplTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * 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,10 +21,6 @@ * questions. */ -import org.testng.Assert; -import org.testng.annotations.AfterTest; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.Test; import sun.net.spi.DefaultProxySelector; import java.io.IOException; @@ -37,25 +33,33 @@ import java.net.URI; import java.net.URISyntaxException; import java.util.List; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.fail; + /** * @test * @bug 8230310 * @summary Tests java.net.SocksSocketImpl - * @run testng SocksSocketImplTest + * @run junit ${test.main.class} * @modules java.base/sun.net.spi:+open */ public class SocksSocketImplTest { - private ProxySelector previousDefault; + private static ProxySelector previousDefault; - @BeforeTest - public void beforeTest() { + @BeforeAll + public static void beforeTest() { previousDefault = ProxySelector.getDefault(); ProxySelector.setDefault(new SchemeStrippedProxySelector()); } - @AfterTest - public void afterTest() { + @AfterAll + public static void afterTest() { ProxySelector.setDefault(previousDefault); } @@ -65,17 +69,14 @@ public class SocksSocketImplTest { * which throws a {@link IllegalArgumentException}. This test then verifies that this IAE gets wrapped * by {@code java.net.SocksSocketImpl} into an {@link IOException} before being thrown * - * @throws Exception + * @throws Exception if the test fails */ @Test public void testIOEOnProxySelection() throws Exception { final int backlog = -1; final int port = 0; - try (ServerSocket ss = new ServerSocket(port, backlog, InetAddress.getLoopbackAddress()); - Socket s1 = new Socket(ss.getInetAddress(), ss.getLocalPort()); - Socket s2 = ss.accept()) { - Assert.fail("IOException was expected to be thrown, but wasn't"); - } catch (IOException ioe) { + try (ServerSocket ss = new ServerSocket(port, backlog, InetAddress.getLoopbackAddress())) { + IOException ioe = assertThrows(IOException.class, () -> new Socket(ss.getInetAddress(), ss.getLocalPort())); // expected // now verify the IOE was thrown for the correct expected reason if (!(ioe.getCause() instanceof IllegalArgumentException)) { @@ -96,7 +97,7 @@ public class SocksSocketImplTest { @Override public List select(final URI uri) { - System.out.println("Proxy selection for " + uri); + System.err.println("Proxy selection for " + uri); final URI schemeStrippedURI; try { // strip the scheme and pass the rest @@ -104,7 +105,7 @@ public class SocksSocketImplTest { } catch (URISyntaxException e) { throw new RuntimeException(e); } - System.out.println("Scheme stripped URI " + schemeStrippedURI + " is being used to select a proxy"); + System.err.println("Scheme stripped URI " + schemeStrippedURI + " is being used to select a proxy"); return super.select(schemeStrippedURI); } } diff --git a/test/jdk/java/net/UnixDomainSocketAddress/AddressTest.java b/test/jdk/java/net/UnixDomainSocketAddress/AddressTest.java index ba55eac46df..d5d1f295fd1 100644 --- a/test/jdk/java/net/UnixDomainSocketAddress/AddressTest.java +++ b/test/jdk/java/net/UnixDomainSocketAddress/AddressTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,18 +25,16 @@ * @test * @bug 8231358 * @compile ../../nio/file/spi/testfsp/testfsp/TestProvider.java AddressTest.java - * @run testng/othervm AddressTest + * @run junit/othervm ${test.main.class} */ import java.net.UnixDomainSocketAddress; import java.net.URI; import java.nio.file.FileSystems; -import java.nio.file.spi.FileSystemProvider; import java.nio.file.Path; -import org.testng.annotations.Test; - -import static org.testng.Assert.assertThrows; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertThrows; /** * Verify that UnixDomainSocketAddress.of(path) throws IAE @@ -50,7 +48,7 @@ public class AddressTest { IllegalArgumentException.class; @Test - public static void runTest() throws Exception { + public void runTest() throws Exception { var fsp = new testfsp.TestProvider(FileSystems.getDefault().provider()); Path path = fsp.getPath(URI.create("file:/")); assertThrows(IAE, () -> UnixDomainSocketAddress.of(path)); diff --git a/test/jdk/java/net/UnixDomainSocketAddress/LengthTest.java b/test/jdk/java/net/UnixDomainSocketAddress/LengthTest.java index c34c8e001b7..d75658011c9 100644 --- a/test/jdk/java/net/UnixDomainSocketAddress/LengthTest.java +++ b/test/jdk/java/net/UnixDomainSocketAddress/LengthTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * 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,61 +25,54 @@ * @test * @summary Test UnixDomainSocketAddress constructor * @library /test/lib - * @run testng/othervm LengthTest + * @run junit/othervm ${test.main.class} */ -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; -import static java.lang.System.out; -import static java.net.StandardProtocolFamily.UNIX; -import static jdk.test.lib.Asserts.assertTrue; +import static java.lang.System.err; import java.net.UnixDomainSocketAddress; -import java.io.IOException; -import java.nio.channels.SocketChannel; import java.nio.file.Path; +import java.util.List; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; public class LengthTest { - final int namelen = 100; // length close to max + private static final int namelen = 100; // length close to max - @DataProvider(name = "strings") - public Object[][] strings() { - if (namelen == -1) - return new Object[][] {new String[]{""}}; - - return new Object[][]{ - {""}, - {new String(new char[100]).replaceAll("\0", "x")}, - {new String(new char[namelen]).replaceAll("\0", "x")}, - {new String(new char[namelen-1]).replaceAll("\0", "x")}, - }; + public static List strings() { + assert namelen > 0; + return List.of( + "", + "x".repeat(100), + "x".repeat(namelen), + "x".repeat(namelen - 1) + ); } - @Test(dataProvider = "strings") + @ParameterizedTest + @MethodSource("strings") public void expectPass(String s) { var addr = UnixDomainSocketAddress.of(s); - assertTrue(addr.getPath().toString().equals(s), "getPathName.equals(s)"); + assertEquals(s, addr.getPath().toString(), "getPathName.equals(s)"); var p = Path.of(s); addr = UnixDomainSocketAddress.of(p); - assertTrue(addr.getPath().equals(p), "getPath.equals(p)"); + assertEquals(p, addr.getPath(), "getPath.equals(p)"); } @Test public void expectNPE() { - try { - String s = null; - UnixDomainSocketAddress.of(s); - throw new RuntimeException("Expected NPE"); - } catch (NullPointerException npe) { - out.println("\tCaught expected exception: " + npe); - } - try { - Path p = null; - UnixDomainSocketAddress.of(p); - throw new RuntimeException("Expected NPE"); - } catch (NullPointerException npe) { - out.println("\tCaught expected exception: " + npe); - } + String s = null; + NullPointerException npe = + assertThrows(NullPointerException.class, () -> UnixDomainSocketAddress.of(s)); + err.println("\tCaugth expected NPE for UnixDomainSocketAddress.of(s): " + npe); + Path p = null; + npe = assertThrows(NullPointerException.class, () -> UnixDomainSocketAddress.of(p)); + err.println("\tCaugth expected NPE for UnixDomainSocketAddress.of(p): " + npe); } } diff --git a/test/jdk/java/net/UnixDomainSocketAddress/UnixDomainSocketAddressSerializationTest.java b/test/jdk/java/net/UnixDomainSocketAddress/UnixDomainSocketAddressSerializationTest.java index 305b4bee95e..b48805f61b3 100644 --- a/test/jdk/java/net/UnixDomainSocketAddress/UnixDomainSocketAddressSerializationTest.java +++ b/test/jdk/java/net/UnixDomainSocketAddress/UnixDomainSocketAddressSerializationTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 @@ * questions. */ -import org.testng.annotations.Test; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -35,51 +34,56 @@ import java.io.Serializable; import java.net.UnixDomainSocketAddress; import java.nio.file.Path; import static java.io.ObjectStreamConstants.*; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.expectThrows; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; /* * @test * @summary UnixDomainSocketAddress serialization test - * @run testng/othervm UnixDomainSocketAddressSerializationTest + * @run junit/othervm ${test.main.class} */ -@Test public class UnixDomainSocketAddressSerializationTest { private static final UnixDomainSocketAddress addr = UnixDomainSocketAddress.of(Path.of("test.sock")); - public static void test() throws Exception { - assertTrue(addr instanceof Serializable); + @Test + public void test() throws Exception { + assertInstanceOf(Serializable.class, addr); byte[] serialized = serialize(addr); assertTrue(serialized.length > 0); UnixDomainSocketAddress deserialized = deserialize(serialized, UnixDomainSocketAddress.class); - assertEquals(deserialized.getPath(), addr.getPath()); - assertEquals(deserialized.toString(), addr.toString()); - assertEquals(deserialized.hashCode(), addr.hashCode()); - assertEquals(deserialized, addr); + assertEquals(addr.getPath(), deserialized.getPath()); + assertEquals(addr.toString(), deserialized.toString()); + assertEquals(addr.hashCode(), deserialized.hashCode()); + assertEquals(addr, deserialized); } static final Class IOE = InvalidObjectException.class; static final Class NPE = NullPointerException.class; /** Tests that UnixDomainSocketAddress in the byte-stream is disallowed. */ - public static void testUnixDomainSocketAddressInStream() throws Exception { + @Test + public void testUnixDomainSocketAddressInStream() throws Exception { long suid = ObjectStreamClass.lookup(UnixDomainSocketAddress.class).getSerialVersionUID(); byte[] bytes = byteStreamFor(UnixDomainSocketAddress.class.getName(), suid); - expectThrows(IOE, () -> deserialize(bytes, UnixDomainSocketAddress.class)); + assertThrows(IOE, () -> deserialize(bytes, UnixDomainSocketAddress.class)); } /** Tests that SerialProxy with a null/absent path value in the byte-stream is disallowed. */ - public static void testSerialProxyNoStreamValues() throws Exception { + @Test + public void testSerialProxyNoStreamValues() throws Exception { Class c = Class.forName("java.net.UnixDomainSocketAddress$Ser"); long suid = ObjectStreamClass.lookup(c).getSerialVersionUID(); byte[] bytes = byteStreamFor(c.getName(), suid); - expectThrows(NPE, () -> deserialize(bytes, UnixDomainSocketAddress.class)); + assertThrows(NPE, () -> deserialize(bytes, UnixDomainSocketAddress.class)); } private static byte[] serialize(T t) From 3384c6736daf81aba08e15d6340065517747736e Mon Sep 17 00:00:00 2001 From: Bhavana Kilambi Date: Wed, 15 Apr 2026 12:27:56 +0000 Subject: [PATCH 292/359] 8366444: Add support for add/mul reduction operations for Float16 Reviewed-by: jbhateja, mchevalier, xgong, epeter --- src/hotspot/cpu/aarch64/aarch64_vector.ad | 90 ++++++- src/hotspot/cpu/aarch64/aarch64_vector_ad.m4 | 139 +++++++--- .../cpu/aarch64/c2_MacroAssembler_aarch64.cpp | 49 ++++ .../cpu/aarch64/c2_MacroAssembler_aarch64.hpp | 3 + src/hotspot/share/adlc/formssel.cpp | 8 +- src/hotspot/share/opto/classes.hpp | 2 + src/hotspot/share/opto/compile.cpp | 8 +- src/hotspot/share/opto/vectornode.cpp | 18 +- src/hotspot/share/opto/vectornode.hpp | 69 ++++- .../compiler/lib/ir_framework/IRNode.java | 10 + .../loopopts/superword/TestReductions.java | 141 +++++++++- .../TestFloat16VectorOperations.java | 240 +++++++++++++++++- .../vector/Float16OperationsBenchmark.java | 19 ++ .../bench/vm/compiler/VectorReduction2.java | 93 ++++++- 14 files changed, 820 insertions(+), 69 deletions(-) diff --git a/src/hotspot/cpu/aarch64/aarch64_vector.ad b/src/hotspot/cpu/aarch64/aarch64_vector.ad index 30b0c9c799b..4c854913e63 100644 --- a/src/hotspot/cpu/aarch64/aarch64_vector.ad +++ b/src/hotspot/cpu/aarch64/aarch64_vector.ad @@ -1,6 +1,6 @@ // // Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. -// Copyright (c) 2020, 2025, Arm Limited. All rights reserved. +// Copyright (c) 2020, 2026, Arm Limited. All rights reserved. // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. // // This code is free software; you can redistribute it and/or modify it @@ -247,10 +247,39 @@ source %{ case Op_MinVHF: case Op_MaxVHF: case Op_SqrtVHF: + if (UseSVE == 0 && !is_feat_fp16_supported()) { + return false; + } + break; + // At the time of writing this, the Vector API has no half-float (FP16) species. + // Consequently, AddReductionVHF and MulReductionVHF are only produced by the + // auto-vectorizer, which requires strictly ordered semantics for FP reductions. + // + // There is no direct Neon instruction that performs strictly ordered floating + // point add reduction. Hence, on Neon only machines, the add reduction operation + // is implemented as a scalarized sequence using half-precision scalar instruction + // FADD which requires FEAT_FP16 and ASIMDHP to be available on the target. + // On SVE machines (UseSVE > 0) however, there is a direct instruction (FADDA) which + // implements strictly ordered floating point add reduction which does not require + // the FEAT_FP16 and ASIMDHP checks as SVE supports half-precision floats by default. + case Op_AddReductionVHF: // FEAT_FP16 is enabled if both "fphp" and "asimdhp" features are supported. // Only the Neon instructions need this check. SVE supports half-precision floats // by default. - if (UseSVE == 0 && !is_feat_fp16_supported()) { + if (length_in_bytes < 8 || (UseSVE == 0 && !is_feat_fp16_supported())) { + return false; + } + break; + case Op_MulReductionVHF: + // There are no direct Neon/SVE instructions that perform strictly ordered + // floating point multiply reduction. + // For vector length ≤ 16 bytes, the reduction is implemented as a scalarized + // sequence using half-precision scalar instruction FMUL. This path requires + // FEAT_FP16 and ASIMDHP to be available on the target. + // For vector length > 16 bytes, this operation is disabled because there is no + // direct SVE instruction that performs a strictly ordered FP16 multiply + // reduction. + if (length_in_bytes < 8 || length_in_bytes > 16 || !is_feat_fp16_supported()) { return false; } break; @@ -300,6 +329,7 @@ source %{ case Op_VectorRearrange: case Op_MulReductionVD: case Op_MulReductionVF: + case Op_MulReductionVHF: case Op_MulReductionVI: case Op_MulReductionVL: case Op_CompressBitsV: @@ -364,6 +394,7 @@ source %{ case Op_VectorMaskCmp: case Op_LoadVectorGather: case Op_StoreVectorScatter: + case Op_AddReductionVHF: case Op_AddReductionVF: case Op_AddReductionVD: case Op_AndReductionV: @@ -3402,6 +3433,44 @@ instruct reduce_non_strict_order_add4F_neon(vRegF dst, vRegF fsrc, vReg vsrc, vR ins_pipe(pipe_slow); %} +// Add Reduction for Half floats (FP16). +// Neon does not provide direct instructions for strictly ordered floating-point add reductions. +// On Neon-only targets (UseSVE = 0), this operation is implemented as a sequence of scalar additions: +// values equal to the vector width are loaded into a vector register, each lane is extracted, +// and its value is accumulated into the running sum, producing a final scalar result. +instruct reduce_addHF_neon(vRegF dst, vRegF fsrc, vReg vsrc, vReg tmp) %{ + predicate(UseSVE == 0); + match(Set dst (AddReductionVHF fsrc vsrc)); + effect(TEMP_DEF dst, TEMP tmp); + format %{ "reduce_addHF $dst, $fsrc, $vsrc\t# 4HF/8HF. KILL $tmp" %} + ins_encode %{ + uint length_in_bytes = Matcher::vector_length_in_bytes(this, $vsrc); + __ neon_reduce_add_fp16($dst$$FloatRegister, $fsrc$$FloatRegister, + $vsrc$$FloatRegister, length_in_bytes, $tmp$$FloatRegister); + %} + ins_pipe(pipe_slow); +%} + +// This rule calculates the reduction result in strict order. Two cases will +// reach here: +// 1. Non strictly-ordered AddReductionVHF when vector size > 128-bits. For example - +// AddReductionVHF generated by Vector API. For vector size > 128-bits, it is more +// beneficial performance-wise to generate direct SVE instruction even if it is +// strictly ordered. +// 2. Strictly-ordered AddReductionVHF. For example - AddReductionVHF generated by +// auto-vectorization on SVE machine. +instruct reduce_addHF_sve(vRegF dst_src1, vReg src2) %{ + predicate(UseSVE > 0); + match(Set dst_src1 (AddReductionVHF dst_src1 src2)); + format %{ "reduce_addHF_sve $dst_src1, $dst_src1, $src2" %} + ins_encode %{ + uint length_in_bytes = Matcher::vector_length_in_bytes(this, $src2); + assert(length_in_bytes == MaxVectorSize, "invalid vector length"); + __ sve_fadda($dst_src1$$FloatRegister, __ H, ptrue, $src2$$FloatRegister); + %} + ins_pipe(pipe_slow); +%} + // This rule calculates the reduction result in strict order. Two cases will // reach here: // 1. Non strictly-ordered AddReductionVF when vector size > 128-bits. For example - @@ -3492,12 +3561,14 @@ instruct reduce_addL_masked(iRegLNoSp dst, iRegL isrc, vReg vsrc, pRegGov pg, vR ins_pipe(pipe_slow); %} -instruct reduce_addF_masked(vRegF dst_src1, vReg src2, pRegGov pg) %{ +instruct reduce_addFHF_masked(vRegF dst_src1, vReg src2, pRegGov pg) %{ predicate(UseSVE > 0); + match(Set dst_src1 (AddReductionVHF (Binary dst_src1 src2) pg)); match(Set dst_src1 (AddReductionVF (Binary dst_src1 src2) pg)); - format %{ "reduce_addF_masked $dst_src1, $pg, $dst_src1, $src2" %} + format %{ "reduce_addFHF_masked $dst_src1, $pg, $dst_src1, $src2" %} ins_encode %{ - __ sve_fadda($dst_src1$$FloatRegister, __ S, + BasicType bt = Matcher::vector_element_basic_type(this, $src2); + __ sve_fadda($dst_src1$$FloatRegister, __ elemType_to_regVariant(bt), $pg$$PRegister, $src2$$FloatRegister); %} ins_pipe(pipe_slow); @@ -3545,14 +3616,17 @@ instruct reduce_mulL(iRegLNoSp dst, iRegL isrc, vReg vsrc) %{ ins_pipe(pipe_slow); %} -instruct reduce_mulF(vRegF dst, vRegF fsrc, vReg vsrc, vReg tmp) %{ + +instruct reduce_mulFHF(vRegF dst, vRegF fsrc, vReg vsrc, vReg tmp) %{ predicate(Matcher::vector_length_in_bytes(n->in(2)) <= 16); + match(Set dst (MulReductionVHF fsrc vsrc)); match(Set dst (MulReductionVF fsrc vsrc)); effect(TEMP_DEF dst, TEMP tmp); - format %{ "reduce_mulF $dst, $fsrc, $vsrc\t# 2F/4F. KILL $tmp" %} + format %{ "reduce_mulFHF $dst, $fsrc, $vsrc\t# 2F/4F/4HF/8HF. KILL $tmp" %} ins_encode %{ uint length_in_bytes = Matcher::vector_length_in_bytes(this, $vsrc); - __ neon_reduce_mul_fp($dst$$FloatRegister, T_FLOAT, $fsrc$$FloatRegister, + BasicType bt = Matcher::vector_element_basic_type(this, $vsrc); + __ neon_reduce_mul_fp($dst$$FloatRegister, bt, $fsrc$$FloatRegister, $vsrc$$FloatRegister, length_in_bytes, $tmp$$FloatRegister); %} ins_pipe(pipe_slow); diff --git a/src/hotspot/cpu/aarch64/aarch64_vector_ad.m4 b/src/hotspot/cpu/aarch64/aarch64_vector_ad.m4 index 48bffb3cf35..58ed234194a 100644 --- a/src/hotspot/cpu/aarch64/aarch64_vector_ad.m4 +++ b/src/hotspot/cpu/aarch64/aarch64_vector_ad.m4 @@ -1,6 +1,6 @@ // // Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. -// Copyright (c) 2020, 2025, Arm Limited. All rights reserved. +// Copyright (c) 2020, 2026, Arm Limited. All rights reserved. // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. // // This code is free software; you can redistribute it and/or modify it @@ -237,10 +237,39 @@ source %{ case Op_MinVHF: case Op_MaxVHF: case Op_SqrtVHF: + if (UseSVE == 0 && !is_feat_fp16_supported()) { + return false; + } + break; + // At the time of writing this, the Vector API has no half-float (FP16) species. + // Consequently, AddReductionVHF and MulReductionVHF are only produced by the + // auto-vectorizer, which requires strictly ordered semantics for FP reductions. + // + // There is no direct Neon instruction that performs strictly ordered floating + // point add reduction. Hence, on Neon only machines, the add reduction operation + // is implemented as a scalarized sequence using half-precision scalar instruction + // FADD which requires FEAT_FP16 and ASIMDHP to be available on the target. + // On SVE machines (UseSVE > 0) however, there is a direct instruction (FADDA) which + // implements strictly ordered floating point add reduction which does not require + // the FEAT_FP16 and ASIMDHP checks as SVE supports half-precision floats by default. + case Op_AddReductionVHF: // FEAT_FP16 is enabled if both "fphp" and "asimdhp" features are supported. // Only the Neon instructions need this check. SVE supports half-precision floats // by default. - if (UseSVE == 0 && !is_feat_fp16_supported()) { + if (length_in_bytes < 8 || (UseSVE == 0 && !is_feat_fp16_supported())) { + return false; + } + break; + case Op_MulReductionVHF: + // There are no direct Neon/SVE instructions that perform strictly ordered + // floating point multiply reduction. + // For vector length ≤ 16 bytes, the reduction is implemented as a scalarized + // sequence using half-precision scalar instruction FMUL. This path requires + // FEAT_FP16 and ASIMDHP to be available on the target. + // For vector length > 16 bytes, this operation is disabled because there is no + // direct SVE instruction that performs a strictly ordered FP16 multiply + // reduction. + if (length_in_bytes < 8 || length_in_bytes > 16 || !is_feat_fp16_supported()) { return false; } break; @@ -290,6 +319,7 @@ source %{ case Op_VectorRearrange: case Op_MulReductionVD: case Op_MulReductionVF: + case Op_MulReductionVHF: case Op_MulReductionVI: case Op_MulReductionVL: case Op_CompressBitsV: @@ -354,6 +384,7 @@ source %{ case Op_VectorMaskCmp: case Op_LoadVectorGather: case Op_StoreVectorScatter: + case Op_AddReductionVHF: case Op_AddReductionVF: case Op_AddReductionVD: case Op_AndReductionV: @@ -2063,6 +2094,25 @@ instruct reduce_non_strict_order_add4F_neon(vRegF dst, vRegF fsrc, vReg vsrc, vR ins_pipe(pipe_slow); %} dnl + +// Add Reduction for Half floats (FP16). +// Neon does not provide direct instructions for strictly ordered floating-point add reductions. +// On Neon-only targets (UseSVE = 0), this operation is implemented as a sequence of scalar additions: +// values equal to the vector width are loaded into a vector register, each lane is extracted, +// and its value is accumulated into the running sum, producing a final scalar result. +instruct reduce_addHF_neon(vRegF dst, vRegF fsrc, vReg vsrc, vReg tmp) %{ + predicate(UseSVE == 0); + match(Set dst (AddReductionVHF fsrc vsrc)); + effect(TEMP_DEF dst, TEMP tmp); + format %{ "reduce_addHF $dst, $fsrc, $vsrc\t# 4HF/8HF. KILL $tmp" %} + ins_encode %{ + uint length_in_bytes = Matcher::vector_length_in_bytes(this, $vsrc); + __ neon_reduce_add_fp16($dst$$FloatRegister, $fsrc$$FloatRegister, + $vsrc$$FloatRegister, length_in_bytes, $tmp$$FloatRegister); + %} + ins_pipe(pipe_slow); +%} +dnl dnl REDUCE_ADD_FP_SVE($1, $2 ) dnl REDUCE_ADD_FP_SVE(type, size) define(`REDUCE_ADD_FP_SVE', ` @@ -2074,21 +2124,26 @@ define(`REDUCE_ADD_FP_SVE', ` // strictly ordered. // 2. Strictly-ordered AddReductionV$1. For example - AddReductionV$1 generated by // auto-vectorization on SVE machine. -instruct reduce_add$1_sve(vReg$1 dst_src1, vReg src2) %{ - predicate(!VM_Version::use_neon_for_vector(Matcher::vector_length_in_bytes(n->in(2))) || - n->as_Reduction()->requires_strict_order()); +instruct reduce_add$1_sve(vReg`'ifelse($1, HF, F, $1) dst_src1, vReg src2) %{ + ifelse($1, HF, + `predicate(UseSVE > 0);', + `predicate(!VM_Version::use_neon_for_vector(Matcher::vector_length_in_bytes(n->in(2))) || + n->as_Reduction()->requires_strict_order());') match(Set dst_src1 (AddReductionV$1 dst_src1 src2)); format %{ "reduce_add$1_sve $dst_src1, $dst_src1, $src2" %} ins_encode %{ - assert(UseSVE > 0, "must be sve"); - uint length_in_bytes = Matcher::vector_length_in_bytes(this, $src2); + ifelse($1, HF, `', + `assert(UseSVE > 0, "must be sve"); + ')dnl +uint length_in_bytes = Matcher::vector_length_in_bytes(this, $src2); assert(length_in_bytes == MaxVectorSize, "invalid vector length"); __ sve_fadda($dst_src1$$FloatRegister, __ $2, ptrue, $src2$$FloatRegister); %} ins_pipe(pipe_slow); %}')dnl dnl -REDUCE_ADD_FP_SVE(F, S) +REDUCE_ADD_FP_SVE(HF, H) +REDUCE_ADD_FP_SVE(F, S) // reduction addD @@ -2129,21 +2184,30 @@ dnl dnl REDUCE_ADD_FP_PREDICATE($1, $2 ) dnl REDUCE_ADD_FP_PREDICATE(insn_name, op_name) define(`REDUCE_ADD_FP_PREDICATE', ` -instruct reduce_add$1_masked(vReg$1 dst_src1, vReg src2, pRegGov pg) %{ +instruct reduce_add$1_masked(vReg$2 dst_src1, vReg src2, pRegGov pg) %{ predicate(UseSVE > 0); - match(Set dst_src1 (AddReductionV$1 (Binary dst_src1 src2) pg)); + ifelse($2, F, + `match(Set dst_src1 (AddReductionVHF (Binary dst_src1 src2) pg)); + match(Set dst_src1 (AddReductionV$2 (Binary dst_src1 src2) pg));', + `match(Set dst_src1 (AddReductionV$2 (Binary dst_src1 src2) pg));') format %{ "reduce_add$1_masked $dst_src1, $pg, $dst_src1, $src2" %} ins_encode %{ - __ sve_fadda($dst_src1$$FloatRegister, __ $2, - $pg$$PRegister, $src2$$FloatRegister); + ifelse($2, F, + `BasicType bt = Matcher::vector_element_basic_type(this, $src2); + ',)dnl +ifelse($2, F, + `__ sve_fadda($dst_src1$$FloatRegister, __ elemType_to_regVariant(bt), + $pg$$PRegister, $src2$$FloatRegister);', + `__ sve_fadda($dst_src1$$FloatRegister, __ $2, + $pg$$PRegister, $src2$$FloatRegister);') %} ins_pipe(pipe_slow); %}')dnl dnl REDUCE_ADD_INT_PREDICATE(I, iRegIorL2I) REDUCE_ADD_INT_PREDICATE(L, iRegL) -REDUCE_ADD_FP_PREDICATE(F, S) -REDUCE_ADD_FP_PREDICATE(D, D) +REDUCE_ADD_FP_PREDICATE(FHF, F) +REDUCE_ADD_FP_PREDICATE(D, D) // ------------------------------ Vector reduction mul ------------------------- @@ -2176,30 +2240,37 @@ instruct reduce_mulL(iRegLNoSp dst, iRegL isrc, vReg vsrc) %{ ins_pipe(pipe_slow); %} -instruct reduce_mulF(vRegF dst, vRegF fsrc, vReg vsrc, vReg tmp) %{ - predicate(Matcher::vector_length_in_bytes(n->in(2)) <= 16); - match(Set dst (MulReductionVF fsrc vsrc)); +dnl REDUCE_MUL_FP($1, $2 ) +dnl REDUCE_MUL_FP(insn_name, op_name) +define(`REDUCE_MUL_FP', ` +instruct reduce_mul$1(vReg$2 dst, vReg$2 ifelse($2, F, fsrc, dsrc), vReg vsrc, vReg tmp) %{ + predicate(Matcher::vector_length_in_bytes(n->in(2)) ifelse($2, F, <=, ==) 16); + ifelse($2, F, + `match(Set dst (MulReductionVHF fsrc vsrc)); + match(Set dst (MulReductionV$2 fsrc vsrc));', + `match(Set dst (MulReductionV$2 dsrc vsrc));') effect(TEMP_DEF dst, TEMP tmp); - format %{ "reduce_mulF $dst, $fsrc, $vsrc\t# 2F/4F. KILL $tmp" %} + ifelse($2, F, + `format %{ "reduce_mul$1 $dst, $fsrc, $vsrc\t# 2F/4F/4HF/8HF. KILL $tmp" %}', + `format %{ "reduce_mul$1 $dst, $dsrc, $vsrc\t# 2D. KILL $tmp" %}') ins_encode %{ - uint length_in_bytes = Matcher::vector_length_in_bytes(this, $vsrc); - __ neon_reduce_mul_fp($dst$$FloatRegister, T_FLOAT, $fsrc$$FloatRegister, - $vsrc$$FloatRegister, length_in_bytes, $tmp$$FloatRegister); + ifelse($2, F, + `uint length_in_bytes = Matcher::vector_length_in_bytes(this, $vsrc); + ',)dnl +ifelse($2, F, + `BasicType bt = Matcher::vector_element_basic_type(this, $vsrc); + ',)dnl +ifelse($2, F, + `__ neon_reduce_mul_fp($dst$$FloatRegister, bt, $fsrc$$FloatRegister, + $vsrc$$FloatRegister, length_in_bytes, $tmp$$FloatRegister);', + `__ neon_reduce_mul_fp($dst$$FloatRegister, T_DOUBLE, $dsrc$$FloatRegister, + $vsrc$$FloatRegister, 16, $tmp$$FloatRegister);') %} ins_pipe(pipe_slow); -%} - -instruct reduce_mulD(vRegD dst, vRegD dsrc, vReg vsrc, vReg tmp) %{ - predicate(Matcher::vector_length_in_bytes(n->in(2)) == 16); - match(Set dst (MulReductionVD dsrc vsrc)); - effect(TEMP_DEF dst, TEMP tmp); - format %{ "reduce_mulD $dst, $dsrc, $vsrc\t# 2D. KILL $tmp" %} - ins_encode %{ - __ neon_reduce_mul_fp($dst$$FloatRegister, T_DOUBLE, $dsrc$$FloatRegister, - $vsrc$$FloatRegister, 16, $tmp$$FloatRegister); - %} - ins_pipe(pipe_slow); -%} +%}')dnl +dnl +REDUCE_MUL_FP(FHF, F) +REDUCE_MUL_FP(D, D) dnl dnl REDUCE_BITWISE_OP_NEON($1, $2 $3 $4 ) diff --git a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp index bba37a7a390..3c179f21c14 100644 --- a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. + * Copyright 2026 Arm Limited 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 @@ -1883,6 +1884,27 @@ void C2_MacroAssembler::neon_reduce_mul_fp(FloatRegister dst, BasicType bt, BLOCK_COMMENT("neon_reduce_mul_fp {"); switch(bt) { + // The T_SHORT type below is for Float16 type which also uses floating-point + // instructions. + case T_SHORT: + fmulh(dst, fsrc, vsrc); + ext(vtmp, T8B, vsrc, vsrc, 2); + fmulh(dst, dst, vtmp); + ext(vtmp, T8B, vsrc, vsrc, 4); + fmulh(dst, dst, vtmp); + ext(vtmp, T8B, vsrc, vsrc, 6); + fmulh(dst, dst, vtmp); + if (isQ) { + ext(vtmp, T16B, vsrc, vsrc, 8); + fmulh(dst, dst, vtmp); + ext(vtmp, T16B, vsrc, vsrc, 10); + fmulh(dst, dst, vtmp); + ext(vtmp, T16B, vsrc, vsrc, 12); + fmulh(dst, dst, vtmp); + ext(vtmp, T16B, vsrc, vsrc, 14); + fmulh(dst, dst, vtmp); + } + break; case T_FLOAT: fmuls(dst, fsrc, vsrc); ins(vtmp, S, vsrc, 0, 1); @@ -1907,6 +1929,33 @@ void C2_MacroAssembler::neon_reduce_mul_fp(FloatRegister dst, BasicType bt, BLOCK_COMMENT("} neon_reduce_mul_fp"); } +// Vector reduction add for half float type with ASIMD instructions. +void C2_MacroAssembler::neon_reduce_add_fp16(FloatRegister dst, FloatRegister fsrc, FloatRegister vsrc, + unsigned vector_length_in_bytes, FloatRegister vtmp) { + assert(vector_length_in_bytes == 8 || vector_length_in_bytes == 16, "unsupported"); + bool isQ = vector_length_in_bytes == 16; + + BLOCK_COMMENT("neon_reduce_add_fp16 {"); + faddh(dst, fsrc, vsrc); + ext(vtmp, T8B, vsrc, vsrc, 2); + faddh(dst, dst, vtmp); + ext(vtmp, T8B, vsrc, vsrc, 4); + faddh(dst, dst, vtmp); + ext(vtmp, T8B, vsrc, vsrc, 6); + faddh(dst, dst, vtmp); + if (isQ) { + ext(vtmp, T16B, vsrc, vsrc, 8); + faddh(dst, dst, vtmp); + ext(vtmp, T16B, vsrc, vsrc, 10); + faddh(dst, dst, vtmp); + ext(vtmp, T16B, vsrc, vsrc, 12); + faddh(dst, dst, vtmp); + ext(vtmp, T16B, vsrc, vsrc, 14); + faddh(dst, dst, vtmp); + } + BLOCK_COMMENT("} neon_reduce_add_fp16"); +} + // Helper to select logical instruction void C2_MacroAssembler::neon_reduce_logical_helper(int opc, bool is64, Register Rd, Register Rn, Register Rm, diff --git a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp index 5964bb60d4f..f96d3ffb863 100644 --- a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp @@ -177,6 +177,9 @@ FloatRegister fsrc, FloatRegister vsrc, unsigned vector_length_in_bytes, FloatRegister vtmp); + void neon_reduce_add_fp16(FloatRegister dst, FloatRegister fsrc, FloatRegister vsrc, + unsigned vector_length_in_bytes, FloatRegister vtmp); + void neon_reduce_logical(int opc, Register dst, BasicType bt, Register isrc, FloatRegister vsrc, unsigned vector_length_in_bytes); diff --git a/src/hotspot/share/adlc/formssel.cpp b/src/hotspot/share/adlc/formssel.cpp index 4dd2bff7c89..5802217c1c1 100644 --- a/src/hotspot/share/adlc/formssel.cpp +++ b/src/hotspot/share/adlc/formssel.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -4233,11 +4233,13 @@ int MatchRule::is_expensive() const { strcmp(opType,"PopulateIndex")==0 || strcmp(opType,"AddReductionVI")==0 || strcmp(opType,"AddReductionVL")==0 || + strcmp(opType,"AddReductionVHF")==0 || strcmp(opType,"AddReductionVF")==0 || strcmp(opType,"AddReductionVD")==0 || strcmp(opType,"MulReductionVI")==0 || strcmp(opType,"MulReductionVL")==0 || strcmp(opType,"MulReductionVF")==0 || + strcmp(opType,"MulReductionVHF")==0 || strcmp(opType,"MulReductionVD")==0 || strcmp(opType,"MinReductionV")==0 || strcmp(opType,"MaxReductionV")==0 || @@ -4348,9 +4350,9 @@ bool MatchRule::is_vector() const { "MaxV", "MinV", "MinVHF", "MaxVHF", "UMinV", "UMaxV", "CompressV", "ExpandV", "CompressM", "CompressBitsV", "ExpandBitsV", "AddReductionVI", "AddReductionVL", - "AddReductionVF", "AddReductionVD", + "AddReductionVHF", "AddReductionVF", "AddReductionVD", "MulReductionVI", "MulReductionVL", - "MulReductionVF", "MulReductionVD", + "MulReductionVHF", "MulReductionVF", "MulReductionVD", "MaxReductionV", "MinReductionV", "AndReductionV", "OrReductionV", "XorReductionV", "MulAddVS2VI", "MacroLogicV", diff --git a/src/hotspot/share/opto/classes.hpp b/src/hotspot/share/opto/classes.hpp index 3c1a68d6224..0f67cf90183 100644 --- a/src/hotspot/share/opto/classes.hpp +++ b/src/hotspot/share/opto/classes.hpp @@ -396,6 +396,7 @@ macro(AddVL) macro(AddReductionVL) macro(AddVF) macro(AddVHF) +macro(AddReductionVHF) macro(AddReductionVF) macro(AddVD) macro(AddReductionVD) @@ -413,6 +414,7 @@ macro(MulReductionVI) macro(MulVL) macro(MulReductionVL) macro(MulVF) +macro(MulReductionVHF) macro(MulReductionVF) macro(MulVD) macro(MulReductionVD) diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index db3cbd4109c..e05df8ea716 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -3200,10 +3200,10 @@ void Compile::final_graph_reshaping_impl(Node *n, Final_Reshape_Counts& frc, Uni !n->in(2)->is_Con() ) { // right use is not a constant // Check for commutative opcode switch( nop ) { - case Op_AddI: case Op_AddF: case Op_AddD: case Op_AddL: + case Op_AddI: case Op_AddF: case Op_AddD: case Op_AddHF: case Op_AddL: case Op_MaxI: case Op_MaxL: case Op_MaxF: case Op_MaxD: case Op_MinI: case Op_MinL: case Op_MinF: case Op_MinD: - case Op_MulI: case Op_MulF: case Op_MulD: case Op_MulL: + case Op_MulI: case Op_MulF: case Op_MulD: case Op_MulHF: case Op_MulL: case Op_AndL: case Op_XorL: case Op_OrL: case Op_AndI: case Op_XorI: case Op_OrI: { // Move "last use" input to left by swapping inputs @@ -3282,6 +3282,8 @@ void Compile::handle_div_mod_op(Node* n, BasicType bt, bool is_unsigned) { void Compile::final_graph_reshaping_main_switch(Node* n, Final_Reshape_Counts& frc, uint nop, Unique_Node_List& dead_nodes) { switch( nop ) { // Count all float operations that may use FPU + case Op_AddHF: + case Op_MulHF: case Op_AddF: case Op_SubF: case Op_MulF: @@ -3788,10 +3790,12 @@ void Compile::final_graph_reshaping_main_switch(Node* n, Final_Reshape_Counts& f case Op_AddReductionVI: case Op_AddReductionVL: + case Op_AddReductionVHF: case Op_AddReductionVF: case Op_AddReductionVD: case Op_MulReductionVI: case Op_MulReductionVL: + case Op_MulReductionVHF: case Op_MulReductionVF: case Op_MulReductionVD: case Op_MinReductionV: diff --git a/src/hotspot/share/opto/vectornode.cpp b/src/hotspot/share/opto/vectornode.cpp index dbadc18da01..d19aa476196 100644 --- a/src/hotspot/share/opto/vectornode.cpp +++ b/src/hotspot/share/opto/vectornode.cpp @@ -1260,6 +1260,10 @@ int ReductionNode::opcode(int opc, BasicType bt) { assert(bt == T_LONG, "must be"); vopc = Op_AddReductionVL; break; + case Op_AddHF: + assert(bt == T_SHORT, "must be"); + vopc = Op_AddReductionVHF; + break; case Op_AddF: assert(bt == T_FLOAT, "must be"); vopc = Op_AddReductionVF; @@ -1284,6 +1288,10 @@ int ReductionNode::opcode(int opc, BasicType bt) { assert(bt == T_LONG, "must be"); vopc = Op_MulReductionVL; break; + case Op_MulHF: + assert(bt == T_SHORT, "must be"); + vopc = Op_MulReductionVHF; + break; case Op_MulF: assert(bt == T_FLOAT, "must be"); vopc = Op_MulReductionVF; @@ -1432,10 +1440,12 @@ ReductionNode* ReductionNode::make(int opc, Node* ctrl, Node* n1, Node* n2, Basi switch (vopc) { case Op_AddReductionVI: return new AddReductionVINode(ctrl, n1, n2); case Op_AddReductionVL: return new AddReductionVLNode(ctrl, n1, n2); + case Op_AddReductionVHF: return new AddReductionVHFNode(ctrl, n1, n2, requires_strict_order); case Op_AddReductionVF: return new AddReductionVFNode(ctrl, n1, n2, requires_strict_order); case Op_AddReductionVD: return new AddReductionVDNode(ctrl, n1, n2, requires_strict_order); case Op_MulReductionVI: return new MulReductionVINode(ctrl, n1, n2); case Op_MulReductionVL: return new MulReductionVLNode(ctrl, n1, n2); + case Op_MulReductionVHF: return new MulReductionVHFNode(ctrl, n1, n2, requires_strict_order); case Op_MulReductionVF: return new MulReductionVFNode(ctrl, n1, n2, requires_strict_order); case Op_MulReductionVD: return new MulReductionVDNode(ctrl, n1, n2, requires_strict_order); case Op_MinReductionV: return new MinReductionVNode (ctrl, n1, n2); @@ -1613,6 +1623,8 @@ Node* ReductionNode::make_identity_con_scalar(PhaseGVN& gvn, int sopc, BasicType return nullptr; } break; + case Op_AddReductionVHF: + return gvn.makecon(TypeH::ZERO); case Op_AddReductionVI: // fallthrough case Op_AddReductionVL: // fallthrough case Op_AddReductionVF: // fallthrough @@ -1624,6 +1636,8 @@ Node* ReductionNode::make_identity_con_scalar(PhaseGVN& gvn, int sopc, BasicType return gvn.makecon(TypeInt::ONE); case Op_MulReductionVL: return gvn.makecon(TypeLong::ONE); + case Op_MulReductionVHF: + return gvn.makecon(TypeH::ONE); case Op_MulReductionVF: return gvn.makecon(TypeF::ONE); case Op_MulReductionVD: @@ -1716,12 +1730,14 @@ bool ReductionNode::auto_vectorization_requires_strict_order(int vopc) { // These are cases that all have associative operations, which can // thus be reordered, allowing non-strict order reductions. return false; + case Op_AddReductionVHF: + case Op_MulReductionVHF: case Op_AddReductionVF: case Op_MulReductionVF: case Op_AddReductionVD: case Op_MulReductionVD: // Floating-point addition and multiplication are non-associative, - // so AddReductionVF/D and MulReductionVF/D require strict ordering + // so AddReductionVHF/VF/VD and MulReductionVHF/VF/VD require strict ordering // in auto-vectorization. return true; default: diff --git a/src/hotspot/share/opto/vectornode.hpp b/src/hotspot/share/opto/vectornode.hpp index de866898302..91cff9fcae8 100644 --- a/src/hotspot/share/opto/vectornode.hpp +++ b/src/hotspot/share/opto/vectornode.hpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. + * Copyright 2026 Arm Limited 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 @@ -322,7 +323,7 @@ class ReductionNode : public Node { virtual uint size_of() const { return sizeof(*this); } // Floating-point addition and multiplication are non-associative, so - // AddReductionVF/D and MulReductionVF/D require strict ordering + // AddReductionVHF/F/D and MulReductionVHF/F/D require strict ordering // in auto-vectorization. Vector API can generate AddReductionVF/D // and MulReductionVF/VD without strict ordering, which can benefit // some platforms. @@ -359,6 +360,35 @@ public: virtual int Opcode() const; }; +// Vector add half float as a reduction +class AddReductionVHFNode : public ReductionNode { +private: + // True if add reduction operation for half floats requires strict ordering. + // As an example - The value is true when add reduction for half floats is auto-vectorized + // as auto-vectorization mandates strict ordering but the value is false when this node + // is generated through VectorAPI as VectorAPI does not impose any such rules on ordering. + const bool _requires_strict_order; + +public: + // _requires_strict_order is set to true by default as mandated by auto-vectorization + AddReductionVHFNode(Node* ctrl, Node* in1, Node* in2, bool requires_strict_order = true) : + ReductionNode(ctrl, in1, in2), _requires_strict_order(requires_strict_order) {} + + int Opcode() const override; + bool requires_strict_order() const override { return _requires_strict_order; } + + uint hash() const override { return Node::hash() + _requires_strict_order; } + + bool cmp(const Node& n) const override { + return Node::cmp(n) && _requires_strict_order == ((ReductionNode&)n).requires_strict_order(); + } + + uint size_of() const override { return sizeof(*this); } + + const Type* bottom_type() const override { return Type::HALF_FLOAT; } + uint ideal_reg() const override { return Op_RegF; } +}; + // Vector add float as a reduction class AddReductionVFNode : public ReductionNode { private: @@ -368,7 +398,7 @@ private: // is generated through VectorAPI as VectorAPI does not impose any such rules on ordering. const bool _requires_strict_order; public: - //_requires_strict_order is set to true by default as mandated by auto-vectorization + // _requires_strict_order is set to true by default as mandated by auto-vectorization AddReductionVFNode(Node* ctrl, Node* in1, Node* in2, bool requires_strict_order = true) : ReductionNode(ctrl, in1, in2), _requires_strict_order(requires_strict_order) {} @@ -394,7 +424,7 @@ private: // is generated through VectorAPI as VectorAPI does not impose any such rules on ordering. const bool _requires_strict_order; public: - //_requires_strict_order is set to true by default as mandated by auto-vectorization + // _requires_strict_order is set to true by default as mandated by auto-vectorization AddReductionVDNode(Node* ctrl, Node* in1, Node* in2, bool requires_strict_order = true) : ReductionNode(ctrl, in1, in2), _requires_strict_order(requires_strict_order) {} @@ -578,6 +608,35 @@ public: virtual int Opcode() const; }; +// Vector multiply half float as a reduction +class MulReductionVHFNode : public ReductionNode { +private: + // True if mul reduction operation for half floats requires strict ordering. + // As an example - The value is true when mul reduction for half floats is auto-vectorized + // as auto-vectorization mandates strict ordering but the value is false when this node + // is generated through VectorAPI as VectorAPI does not impose any such rules on ordering. + const bool _requires_strict_order; + +public: + // _requires_strict_order is set to true by default as mandated by auto-vectorization + MulReductionVHFNode(Node* ctrl, Node* in1, Node* in2, bool requires_strict_order = true) : + ReductionNode(ctrl, in1, in2), _requires_strict_order(requires_strict_order) {} + + int Opcode() const override; + bool requires_strict_order() const override { return _requires_strict_order; } + + uint hash() const override { return Node::hash() + _requires_strict_order; } + + bool cmp(const Node& n) const override { + return Node::cmp(n) && _requires_strict_order == ((ReductionNode&)n).requires_strict_order(); + } + + uint size_of() const override { return sizeof(*this); } + + const Type* bottom_type() const override { return Type::HALF_FLOAT; } + uint ideal_reg() const override { return Op_RegF; } +}; + // Vector multiply float as a reduction class MulReductionVFNode : public ReductionNode { // True if mul reduction operation for floats requires strict ordering. @@ -586,7 +645,7 @@ class MulReductionVFNode : public ReductionNode { // is generated through VectorAPI as VectorAPI does not impose any such rules on ordering. const bool _requires_strict_order; public: - //_requires_strict_order is set to true by default as mandated by auto-vectorization + // _requires_strict_order is set to true by default as mandated by auto-vectorization MulReductionVFNode(Node* ctrl, Node* in1, Node* in2, bool requires_strict_order = true) : ReductionNode(ctrl, in1, in2), _requires_strict_order(requires_strict_order) {} @@ -611,7 +670,7 @@ class MulReductionVDNode : public ReductionNode { // is generated through VectorAPI as VectorAPI does not impose any such rules on ordering. const bool _requires_strict_order; public: - //_requires_strict_order is set to true by default as mandated by auto-vectorization + // _requires_strict_order is set to true by default as mandated by auto-vectorization MulReductionVDNode(Node* ctrl, Node* in1, Node* in2, bool requires_strict_order = true) : ReductionNode(ctrl, in1, in2), _requires_strict_order(requires_strict_order) {} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java index f3fc4afb170..55d591acdb3 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java @@ -323,6 +323,11 @@ public class IRNode { superWordNodes(ADD_REDUCTION_VF, "AddReductionVF"); } + public static final String ADD_REDUCTION_VHF = PREFIX + "ADD_REDUCTION_VHF" + POSTFIX; + static { + superWordNodes(ADD_REDUCTION_VHF, "AddReductionVHF"); + } + public static final String ADD_REDUCTION_VI = PREFIX + "ADD_REDUCTION_VI" + POSTFIX; static { superWordNodes(ADD_REDUCTION_VI, "AddReductionVI"); @@ -1576,6 +1581,11 @@ public class IRNode { superWordNodes(MUL_REDUCTION_VF, "MulReductionVF"); } + public static final String MUL_REDUCTION_VHF = PREFIX + "MUL_REDUCTION_VHF" + POSTFIX; + static { + superWordNodes(MUL_REDUCTION_VHF, "MulReductionVHF"); + } + public static final String MUL_REDUCTION_VI = PREFIX + "MUL_REDUCTION_VI" + POSTFIX; static { superWordNodes(MUL_REDUCTION_VI, "MulReductionVI"); diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestReductions.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestReductions.java index 5c085e6a3a3..97a55ae2074 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/TestReductions.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestReductions.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. + * Copyright 2026 Arm Limited 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 @@ -25,6 +26,7 @@ * @test id=no-vectorization * @bug 8340093 8342095 * @summary Test vectorization of reduction loops. + * @modules jdk.incubator.vector * @library /test/lib / * @run driver compiler.loopopts.superword.TestReductions P0 */ @@ -33,6 +35,7 @@ * @test id=vanilla * @bug 8340093 8342095 * @summary Test vectorization of reduction loops. + * @modules jdk.incubator.vector * @library /test/lib / * @run driver compiler.loopopts.superword.TestReductions P1 */ @@ -41,6 +44,7 @@ * @test id=force-vectorization * @bug 8340093 8342095 * @summary Test vectorization of reduction loops. + * @modules jdk.incubator.vector * @library /test/lib / * @run driver compiler.loopopts.superword.TestReductions P2 */ @@ -50,10 +54,14 @@ package compiler.loopopts.superword; import java.util.Map; import java.util.HashMap; +import jdk.incubator.vector.Float16; + import compiler.lib.ir_framework.*; import compiler.lib.verify.*; import static compiler.lib.generators.Generators.G; import compiler.lib.generators.Generator; +import static java.lang.Float.floatToFloat16; +import static jdk.incubator.vector.Float16.*; /** * Note: there is a corresponding JMH benchmark: @@ -65,6 +73,7 @@ public class TestReductions { private static final Generator GEN_L = G.longs(); private static final Generator GEN_F = G.floats(); private static final Generator GEN_D = G.doubles(); + private static final Generator GEN_F16 = G.float16s(); private static byte[] in1B = fillRandom(new byte[SIZE]); private static byte[] in2B = fillRandom(new byte[SIZE]); @@ -89,6 +98,9 @@ public class TestReductions { private static double[] in1D = fillRandom(new double[SIZE]); private static double[] in2D = fillRandom(new double[SIZE]); private static double[] in3D = fillRandom(new double[SIZE]); + private static short[] in1F16 = fillRandomFloat16(new short[SIZE]); + private static short[] in2F16 = fillRandomFloat16(new short[SIZE]); + private static short[] in3F16 = fillRandomFloat16(new short[SIZE]); interface TestFunction { Object run(); @@ -102,6 +114,7 @@ public class TestReductions { public static void main(String[] args) { TestFramework framework = new TestFramework(TestReductions.class); + framework.addFlags("--add-modules=jdk.incubator.vector"); switch (args[0]) { case "P0" -> { framework.addFlags("-XX:+UnlockDiagnosticVMOptions", "-XX:AutoVectorizationOverrideProfitability=0"); } case "P1" -> { framework.addFlags("-XX:+UnlockDiagnosticVMOptions", "-XX:AutoVectorizationOverrideProfitability=1"); } @@ -250,6 +263,13 @@ public class TestReductions { tests.put("doubleMinBig", TestReductions::doubleMinBig); tests.put("doubleMaxBig", TestReductions::doubleMaxBig); + tests.put("float16AddSimple", TestReductions::float16AddSimple); + tests.put("float16MulSimple", TestReductions::float16MulSimple); + tests.put("float16AddDotProduct", TestReductions::float16AddDotProduct); + tests.put("float16MulDotProduct", TestReductions::float16MulDotProduct); + tests.put("float16AddBig", TestReductions::float16AddBig); + tests.put("float16MulBig", TestReductions::float16MulBig); + // Compute gold value for all test methods before compilation for (Map.Entry entry : tests.entrySet()) { String name = entry.getKey(); @@ -394,7 +414,14 @@ public class TestReductions { "doubleAddBig", "doubleMulBig", "doubleMinBig", - "doubleMaxBig"}) + "doubleMaxBig", + + "float16AddSimple", + "float16MulSimple", + "float16AddDotProduct", + "float16MulDotProduct", + "float16AddBig", + "float16MulBig"}) public void runTests() { for (Map.Entry entry : tests.entrySet()) { String name = entry.getKey(); @@ -453,6 +480,13 @@ public class TestReductions { return a; } + static short[] fillRandomFloat16(short[] a) { + for (int i = 0; i < a.length; i++) { + a[i] = GEN_F16.next(); + } + return a; + } + // ---------byte***Simple ------------------------------------------------------------ @Test @IR(counts = {IRNode.LOAD_VECTOR_B, IRNode.VECTOR_SIZE + "min(max_int, max_byte)", "> 0", @@ -2628,5 +2662,110 @@ public class TestReductions { return acc; } + // ---------float16***Simple ------------------------------------------------------------ + @Test + @IR(counts = {IRNode.ADD_REDUCTION_VHF, "> 0"}, + applyIfCPUFeature = {"sve", "true"}, + applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) + @IR(counts = {IRNode.ADD_REDUCTION_VHF, "> 0"}, + applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}, + applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) + @IR(failOn = IRNode.ADD_REDUCTION_VHF, + applyIf = {"AutoVectorizationOverrideProfitability", "= 0"}) + private static Float16 float16AddSimple() { + short acc = (short)0; // neutral element + for (int i = 0; i < SIZE; i++) { + acc = float16ToRawShortBits(add(shortBitsToFloat16(acc), shortBitsToFloat16(in1F16[i]))); + } + return shortBitsToFloat16(acc); + } + + @Test + @IR(counts = {IRNode.MUL_REDUCTION_VHF, "> 0"}, + applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}, + applyIfAnd = {"AutoVectorizationOverrideProfitability", "> 0", "MaxVectorSize", "<=16"}) + @IR(failOn = IRNode.MUL_REDUCTION_VHF, + applyIf = {"AutoVectorizationOverrideProfitability", "= 0"}) + private static Float16 float16MulSimple() { + short acc = floatToFloat16(1.0f); // neutral element + for (int i = 0; i < SIZE; i++) { + acc = float16ToRawShortBits(multiply(shortBitsToFloat16(acc), shortBitsToFloat16(in1F16[i]))); + } + return shortBitsToFloat16(acc); + } + + // ---------float16***DotProduct ------------------------------------------------------------ + @Test + @IR(counts = {IRNode.ADD_REDUCTION_VHF, "> 0"}, + applyIfCPUFeature = {"sve", "true"}, + applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) + @IR(counts = {IRNode.ADD_REDUCTION_VHF, "> 0"}, + applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}, + applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) + @IR(failOn = IRNode.ADD_REDUCTION_VHF, + applyIf = {"AutoVectorizationOverrideProfitability", "= 0"}) + private static Float16 float16AddDotProduct() { + short acc = (short)0; // neutral element + for (int i = 0; i < SIZE; i++) { + Float16 val = multiply(shortBitsToFloat16(in1F16[i]), shortBitsToFloat16(in2F16[i])); + acc = float16ToRawShortBits(add(shortBitsToFloat16(acc), val)); + } + return shortBitsToFloat16(acc); + } + + @Test + @IR(counts = {IRNode.MUL_REDUCTION_VHF, "> 0"}, + applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}, + applyIfAnd = {"AutoVectorizationOverrideProfitability", "> 0", "MaxVectorSize", "<=16"}) + @IR(failOn = IRNode.MUL_REDUCTION_VHF, + applyIf = {"AutoVectorizationOverrideProfitability", "= 0"}) + private static Float16 float16MulDotProduct() { + short acc = floatToFloat16(1.0f); // neutral element + for (int i = 0; i < SIZE; i++) { + Float16 val = multiply(shortBitsToFloat16(in1F16[i]), shortBitsToFloat16(in2F16[i])); + acc = float16ToRawShortBits(multiply(shortBitsToFloat16(acc), val)); + } + return shortBitsToFloat16(acc); + } + + // ---------float16***Big ------------------------------------------------------------ + @Test + @IR(counts = {IRNode.ADD_REDUCTION_VHF, "> 0"}, + applyIfCPUFeature = {"sve", "true"}, + applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) + @IR(counts = {IRNode.ADD_REDUCTION_VHF, "> 0"}, + applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}, + applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) + @IR(failOn = IRNode.ADD_REDUCTION_VHF, + applyIf = {"AutoVectorizationOverrideProfitability", "= 0"}) + private static Float16 float16AddBig() { + short acc = (short)0; // neutral element + for (int i = 0; i < SIZE; i++) { + Float16 a = shortBitsToFloat16(in1F16[i]); + Float16 b = shortBitsToFloat16(in2F16[i]); + Float16 c = shortBitsToFloat16(in3F16[i]); + Float16 val = add(multiply(a, b), add(multiply(a, c), multiply(b, c))); + acc = float16ToRawShortBits(add(shortBitsToFloat16(acc), val)); + } + return shortBitsToFloat16(acc); + } + + @Test + @IR(counts = {IRNode.MUL_REDUCTION_VHF, "> 0"}, + applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}, + applyIfAnd = {"AutoVectorizationOverrideProfitability", "> 0", "MaxVectorSize", "<=16"}) + @IR(failOn = IRNode.MUL_REDUCTION_VHF, + applyIf = {"AutoVectorizationOverrideProfitability", "= 0"}) + private static Float16 float16MulBig() { + short acc = floatToFloat16(1.0f); // neutral element + for (int i = 0; i < SIZE; i++) { + Float16 a = shortBitsToFloat16(in1F16[i]); + Float16 b = shortBitsToFloat16(in2F16[i]); + Float16 c = shortBitsToFloat16(in3F16[i]); + Float16 val = add(multiply(a, b), add(multiply(a, c), multiply(b, c))); + acc = float16ToRawShortBits(multiply(shortBitsToFloat16(acc), val)); + } + return shortBitsToFloat16(acc); + } } diff --git a/test/hotspot/jtreg/compiler/vectorization/TestFloat16VectorOperations.java b/test/hotspot/jtreg/compiler/vectorization/TestFloat16VectorOperations.java index f3c27c4d278..929a70f304a 100644 --- a/test/hotspot/jtreg/compiler/vectorization/TestFloat16VectorOperations.java +++ b/test/hotspot/jtreg/compiler/vectorization/TestFloat16VectorOperations.java @@ -1,6 +1,6 @@ /* * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2025, Arm Limited. All rights reserved. + * Copyright 2025, 2026 Arm Limited 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 @@ -33,19 +33,21 @@ */ package compiler.vectorization; -import compiler.lib.ir_framework.*; -import jdk.incubator.vector.Float16; -import static jdk.incubator.vector.Float16.*; -import static java.lang.Float.*; -import java.util.Arrays; -import jdk.test.lib.*; import compiler.lib.generators.Generator; +import compiler.lib.ir_framework.*; +import compiler.lib.verify.Verify; +import java.util.Arrays; +import jdk.incubator.vector.Float16; +import jdk.test.lib.*; import static compiler.lib.generators.Generators.G; +import static java.lang.Float.*; +import static jdk.incubator.vector.Float16.*; public class TestFloat16VectorOperations { private short[] input1; private short[] input2; private short[] input3; + private Float16[] input4; private short[] output; private static short FP16_SCALAR = (short)0x7777; private static final int LEN = 2048; @@ -77,6 +79,7 @@ public class TestFloat16VectorOperations { input1 = new short[LEN]; input2 = new short[LEN]; input3 = new short[LEN]; + input4 = new Float16[LEN]; output = new short[LEN]; short min_value = float16ToRawShortBits(Float16.MIN_VALUE); @@ -86,6 +89,7 @@ public class TestFloat16VectorOperations { input1[i] = gen.next(); input2[i] = gen.next(); input3[i] = gen.next(); + input4[i] = shortBitsToFloat16(gen.next()); } } @@ -349,7 +353,9 @@ public class TestFloat16VectorOperations { @Test @Warmup(50) @IR(counts = {IRNode.SUB_VHF, " >0 "}, - applyIfCPUFeature = {"avx512_fp16", "true"}) + applyIfCPUFeatureOr = {"avx512_fp16", "true", "sve", "true"}) + @IR(counts = {IRNode.SUB_VHF, " >0 "}, + applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}) public void vectorSubConstInputFloat16() { for (int i = 0; i < LEN; ++i) { output[i] = float16ToRawShortBits(subtract(shortBitsToFloat16(input1[i]), FP16_CONST)); @@ -367,7 +373,9 @@ public class TestFloat16VectorOperations { @Test @Warmup(50) @IR(counts = {IRNode.MUL_VHF, " >0 "}, - applyIfCPUFeature = {"avx512_fp16", "true"}) + applyIfCPUFeatureOr = {"avx512_fp16", "true", "sve", "true"}) + @IR(counts = {IRNode.MUL_VHF, " >0 "}, + applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}) public void vectorMulConstantInputFloat16() { for (int i = 0; i < LEN; ++i) { output[i] = float16ToRawShortBits(multiply(FP16_CONST, shortBitsToFloat16(input2[i]))); @@ -385,7 +393,9 @@ public class TestFloat16VectorOperations { @Test @Warmup(50) @IR(counts = {IRNode.DIV_VHF, " >0 "}, - applyIfCPUFeature = {"avx512_fp16", "true"}) + applyIfCPUFeatureOr = {"avx512_fp16", "true", "sve", "true"}) + @IR(counts = {IRNode.DIV_VHF, " >0 "}, + applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}) public void vectorDivConstantInputFloat16() { for (int i = 0; i < LEN; ++i) { output[i] = float16ToRawShortBits(divide(FP16_CONST, shortBitsToFloat16(input2[i]))); @@ -403,7 +413,9 @@ public class TestFloat16VectorOperations { @Test @Warmup(50) @IR(counts = {IRNode.MAX_VHF, " >0 "}, - applyIfCPUFeature = {"avx512_fp16", "true"}) + applyIfCPUFeatureOr = {"avx512_fp16", "true", "sve", "true"}) + @IR(counts = {IRNode.MAX_VHF, " >0 "}, + applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}) public void vectorMaxConstantInputFloat16() { for (int i = 0; i < LEN; ++i) { output[i] = float16ToRawShortBits(max(FP16_CONST, shortBitsToFloat16(input2[i]))); @@ -421,7 +433,9 @@ public class TestFloat16VectorOperations { @Test @Warmup(50) @IR(counts = {IRNode.MIN_VHF, " >0 "}, - applyIfCPUFeature = {"avx512_fp16", "true"}) + applyIfCPUFeatureOr = {"avx512_fp16", "true", "sve", "true"}) + @IR(counts = {IRNode.MIN_VHF, " >0 "}, + applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}) public void vectorMinConstantInputFloat16() { for (int i = 0; i < LEN; ++i) { output[i] = float16ToRawShortBits(min(FP16_CONST, shortBitsToFloat16(input2[i]))); @@ -435,4 +449,206 @@ public class TestFloat16VectorOperations { assertResults(2, float16ToRawShortBits(FP16_CONST), input2[i], expected, output[i]); } } + + @Test + @Warmup(50) + @IR(counts = {IRNode.ADD_REDUCTION_VHF, " >0 "}, + applyIfCPUFeature = {"sve", "true"}) + @IR(counts = {IRNode.ADD_REDUCTION_VHF, " >0 "}, + applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}) + public short vectorAddReductionFloat16() { + short result = (short) 0; + for (int i = 0; i < LEN; i++) { + result = float16ToRawShortBits(add(shortBitsToFloat16(result), shortBitsToFloat16(input1[i]))); + } + return result; + } + + @Check(test="vectorAddReductionFloat16") + public void checkResultAddReductionFloat16() { + short expected = (short) 0; + for (int i = 0; i < LEN; ++i) { + expected = floatToFloat16(float16ToFloat(expected) + float16ToFloat(input1[i])); + } + Verify.checkEQ(shortBitsToFloat16(expected), shortBitsToFloat16(vectorAddReductionFloat16())); + } + + @Test + @Warmup(50) + @IR(counts = {IRNode.MUL_REDUCTION_VHF, " >0 "}, + applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}, + applyIf = {"MaxVectorSize", "<=16"}) + public short vectorMulReductionFloat16() { + short result = floatToFloat16(1.0f); + for (int i = 0; i < LEN; i++) { + result = float16ToRawShortBits(multiply(shortBitsToFloat16(result), shortBitsToFloat16(input1[i]))); + } + return result; + } + + @Check(test="vectorMulReductionFloat16") + public void checkResultMulReductionFloat16() { + short expected = floatToFloat16(1.0f); + for (int i = 0; i < LEN; ++i) { + expected = floatToFloat16(float16ToFloat(expected) * float16ToFloat(input1[i])); + } + Verify.checkEQ(shortBitsToFloat16(expected), shortBitsToFloat16(vectorMulReductionFloat16())); + } + + // This test case verifies that autovectorization takes place in scenarios where masked + // add reduction instructions are required to be generated on platforms that support + // such masked/partial instructions. + @Test + @Warmup(500) + @IR(counts = {"reduce_addFHF_masked", " >0 "}, phase = {CompilePhase.FINAL_CODE}, + applyIfCPUFeature = {"sve", "true"}) + public short vectorAddReductionFloat16Partial() { + short result = (short) 0; + for (int i = 0; i < LEN; i+=8) { + result = float16ToRawShortBits(add(shortBitsToFloat16(result), shortBitsToFloat16(input1[i]))); + result = float16ToRawShortBits(add(shortBitsToFloat16(result), shortBitsToFloat16(input1[i+1]))); + result = float16ToRawShortBits(add(shortBitsToFloat16(result), shortBitsToFloat16(input1[i+2]))); + result = float16ToRawShortBits(add(shortBitsToFloat16(result), shortBitsToFloat16(input1[i+3]))); + } + return result; + } + + @Check(test="vectorAddReductionFloat16Partial") + public void checkResultAddReductionFloat16Partial() { + short expected = (short) 0; + for (int i = 0; i < LEN; i+=8) { + expected = floatToFloat16(float16ToFloat(expected) + float16ToFloat(input1[i])); + expected = floatToFloat16(float16ToFloat(expected) + float16ToFloat(input1[i+1])); + expected = floatToFloat16(float16ToFloat(expected) + float16ToFloat(input1[i+2])); + expected = floatToFloat16(float16ToFloat(expected) + float16ToFloat(input1[i+3])); + } + Verify.checkEQ(shortBitsToFloat16(expected), shortBitsToFloat16(vectorAddReductionFloat16Partial())); + } + + // Partial multiply reduction for floating point is disabled on AArch64. This test makes sure that code that performs such partial + // multiply reduction operation for FP16 runs without any failures/result mismatch. + @Test + @Warmup(500) + public short vectorMulReductionFloat16Partial() { + short result = floatToFloat16(1.0f); + for (int i = 0; i < LEN; i+=8) { + result = float16ToRawShortBits(multiply(shortBitsToFloat16(result), shortBitsToFloat16(input1[i]))); + result = float16ToRawShortBits(multiply(shortBitsToFloat16(result), shortBitsToFloat16(input1[i+1]))); + result = float16ToRawShortBits(multiply(shortBitsToFloat16(result), shortBitsToFloat16(input1[i+2]))); + result = float16ToRawShortBits(multiply(shortBitsToFloat16(result), shortBitsToFloat16(input1[i+3]))); + } + return result; + } + + @Check(test="vectorMulReductionFloat16Partial") + public void checkResultMulReductionFloat16Partial() { + short expected = floatToFloat16(1.0f); + for (int i = 0; i < LEN; i+=8) { + expected = floatToFloat16(float16ToFloat(expected) * float16ToFloat(input1[i])); + expected = floatToFloat16(float16ToFloat(expected) * float16ToFloat(input1[i+1])); + expected = floatToFloat16(float16ToFloat(expected) * float16ToFloat(input1[i+2])); + expected = floatToFloat16(float16ToFloat(expected) * float16ToFloat(input1[i+3])); + } + Verify.checkEQ(shortBitsToFloat16(expected), shortBitsToFloat16(vectorMulReductionFloat16Partial())); + } + + // This test case verifies that autovectorization does NOT take place when using Float16. + // Filed RFE: JDK-8375321 + @Test + @Warmup(50) + @IR(counts = {IRNode.ADD_REDUCTION_VHF, " =0 "}, + applyIfCPUFeature = {"sve", "true"}) + @IR(counts = {IRNode.ADD_REDUCTION_VHF, " =0 "}, + applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}) + public Float16 vectorAddReductionFloat16NotVectorized() { + Float16 result = Float16.valueOf(0.0f); + for (int i = 0; i < LEN; i++) { + result = add(result, input4[i]); + } + return result; + } + + @Check(test="vectorAddReductionFloat16NotVectorized") + public void checkResultAddReductionFloat16NotVectorized() { + Float16 expected = Float16.valueOf(0.0f); + for (int i = 0; i < LEN; ++i) { + expected = Float16.valueOf(expected.floatValue() + input4[i].floatValue()); + } + Verify.checkEQ(expected, vectorAddReductionFloat16NotVectorized()); + } + + @Test + @Warmup(50) + @IR(counts = {IRNode.MUL_REDUCTION_VHF, " =0 "}, + applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}, + applyIf = {"MaxVectorSize", "<=16"}) + public Float16 vectorMulReductionFloat16NotVectorized() { + Float16 result = Float16.valueOf(1.0f); + for (int i = 0; i < LEN; i++) { + result = multiply(result, input4[i]); + } + return result; + } + + @Check(test="vectorMulReductionFloat16NotVectorized") + public void checkResultMulReductionFloat16NotVectorized() { + Float16 expected = Float16.valueOf(1.0f); + for (int i = 0; i < LEN; ++i) { + expected = Float16.valueOf(expected.floatValue() * input4[i].floatValue()); + } + Verify.checkEQ(expected, vectorMulReductionFloat16NotVectorized()); + } + + @Test + @Warmup(500) + @IR(counts = {"reduce_addFHF_masked", " =0 "}, phase = {CompilePhase.FINAL_CODE}, + applyIfCPUFeature = {"sve", "true"}) + public Float16 vectorAddReductionFloat16PartialNotVectorized() { + Float16 result = Float16.valueOf(0.0f); + for (int i = 0; i < LEN; i += 8) { + result = add(result, input4[i]); + result = add(result, input4[i + 1]); + result = add(result, input4[i + 2]); + result = add(result, input4[i + 3]); + } + return result; + } + + @Check(test="vectorAddReductionFloat16PartialNotVectorized") + public void checkResultAddReductionFloat16PartialNotVectorized() { + Float16 expected = Float16.valueOf(0.0f); + for (int i = 0; i < LEN; i += 8) { + expected = Float16.valueOf(expected.floatValue() + input4[i].floatValue()); + expected = Float16.valueOf(expected.floatValue() + input4[i + 1].floatValue()); + expected = Float16.valueOf(expected.floatValue() + input4[i + 2].floatValue()); + expected = Float16.valueOf(expected.floatValue() + input4[i + 3].floatValue()); + } + Verify.checkEQ(expected, vectorAddReductionFloat16PartialNotVectorized()); + } + + @Test + @Warmup(500) + public Float16 vectorMulReductionFloat16PartialNotVectorized() { + Float16 result = Float16.valueOf(1.0f); + for (int i = 0; i < LEN; i += 8) { + result = multiply(result, input4[i]); + result = multiply(result, input4[i + 1]); + result = multiply(result, input4[i + 2]); + result = multiply(result, input4[i + 3]); + } + return result; + } + + @Check(test="vectorMulReductionFloat16PartialNotVectorized") + public void checkResultMulReductionFloat16PartialNotVectorized() { + Float16 expected = Float16.valueOf(1.0f); + for (int i = 0; i < LEN; i += 8) { + expected = Float16.valueOf(expected.floatValue() * input4[i].floatValue()); + expected = Float16.valueOf(expected.floatValue() * input4[i + 1].floatValue()); + expected = Float16.valueOf(expected.floatValue() * input4[i + 2].floatValue()); + expected = Float16.valueOf(expected.floatValue() * input4[i + 3].floatValue()); + } + Verify.checkEQ(expected, vectorMulReductionFloat16PartialNotVectorized()); + } + } 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 92c0b58005f..daf18af528e 100644 --- a/test/micro/org/openjdk/bench/jdk/incubator/vector/Float16OperationsBenchmark.java +++ b/test/micro/org/openjdk/bench/jdk/incubator/vector/Float16OperationsBenchmark.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. + * Copyright 2026 Arm Limited 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 @@ -350,4 +351,22 @@ public class Float16OperationsBenchmark { } return distRes; } + + @Benchmark + public short reductionAddFP16() { + short result = (short) 0; + for (int i = 0; i < vectorDim; i++) { + result = float16ToRawShortBits(add(shortBitsToFloat16(result), shortBitsToFloat16(vector1[i]))); + } + return result; + } + + @Benchmark + public short reductionMulFP16() { + short result = floatToFloat16(1.0f); + for (int i = 0; i < vectorDim; i++) { + result = float16ToRawShortBits(multiply(shortBitsToFloat16(result), shortBitsToFloat16(vector1[i]))); + } + return result; + } } diff --git a/test/micro/org/openjdk/bench/vm/compiler/VectorReduction2.java b/test/micro/org/openjdk/bench/vm/compiler/VectorReduction2.java index 9241aca1dad..0d11705c8ec 100644 --- a/test/micro/org/openjdk/bench/vm/compiler/VectorReduction2.java +++ b/test/micro/org/openjdk/bench/vm/compiler/VectorReduction2.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright 2026 Arm Limited 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 @@ -27,6 +28,7 @@ import org.openjdk.jmh.infra.*; import java.util.concurrent.TimeUnit; import java.util.Random; +import jdk.incubator.vector.Float16; /** * Note: there is a corresponding IR test: @@ -64,6 +66,9 @@ public abstract class VectorReduction2 { private double[] in1D; private double[] in2D; private double[] in3D; + private short[] in1F16; + private short[] in2F16; + private short[] in3F16; @Param("0") private int seed; @@ -96,6 +101,9 @@ public abstract class VectorReduction2 { in1D = new double[SIZE]; in2D = new double[SIZE]; in3D = new double[SIZE]; + in1F16 = new short[SIZE]; + in2F16 = new short[SIZE]; + in3F16 = new short[SIZE]; for (int i = 0; i < SIZE; i++) { in1B[i] = (byte)r.nextInt(); @@ -121,6 +129,9 @@ public abstract class VectorReduction2 { in1D[i] = r.nextDouble(); in2D[i] = r.nextDouble(); in3D[i] = r.nextDouble(); + in1F16[i] = Float.floatToFloat16(r.nextFloat()); + in2F16[i] = Float.floatToFloat16(r.nextFloat()); + in3F16[i] = Float.floatToFloat16(r.nextFloat()); } } @@ -1449,10 +1460,86 @@ public abstract class VectorReduction2 { bh.consume(acc); } - @Fork(value = 1, jvmArgs = {"-XX:+UseSuperWord"}) + // ---------float16***Simple ------------------------------------------------------------ + @Benchmark + public void float16AddSimple(Blackhole bh) { + short acc = (short)0; // neutral element + for (int i = 0; i < SIZE; i++) { + acc = Float16.float16ToRawShortBits( + Float16.add(Float16.shortBitsToFloat16(acc), Float16.shortBitsToFloat16(in1F16[i]))); + } + bh.consume(acc); + } + + @Benchmark + public void float16MulSimple(Blackhole bh) { + short acc = Float.floatToFloat16(1.0f); // neutral element + for (int i = 0; i < SIZE; i++) { + acc = Float16.float16ToRawShortBits( + Float16.multiply(Float16.shortBitsToFloat16(acc), Float16.shortBitsToFloat16(in1F16[i]))); + } + bh.consume(acc); + } + + // ---------float16***DotProduct ------------------------------------------------------------ + @Benchmark + public void float16AddDotProduct(Blackhole bh) { + short acc = (short)0; // neutral element + for (int i = 0; i < SIZE; i++) { + Float16 val = Float16.multiply(Float16.shortBitsToFloat16(in1F16[i]), + Float16.shortBitsToFloat16(in2F16[i])); + acc = Float16.float16ToRawShortBits( + Float16.add(Float16.shortBitsToFloat16(acc), val)); + } + bh.consume(acc); + } + + @Benchmark + public void float16MulDotProduct(Blackhole bh) { + short acc = Float.floatToFloat16(1.0f); // neutral element + for (int i = 0; i < SIZE; i++) { + Float16 val = Float16.multiply(Float16.shortBitsToFloat16(in1F16[i]), + Float16.shortBitsToFloat16(in2F16[i])); + acc = Float16.float16ToRawShortBits( + Float16.multiply(Float16.shortBitsToFloat16(acc), val)); + } + bh.consume(acc); + } + + // ---------float16***Big ------------------------------------------------------------ + @Benchmark + public void float16AddBig(Blackhole bh) { + short acc = (short)0; // neutral element + for (int i = 0; i < SIZE; i++) { + Float16 a = Float16.shortBitsToFloat16(in1F16[i]); + Float16 b = Float16.shortBitsToFloat16(in2F16[i]); + Float16 c = Float16.shortBitsToFloat16(in3F16[i]); + Float16 val = Float16.add(Float16.multiply(a, b), + Float16.add(Float16.multiply(a, c), Float16.multiply(b, c))); + acc = Float16.float16ToRawShortBits( + Float16.add(Float16.shortBitsToFloat16(acc), val)); + } + bh.consume(acc); + } + + @Benchmark + public void float16MulBig(Blackhole bh) { + short acc = Float.floatToFloat16(1.0f); // neutral element + for (int i = 0; i < SIZE; i++) { + Float16 a = Float16.shortBitsToFloat16(in1F16[i]); + Float16 b = Float16.shortBitsToFloat16(in2F16[i]); + Float16 c = Float16.shortBitsToFloat16(in3F16[i]); + Float16 val = Float16.add(Float16.multiply(a, b), + Float16.add(Float16.multiply(a, c), Float16.multiply(b, c))); + acc = Float16.float16ToRawShortBits( + Float16.multiply(Float16.shortBitsToFloat16(acc), val)); + } + bh.consume(acc); + } + + @Fork(value = 1, jvmArgs = {"--add-modules=jdk.incubator.vector", "-XX:+UseSuperWord"}) public static class WithSuperword extends VectorReduction2 {} - @Fork(value = 1, jvmArgs = {"-XX:-UseSuperWord"}) + @Fork(value = 1, jvmArgs = {"--add-modules=jdk.incubator.vector", "-XX:-UseSuperWord"}) public static class NoSuperword extends VectorReduction2 {} } - From 0df4bd489de00056736321f1e77389add7a41f83 Mon Sep 17 00:00:00 2001 From: Alexey Ivanov Date: Wed, 15 Apr 2026 13:07:24 +0000 Subject: [PATCH 293/359] 8381208: Init cause with the caught runtime exception Reviewed-by: dmarkov, serb, azvegint --- .../classes/sun/print/RasterPrinterJob.java | 14 +++--- .../ExceptionFromPrintableIsIgnoredTest.java | 45 +++++++++++++++---- 2 files changed, 43 insertions(+), 16 deletions(-) diff --git a/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java b/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java index 32728efde6c..b28723f94a6 100644 --- a/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java +++ b/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java @@ -33,24 +33,23 @@ import java.awt.HeadlessException; import java.awt.KeyboardFocusManager; import java.awt.Rectangle; import java.awt.Shape; +import java.awt.Window; import java.awt.geom.AffineTransform; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import java.awt.print.Book; -import java.awt.print.Pageable; import java.awt.print.PageFormat; +import java.awt.print.Pageable; import java.awt.print.Paper; import java.awt.print.Printable; import java.awt.print.PrinterAbortException; import java.awt.print.PrinterException; import java.awt.print.PrinterJob; -import java.awt.Window; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Locale; -import sun.awt.image.ByteInterleavedRaster; import javax.print.Doc; import javax.print.DocFlavor; @@ -69,8 +68,8 @@ import javax.print.attribute.ResolutionSyntax; import javax.print.attribute.Size2DSyntax; import javax.print.attribute.standard.Copies; import javax.print.attribute.standard.Destination; -import javax.print.attribute.standard.DialogTypeSelection; import javax.print.attribute.standard.DialogOwner; +import javax.print.attribute.standard.DialogTypeSelection; import javax.print.attribute.standard.Fidelity; import javax.print.attribute.standard.JobName; import javax.print.attribute.standard.JobSheets; @@ -81,15 +80,17 @@ import javax.print.attribute.standard.MediaSizeName; import javax.print.attribute.standard.OrientationRequested; import javax.print.attribute.standard.OutputBin; import javax.print.attribute.standard.PageRanges; +import javax.print.attribute.standard.PrinterIsAcceptingJobs; import javax.print.attribute.standard.PrinterResolution; import javax.print.attribute.standard.PrinterState; import javax.print.attribute.standard.PrinterStateReason; import javax.print.attribute.standard.PrinterStateReasons; -import javax.print.attribute.standard.PrinterIsAcceptingJobs; import javax.print.attribute.standard.RequestingUserName; import javax.print.attribute.standard.SheetCollate; import javax.print.attribute.standard.Sides; +import sun.awt.image.ByteInterleavedRaster; + import static sun.font.FontUtilities.isIgnorableWhitespace; /** @@ -1613,8 +1614,7 @@ public abstract class RasterPrinterJob extends PrinterJob { } catch (PrinterException pe) { throw pe; } catch (Throwable printError) { - throw (PrinterException) - new PrinterException().initCause(printError.getCause()); + throw (PrinterException) new PrinterException().initCause(printError); } finally { // reset previousPaper in case this job is invoked again. previousPaper = null; diff --git a/test/jdk/java/awt/print/PrinterJob/ExceptionFromPrintableIsIgnoredTest.java b/test/jdk/java/awt/print/PrinterJob/ExceptionFromPrintableIsIgnoredTest.java index 4c2ff370cb8..322c19ed7c2 100644 --- a/test/jdk/java/awt/print/PrinterJob/ExceptionFromPrintableIsIgnoredTest.java +++ b/test/jdk/java/awt/print/PrinterJob/ExceptionFromPrintableIsIgnoredTest.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8262731 8268675 + * @bug 8262731 8268675 8381208 * @key printer * @summary Verify that "PrinterJob.print" throws the expected exception, * if "Printable.print" throws an exception. @@ -38,7 +38,12 @@ import java.awt.print.PageFormat; import java.awt.print.Printable; import java.awt.print.PrinterException; import java.awt.print.PrinterJob; +import java.io.File; import java.lang.reflect.InvocationTargetException; + +import javax.print.attribute.HashPrintRequestAttributeSet; +import javax.print.attribute.PrintRequestAttributeSet; +import javax.print.attribute.standard.Destination; import javax.swing.SwingUtilities; public class ExceptionFromPrintableIsIgnoredTest { @@ -47,7 +52,14 @@ public class ExceptionFromPrintableIsIgnoredTest { private volatile Throwable printError; + private volatile PrinterException thrownPE; + private volatile RuntimeException thrownRE; + public static void main(String[] args) { + if (PrinterJob.lookupPrintServices().length == 0) { + throw new RuntimeException("Printer not configured or available."); + } + if (args.length < 2) { throw new RuntimeException("Two arguments are expected:" + " test thread type and test exception type."); @@ -58,7 +70,7 @@ public class ExceptionFromPrintableIsIgnoredTest { TestExceptionType.valueOf(args[1])); } - public ExceptionFromPrintableIsIgnoredTest( + private ExceptionFromPrintableIsIgnoredTest( final TestThreadType threadType, final TestExceptionType exceptionType) { System.out.println(String.format( @@ -87,15 +99,28 @@ public class ExceptionFromPrintableIsIgnoredTest { } else if (!(printError instanceof PrinterException)) { throw new RuntimeException("Unexpected exception was thrown."); } + + if (exceptionType == TestExceptionType.PE + && thrownPE != printError) { + throw new RuntimeException( + "Expected the same instance of PrinterException"); + } + + if (exceptionType == TestExceptionType.RE + && thrownRE != printError.getCause()) { + throw new RuntimeException( + "Expected the cause of PrinterException to be the thrown exception"); + } + System.out.println("Test passed."); } private void runTest(final TestExceptionType exceptionType) { + PrintRequestAttributeSet attrs = new HashPrintRequestAttributeSet(); + final File file = new File("out.prn"); + attrs.add(new Destination(file.toURI())); + PrinterJob job = PrinterJob.getPrinterJob(); - if (job.getPrintService() == null) { - System.out.println("No printers are available."); - return; - } job.setPrintable(new Printable() { @Override @@ -105,10 +130,10 @@ public class ExceptionFromPrintableIsIgnoredTest { return NO_SUCH_PAGE; } if (exceptionType == TestExceptionType.PE) { - throw new PrinterException( + throw thrownPE = new PrinterException( "Exception from 'Printable.print'."); } else if (exceptionType == TestExceptionType.RE) { - throw new RuntimeException( + throw thrownRE = new RuntimeException( "Exception from 'Printable.print'."); } return PAGE_EXISTS; @@ -116,12 +141,14 @@ public class ExceptionFromPrintableIsIgnoredTest { }); try { - job.print(); + job.print(attrs); } catch (Throwable t) { printError = t; System.out.println("'PrinterJob.print' threw the exception:"); t.printStackTrace(System.out); + } finally { + file.delete(); } } } From 152fa85fba4615f036f395b5ae03213b02be56e2 Mon Sep 17 00:00:00 2001 From: Vladimir Kozlov Date: Wed, 15 Apr 2026 14:12:57 +0000 Subject: [PATCH 294/359] 8382134: Replace assert with fatal check in AOTCodeCache::load_strings() to make sure we have valid value in product VM Reviewed-by: iklam, mhaessig, adinn --- src/hotspot/share/code/aotCodeCache.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/code/aotCodeCache.cpp b/src/hotspot/share/code/aotCodeCache.cpp index a3dd3d2bfd0..c2838917516 100644 --- a/src/hotspot/share/code/aotCodeCache.cpp +++ b/src/hotspot/share/code/aotCodeCache.cpp @@ -2201,6 +2201,10 @@ void AOTCodeCache::load_strings() { if (strings_count == 0) { return; } + if (strings_count > MAX_STR_COUNT) { + fatal("Invalid strings_count loaded from AOT Code Cache: %d > MAX_STR_COUNT [%d]", strings_count, MAX_STR_COUNT); + return; + } uint strings_offset = _load_header->strings_offset(); uint* string_lengths = (uint*)addr(strings_offset); strings_offset += (strings_count * sizeof(uint)); @@ -2211,7 +2215,6 @@ void AOTCodeCache::load_strings() { char* p = NEW_C_HEAP_ARRAY(char, strings_size+1, mtCode); memcpy(p, addr(strings_offset), strings_size); _C_strings_buf = p; - assert(strings_count <= MAX_STR_COUNT, "sanity"); for (uint i = 0; i < strings_count; i++) { _C_strings[i] = p; uint len = string_lengths[i]; From e82f871871885688d42985c1cfe00ba0dc4c35b3 Mon Sep 17 00:00:00 2001 From: Leonid Mesnik Date: Wed, 15 Apr 2026 14:19:14 +0000 Subject: [PATCH 295/359] 8362350: recompute_enable hit assertion "should never come here before live phase" if happens in post_vm_start Reviewed-by: cjplummer, sspitsyn --- .../share/prims/jvmtiEventController.cpp | 5 ++ .../jtreg/ProblemList-jvmti-stress-agent.txt | 2 - .../singlestep02/libsinglestep02.cpp | 48 ++++++++----------- .../SingleStep/singlestep02/singlestep02.java | 18 +------ 4 files changed, 26 insertions(+), 47 deletions(-) diff --git a/src/hotspot/share/prims/jvmtiEventController.cpp b/src/hotspot/share/prims/jvmtiEventController.cpp index cb44b833c48..832c8a33c88 100644 --- a/src/hotspot/share/prims/jvmtiEventController.cpp +++ b/src/hotspot/share/prims/jvmtiEventController.cpp @@ -544,6 +544,11 @@ JvmtiEventControllerPrivate::recompute_env_thread_enabled(JvmtiEnvThreadState* e } switch (JvmtiEnv::get_phase()) { + case JVMTI_PHASE_ONLOAD: + case JVMTI_PHASE_PRIMORDIAL: + case JVMTI_PHASE_START: + now_enabled &= EARLY_EVENT_BITS; + break; case JVMTI_PHASE_DEAD: // no events allowed when dead now_enabled = 0; diff --git a/test/hotspot/jtreg/ProblemList-jvmti-stress-agent.txt b/test/hotspot/jtreg/ProblemList-jvmti-stress-agent.txt index 1e84a39c30b..d8779a873cd 100644 --- a/test/hotspot/jtreg/ProblemList-jvmti-stress-agent.txt +++ b/test/hotspot/jtreg/ProblemList-jvmti-stress-agent.txt @@ -32,8 +32,6 @@ gc/stringdedup/TestStringDeduplicationInterned.java 8362562 generic-all gc/stringdedup/TestStringDeduplicationPrintOptions.java 8362562 generic-all -serviceability/jvmti/events/SingleStep/singlestep02/singlestep02.java 8362350 generic-all -vmTestbase/nsk/jvmti/scenarios/events/EM02/em02t007/TestDescription.java 8362350 generic-all # Incompatbile tests diff --git a/test/hotspot/jtreg/serviceability/jvmti/events/SingleStep/singlestep02/libsinglestep02.cpp b/test/hotspot/jtreg/serviceability/jvmti/events/SingleStep/singlestep02/libsinglestep02.cpp index 984454dfbaf..b52e3412f4e 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/events/SingleStep/singlestep02/libsinglestep02.cpp +++ b/test/hotspot/jtreg/serviceability/jvmti/events/SingleStep/singlestep02/libsinglestep02.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 @@ extern "C" { -#define STATUS_FAILED 2 -#define PASSED 0 - -static volatile jint result = PASSED; -static volatile long wrongStepEv = 0; static jvmtiEnv *jvmti = nullptr; @@ -44,31 +39,25 @@ SingleStep(jvmtiEnv *jvmti, JNIEnv *jni, jthread thread, jmethodID method, jloca jvmtiError err; err = jvmti->GetPhase(&phase); - if (err != JVMTI_ERROR_NONE) { - result = STATUS_FAILED; - COMPLAIN("TEST FAILED: unable to obtain phase of the VM execution during SingleStep callback\n\n"); - } else { - if (phase != JVMTI_PHASE_LIVE) { - wrongStepEv++; - result = STATUS_FAILED; - COMPLAIN("TEST FAILED: SingleStep event received during non-live phase %s\n", TranslatePhase(phase)); - } + check_jvmti_status(jni, err, "Error in GetPhase"); + if (phase != JVMTI_PHASE_LIVE) { + COMPLAIN("TEST FAILED: SingleStep event received during non-live phase %s\n", TranslatePhase(phase)); + jni->FatalError("Event SingleStep event received during non-live phase."); } } +/* + * The ClassLoad event is not used. This is thread filtered event that should + * be sent during start phase. It is enabled to trigger creation of jvmti thread state + * in the START phase. So test ensures that even jvmti state for thread is created + * before live phase the SingleStep event is sent only during live phase. + */ void JNICALL -VMDeath(jvmtiEnv *jvmti, JNIEnv *jni) { - LOG("VMDeath event received\n"); +ClassLoad(jvmtiEnv *jvmti_env, + JNIEnv* jni_env, + jthread thread, + jclass klass) { - if (wrongStepEv != 0) { - LOG("TEST FAILED: there are %ld SingleStep events\n" - "sent during non-live phase of the VM execution\n", wrongStepEv); - jni->FatalError("Test Failed."); - } - - if (result == STATUS_FAILED) { - jni->FatalError("Test Failed."); - } } jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { @@ -105,19 +94,20 @@ jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { /* set event callback */ LOG("setting event callbacks ...\n"); (void) memset(&callbacks, 0, sizeof(callbacks)); + callbacks.ClassLoad = &ClassLoad; callbacks.SingleStep = &SingleStep; - callbacks.VMDeath = &VMDeath; err = jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks)); if (err != JVMTI_ERROR_NONE) { return JNI_ERR; } LOG("setting event callbacks done\nenabling JVMTI events ...\n"); - err = jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_SINGLE_STEP, nullptr); + + err = jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_CLASS_LOAD, nullptr); if (err != JVMTI_ERROR_NONE) { return JNI_ERR; } - err = jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_VM_DEATH, nullptr); + err = jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_SINGLE_STEP, nullptr); if (err != JVMTI_ERROR_NONE) { return JNI_ERR; } diff --git a/test/hotspot/jtreg/serviceability/jvmti/events/SingleStep/singlestep02/singlestep02.java b/test/hotspot/jtreg/serviceability/jvmti/events/SingleStep/singlestep02/singlestep02.java index 8a7b7cf106a..9d25a7bc090 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/events/SingleStep/singlestep02/singlestep02.java +++ b/test/hotspot/jtreg/serviceability/jvmti/events/SingleStep/singlestep02/singlestep02.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * 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,39 +21,25 @@ * questions. */ -import jdk.test.lib.jvmti.DebugeeClass; import java.io.*; /* * @test * * @summary converted from VM Testbase nsk/jvmti/SingleStep/singlestep002. - * VM Testbase keywords: [jpda, jvmti, onload_only_caps, noras] - * VM Testbase readme: - * DESCRIPTION * This test exercises the JVMTI event SingleStep. - * It verifies that this event s sent only during the live phase + * It verifies that this event is sent only during the live phase * of VM execution. * The test works as follows. The tested event is enabled in the * 'OnLoad' phase. Then all received SingleStep events is checked * to be sent only during the live phase via the GetPhase() call. - * COMMENTS * - * @library /test/lib * @run main/othervm/native -agentlib:singlestep02 singlestep02 */ public class singlestep02 { - static { - System.loadLibrary("singlestep02"); - } - public static void main(String[] args) { - new singlestep02().runThis(args); } - private int runThis(String argv[]) { - return DebugeeClass.TEST_PASSED; - } } From a06f3cd469f1343c53ecc9b1dda2c6cbdf5f98f3 Mon Sep 17 00:00:00 2001 From: Quan Anh Mai Date: Wed, 15 Apr 2026 14:27:25 +0000 Subject: [PATCH 296/359] 8373248: C2: CastPP should not change the type of the oop Reviewed-by: bmaillard, dfenacci, rcastanedalo, mchevalier --- src/hotspot/share/opto/castnode.cpp | 42 +++++++++++++++++++++++++ src/hotspot/share/opto/castnode.hpp | 11 +++++-- src/hotspot/share/opto/library_call.cpp | 2 +- src/hotspot/share/opto/node.hpp | 1 + src/hotspot/share/opto/vector.cpp | 14 ++++----- 5 files changed, 58 insertions(+), 12 deletions(-) diff --git a/src/hotspot/share/opto/castnode.cpp b/src/hotspot/share/opto/castnode.cpp index 54269a56c19..7bb6b1dcb77 100644 --- a/src/hotspot/share/opto/castnode.cpp +++ b/src/hotspot/share/opto/castnode.cpp @@ -413,6 +413,43 @@ Node* CastLLNode::Ideal(PhaseGVN* phase, bool can_reshape) { return nullptr; } +// CastPPNodes are removed before matching, while alias classes are needed in global code motion. +// As a result, it is not valid for a CastPPNode to change the oop such that the derived pointers +// lie in different alias classes with and without the node. For example, a CastPPNode c may not +// cast an Object to a Bottom[], because later removal of c would affect the alias class of c's +// array length field (c + arrayOopDesc::length_offset_in_bytes()). +// +// This function verifies that a CastPPNode on an oop does not violate the aforementioned property. +// +// TODO 8382147: Currently, this verification only applies during the construction of a CastPPNode, +// we may want to apply the same verification during IGVN transformations, as well as final graph +// reshaping. +void CastPPNode::verify_type(const Type* in_type, const Type* out_type) { +#ifdef ASSERT + out_type = out_type->join(in_type); + if (in_type->empty() || out_type->empty()) { + return; + } + if (in_type == TypePtr::NULL_PTR || out_type == TypePtr::NULL_PTR) { + return; + } + if (!in_type->isa_oopptr() && !out_type->isa_oopptr()) { + return; + } + + assert(in_type->isa_oopptr() && out_type->isa_oopptr(), "must be both oops or both non-oops"); + if (in_type->isa_aryptr() && out_type->isa_aryptr()) { + const Type* e1 = in_type->is_aryptr()->elem(); + const Type* e2 = out_type->is_aryptr()->elem(); + assert(e1->basic_type() == e2->basic_type(), "must both be arrays of the same primitive type or both be oops arrays"); + return; + } + + assert(in_type->isa_instptr() && out_type->isa_instptr(), "must be both array oops or both non-array oops"); + assert(in_type->is_instptr()->instance_klass() == out_type->is_instptr()->instance_klass(), "must not cast to a different type"); +#endif // ASSERT +} + //------------------------------Value------------------------------------------ // Take 'join' of input and cast-up type, unless working with an Interface const Type* CheckCastPPNode::Value(PhaseGVN* phase) const { @@ -440,6 +477,11 @@ const Type* CheckCastPPNode::Value(PhaseGVN* phase) const { return result; } +Node* CheckCastPPNode::pin_node_under_control_impl() const { + assert(_dependency.is_floating(), "already pinned"); + return new CheckCastPPNode(in(0), in(1), bottom_type(), _dependency.with_pinned_dependency(), _extra_types); +} + //============================================================================= //------------------------------Value------------------------------------------ const Type* CastX2PNode::Value(PhaseGVN* phase) const { diff --git a/src/hotspot/share/opto/castnode.hpp b/src/hotspot/share/opto/castnode.hpp index 38545fd6f41..dce54eb73c0 100644 --- a/src/hotspot/share/opto/castnode.hpp +++ b/src/hotspot/share/opto/castnode.hpp @@ -303,14 +303,18 @@ public: //------------------------------CastPPNode------------------------------------- // cast pointer to pointer (different type) -class CastPPNode: public ConstraintCastNode { - public: - CastPPNode (Node* ctrl, Node* n, const Type* t, const DependencyType& dependency = DependencyType::FloatingNarrowing, const TypeTuple* types = nullptr) +class CastPPNode : public ConstraintCastNode { +public: + CastPPNode(Node* ctrl, Node* n, const Type* t, const DependencyType& dependency = DependencyType::FloatingNarrowing, const TypeTuple* types = nullptr) : ConstraintCastNode(ctrl, n, t, dependency, types) { init_class_id(Class_CastPP); + verify_type(n->bottom_type(), t); } virtual int Opcode() const; virtual uint ideal_reg() const { return Op_RegP; } + +private: + static void verify_type(const Type* in_type, const Type* out_type); }; //------------------------------CheckCastPPNode-------------------------------- @@ -329,6 +333,7 @@ class CheckCastPPNode: public ConstraintCastNode { private: virtual bool depends_only_on_test_impl() const { return !type()->isa_rawptr() && ConstraintCastNode::depends_only_on_test_impl(); } + virtual Node* pin_node_under_control_impl() const; }; diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index 26417436ed9..ff7bc2c10d3 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -4311,7 +4311,7 @@ Node* LibraryCallKit::generate_array_guard_common(Node* kls, RegionNode* region, if (obj != nullptr && is_array_ctrl != nullptr && is_array_ctrl != top()) { // Keep track of the fact that 'obj' is an array to prevent // array specific accesses from floating above the guard. - *obj = _gvn.transform(new CastPPNode(is_array_ctrl, *obj, TypeAryPtr::BOTTOM)); + *obj = _gvn.transform(new CheckCastPPNode(is_array_ctrl, *obj, TypeAryPtr::BOTTOM)); } return ctrl; } diff --git a/src/hotspot/share/opto/node.hpp b/src/hotspot/share/opto/node.hpp index 36855d659ba..8c6622e643e 100644 --- a/src/hotspot/share/opto/node.hpp +++ b/src/hotspot/share/opto/node.hpp @@ -1186,6 +1186,7 @@ public: return nullptr; } assert(!res->depends_only_on_test(), "the result must not depends_only_on_test"); + assert(Opcode() == res->Opcode(), "pinning must result in the same kind of node %s - %s", Name(), res->Name()); return res; } diff --git a/src/hotspot/share/opto/vector.cpp b/src/hotspot/share/opto/vector.cpp index f44df7e6da2..d35717c5922 100644 --- a/src/hotspot/share/opto/vector.cpp +++ b/src/hotspot/share/opto/vector.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -455,14 +455,12 @@ void PhaseVector::expand_vunbox_node(VectorUnboxNode* vec_unbox) { gvn.record_for_igvn(local_mem); BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2(); C2OptAccess access(gvn, ctrl, local_mem, decorators, T_OBJECT, obj, addr); - const Type* type = TypeOopPtr::make_from_klass(field->type()->as_klass()); - vec_field_ld = bs->load_at(access, type); - } - // For proper aliasing, attach concrete payload type. - ciKlass* payload_klass = ciTypeArrayKlass::make(bt); - const Type* payload_type = TypeAryPtr::make_from_klass(payload_klass)->cast_to_ptr_type(TypePtr::NotNull); - vec_field_ld = gvn.transform(new CastPPNode(nullptr, vec_field_ld, payload_type)); + // For proper aliasing, attach concrete payload type. + ciKlass* payload_klass = ciTypeArrayKlass::make(bt); + const Type* payload_type = TypeAryPtr::make_from_klass(payload_klass)->cast_to_ptr_type(TypePtr::NotNull); + vec_field_ld = bs->load_at(access, payload_type); + } Node* adr = kit.array_element_address(vec_field_ld, gvn.intcon(0), bt); const TypePtr* adr_type = adr->bottom_type()->is_ptr(); From 974596775b2b1fe048ec7de0e35dc6f8283d844a Mon Sep 17 00:00:00 2001 From: Ashutosh Mehra Date: Wed, 15 Apr 2026 14:30:30 +0000 Subject: [PATCH 297/359] 8381968: Extend cds/appcds/aotCode/AOTCodeFlags.java to run test with different flags in assembly and prod run Reviewed-by: kvn, adinn --- test/hotspot/jtreg/TEST.groups | 3 +- .../AOTCodeCPUFeatureIncompatibilityTest.java | 12 +- .../aotCode/AOTCodeCompressedOopsTest.java | 12 +- .../cds/appcds/aotCode/AOTCodeFlags.java | 137 ++++++------ .../cds/appcds/aotCode/AOTCodeTest.java | 196 ++++++++++++++++++ test/setup_aot/HelloWorld.java | 29 +++ 6 files changed, 310 insertions(+), 79 deletions(-) create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeTest.java create mode 100644 test/setup_aot/HelloWorld.java diff --git a/test/hotspot/jtreg/TEST.groups b/test/hotspot/jtreg/TEST.groups index 6e9421e5c09..6623676d2ba 100644 --- a/test/hotspot/jtreg/TEST.groups +++ b/test/hotspot/jtreg/TEST.groups @@ -587,7 +587,8 @@ hotspot_metaspace = \ tier1_runtime_appcds = \ runtime/cds/appcds/aotCache/HelloAOTCache.java \ runtime/cds/appcds/aotCode \ - runtime/cds/appcds/HelloTest.java + runtime/cds/appcds/HelloTest.java \ + -runtime/cds/appcds/aotCode/AOTCodeFlags.java tier1_runtime_appcds_exclude = \ runtime/cds/appcds/ \ diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeCPUFeatureIncompatibilityTest.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeCPUFeatureIncompatibilityTest.java index e9e610330ad..aa7becdb6f8 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeCPUFeatureIncompatibilityTest.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeCPUFeatureIncompatibilityTest.java @@ -31,13 +31,9 @@ * @comment The test verifies AOT checks during VM startup and not code generation. * No need to run it with -Xcomp. * @library /test/lib /test/setup_aot - * @build AOTCodeCPUFeatureIncompatibilityTest JavacBenchApp + * @build AOTCodeCPUFeatureIncompatibilityTest HelloWorld * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app.jar - * JavacBenchApp - * JavacBenchApp$ClassFile - * JavacBenchApp$FileManager - * JavacBenchApp$SourceFile + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app.jar HelloWorld * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI AOTCodeCPUFeatureIncompatibilityTest */ @@ -98,9 +94,7 @@ public class AOTCodeCPUFeatureIncompatibilityTest { } @Override public String[] appCommandLine(RunMode runMode) { - return new String[] { - "JavacBenchApp", "10" - }; + return new String[] { "HelloWorld" }; } }.runAOTWorkflow("--two-step-training"); } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeCompressedOopsTest.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeCompressedOopsTest.java index 3b9458c14da..0fe11235749 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeCompressedOopsTest.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeCompressedOopsTest.java @@ -33,12 +33,8 @@ * No need to run it with -Xcomp. It takes a lot of time to complete all * subtests with this flag. * @library /test/lib /test/setup_aot - * @build AOTCodeCompressedOopsTest JavacBenchApp - * @run driver/timeout=480 jdk.test.lib.helpers.ClassFileInstaller -jar app.jar - * JavacBenchApp - * JavacBenchApp$ClassFile - * JavacBenchApp$FileManager - * JavacBenchApp$SourceFile + * @build AOTCodeCompressedOopsTest HelloWorld + * @run driver/timeout=480 jdk.test.lib.helpers.ClassFileInstaller -jar app.jar HelloWorld * @run driver/timeout=480 AOTCodeCompressedOopsTest */ @@ -149,9 +145,7 @@ public class AOTCodeCompressedOopsTest { @Override public String[] appCommandLine(RunMode runMode) { - return new String[] { - "JavacBenchApp", "10" - }; + return new String[] { "HelloWorld" }; } @Override diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeFlags.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeFlags.java index d3c6a23efa0..01b64a7fff0 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeFlags.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeFlags.java @@ -109,39 +109,44 @@ public class AOTCodeFlags { private static String gcName = null; public static void main(String... args) throws Exception { Tester t = new Tester(args.length == 0 ? null : args[0]); - // Run only 2 modes (0 - no AOT code, 1 - AOT adapters) until JDK-8357398 is fixed - for (int mode = 0; mode < 4; mode++) { - t.setTestMode(mode); - t.run(new String[] {"AOT", "--two-step-training"}); + // mode bits 0 and 1 encode AOTAdapterCaching and AOTStubCaching settings + // aMode is used for assembly run, pMode for production run + for (int aMode = 0; aMode < 4; aMode++) { + for (int pMode = 0; pMode < 4; pMode++) { + t.setTestMode(aMode, pMode); + t.run(new String[] {"AOT", "--two-step-training"}); + } } } static class Tester extends CDSAppTester { - private int testMode; + private int aMode, pMode; private String gcName; public Tester(String name) { super("AOTCodeFlags"); - testMode = 0; + aMode = 0; + pMode = 0; gcName = name; } - boolean isAdapterCachingOn() { - return (testMode & 0x1) != 0; + boolean isAdapterCachingOn(int mode) { + return (mode & 0x1) != 0; } - boolean isStubCachingOn() { - return (testMode & 0x2) != 0; + boolean isStubCachingOn(int mode) { + return (mode & 0x2) != 0; } - public void setTestMode(int mode) { - testMode = mode; + public void setTestMode(int aMode, int pMode) { + this.aMode = aMode; + this.pMode = pMode; } - public List getVMArgsForTestMode() { + public List getVMArgsForTestMode(int mode) { List list = new ArrayList(); list.add("-XX:+UnlockDiagnosticVMOptions"); - list.add(isAdapterCachingOn() ? "-XX:+AOTAdapterCaching" : "-XX:-AOTAdapterCaching"); - list.add(isStubCachingOn() ? "-XX:+AOTStubCaching" : "-XX:-AOTStubCaching"); + list.add(isAdapterCachingOn(mode) ? "-XX:+AOTAdapterCaching" : "-XX:-AOTAdapterCaching"); + list.add(isStubCachingOn(mode) ? "-XX:+AOTStubCaching" : "-XX:-AOTStubCaching"); return list; } @@ -170,79 +175,91 @@ public class AOTCodeFlags { @Override public String[] vmArgs(RunMode runMode) { + List args = getGCArgs(); + args.addAll(List.of("-Xlog:aot+codecache+init=debug", + "-Xlog:aot+codecache+exit=debug", + "-Xlog:aot+codecache+stubs=debug")); switch (runMode) { case RunMode.ASSEMBLY: - case RunMode.PRODUCTION: { - List args = getVMArgsForTestMode(); - args.addAll(List.of("-Xlog:aot+codecache+init=debug", - "-Xlog:aot+codecache+exit=debug")); - args.addAll(getGCArgs()); - return args.toArray(new String[0]); - } + args.addAll(getVMArgsForTestMode(aMode)); + break; + case RunMode.PRODUCTION: + args.addAll(getVMArgsForTestMode(pMode)); + break; + default: + break; } - List args = getGCArgs(); return args.toArray(new String[args.size()]); } @Override public String[] appCommandLine(RunMode runMode) { - return new String[] { - "JavacBenchApp", "10" - }; + return new String[] { "JavacBenchApp", "10" }; } @Override public void checkExecution(OutputAnalyzer out, RunMode runMode) throws Exception { - if (!isAdapterCachingOn() && !isStubCachingOn()) { // this is equivalent to completely disable AOT code cache - switch (runMode) { - case RunMode.ASSEMBLY: - case RunMode.PRODUCTION: + if (runMode == RunMode.ASSEMBLY) { + if (!isAdapterCachingOn(aMode) && !isStubCachingOn(aMode)) { // this is equivalent to completely disable AOT code cache out.shouldNotMatch("Adapters:\\s+total"); out.shouldNotMatch("Shared Blobs:\\s+total"); out.shouldNotMatch("C1 Blobs:\\s+total"); out.shouldNotMatch("C2 Blobs:\\s+total"); - break; - } - } else { - if (isAdapterCachingOn()) { - switch (runMode) { - case RunMode.ASSEMBLY: - case RunMode.PRODUCTION: - // AOTAdapterCaching is on, non-zero adapters should be stored/loaded - out.shouldMatch("Adapters:\\s+total=[1-9][0-9]+"); - break; - } } else { - switch (runMode) { - case RunMode.ASSEMBLY: - case RunMode.PRODUCTION: - // AOTAdapterCaching is off, no adapters should be stored/loaded + if (isAdapterCachingOn(aMode)) { + // AOTAdapterCaching is on, non-zero adapters should be stored + out.shouldMatch("Adapters:\\s+total=[1-9][0-9]+"); + } else { + // AOTAdapterCaching is off, no adapters should be stored out.shouldMatch("Adapters:\\s+total=0"); - break; } - } - if (isStubCachingOn()) { - switch (runMode) { - case RunMode.ASSEMBLY: - case RunMode.PRODUCTION: - // AOTStubCaching is on, non-zero stubs should be stored/loaded + if (isStubCachingOn(aMode)) { + // AOTStubCaching is on, non-zero stubs should be stored out.shouldMatch("Shared Blobs:\\s+total=[1-9][0-9]+"); out.shouldMatch("C1 Blobs:\\s+total=[1-9][0-9]+"); // we do not currently load or store C2 stubs // because we are seeing weird memory errors // when loading them -- see JDK-8357593 out.shouldMatch("C2 Blobs:\\s+total=0"); - break; - } - } else { - switch (runMode) { - case RunMode.ASSEMBLY: - case RunMode.PRODUCTION: - // AOTStubCaching is off, no stubs should be stored/loaded + } else { + // AOTStubCaching is off, no stubs should be stored out.shouldMatch("Shared Blobs:\\s+total=0"); out.shouldMatch("C1 Blobs:\\s+total=0"); out.shouldMatch("C2 Blobs:\\s+total=0"); - break; + } + } + } else if (runMode == RunMode.PRODUCTION) { + // Irrespective of assembly run mode, if both adapter and stub caching is disabled + // in production run, then it is equivalent to completely disabling AOT code cache + if (!isAdapterCachingOn(pMode) && !isStubCachingOn(pMode)) { + out.shouldNotMatch("Adapters:\\s+total"); + out.shouldNotMatch("Shared Blobs:\\s+total"); + out.shouldNotMatch("C1 Blobs:\\s+total"); + out.shouldNotMatch("C2 Blobs:\\s+total"); + } else { + // If AOT code cache is effectively disabled in the assembly run, then production run + // would emit empty code cache message. + if (!isAdapterCachingOn(aMode) && !isStubCachingOn(aMode)) { + if (isAdapterCachingOn(pMode) || isStubCachingOn(pMode)) { + out.shouldMatch("AOT Code Cache is empty"); + } + } else { + if (isAdapterCachingOn(aMode)) { + if (isAdapterCachingOn(pMode)) { + out.shouldMatch("Read blob.*kind=Adapter.*"); + } else { + out.shouldNotMatch("Read blob.*kind=Adapter.*"); + } + } + if (isStubCachingOn(aMode)) { + if (isStubCachingOn(pMode)) { + out.shouldMatch("Read blob.*kind=SharedBlob.*"); + out.shouldMatch("Read blob.*kind=C1Blob.*"); + } else { + out.shouldNotMatch("Read blob.*kind=SharedBlob.*"); + out.shouldNotMatch("Read blob.*kind=C1Blob.*"); + } + } } } } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeTest.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeTest.java new file mode 100644 index 00000000000..2afcd802fc5 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeTest.java @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/** + * @test id=g1 + * @requires vm.gc.G1 + * @summary Sanity test of AOTCodeCache + * @requires vm.cds.supports.aot.code.caching + * @requires vm.compiler1.enabled & vm.compiler2.enabled + * @comment Both C1 and C2 JIT compilers are required because the test verifies + * compiler's runtime blobs generation. + * @requires vm.opt.VerifyOops == null | vm.opt.VerifyOops == false + * @comment VerifyOops flag switch off AOT code generation. Skip it. + * @library /test/lib /test/setup_aot + * @build AOTCodeTest JavacBenchApp + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app.jar + * JavacBenchApp + * JavacBenchApp$ClassFile + * JavacBenchApp$FileManager + * JavacBenchApp$SourceFile + * @run driver/timeout=1500 AOTCodeTest G1 + */ +/** + * @test id=parallel + * @requires vm.gc.Parallel + * @summary Sanity test of AOTCodeCache + * @requires vm.cds.supports.aot.code.caching + * @requires vm.compiler1.enabled & vm.compiler2.enabled + * @comment Both C1 and C2 JIT compilers are required because the test verifies + * compiler's runtime blobs generation. + * @requires vm.opt.VerifyOops == null | vm.opt.VerifyOops == false + * @comment VerifyOops flag switch off AOT code generation. Skip it. + * @library /test/lib /test/setup_aot + * @build AOTCodeTest JavacBenchApp + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app.jar + * JavacBenchApp + * JavacBenchApp$ClassFile + * JavacBenchApp$FileManager + * JavacBenchApp$SourceFile + * @run driver/timeout=1500 AOTCodeTest Parallel + */ +/** + * @test id=serial + * @requires vm.gc.Serial + * @summary Sanity test of AOTCodeCache + * @requires vm.cds.supports.aot.code.caching + * @requires vm.compiler1.enabled & vm.compiler2.enabled + * @comment Both C1 and C2 JIT compilers are required because the test verifies + * compiler's runtime blobs generation. + * @requires vm.opt.VerifyOops == null | vm.opt.VerifyOops == false + * @comment VerifyOops flag switch off AOT code generation. Skip it. + * @library /test/lib /test/setup_aot + * @build AOTCodeTest JavacBenchApp + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app.jar + * JavacBenchApp + * JavacBenchApp$ClassFile + * JavacBenchApp$FileManager + * JavacBenchApp$SourceFile + * @run driver/timeout=1500 AOTCodeTest Serial + */ +/** + * @test id=shenandoah + * @requires vm.gc.Shenandoah + * @summary Sanity test of AOTCodeCache + * @requires vm.cds.supports.aot.code.caching + * @requires vm.compiler1.enabled & vm.compiler2.enabled + * @comment Both C1 and C2 JIT compilers are required because the test verifies + * compiler's runtime blobs generation. + * @requires vm.opt.VerifyOops == null | vm.opt.VerifyOops == false + * @comment VerifyOops flag switch off AOT code generation. Skip it. + * @library /test/lib /test/setup_aot + * @build AOTCodeTest JavacBenchApp + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app.jar + * JavacBenchApp + * JavacBenchApp$ClassFile + * JavacBenchApp$FileManager + * JavacBenchApp$SourceFile + * @run driver/timeout=1500 AOTCodeTest Shenandoah + */ +/** + * @test id=Z + * @requires vm.gc.Z + * @summary Sanity test of AOTCodeCache + * @requires vm.cds.supports.aot.code.caching + * @requires vm.compiler1.enabled & vm.compiler2.enabled + * @comment Both C1 and C2 JIT compilers are required because the test verifies + * compiler's runtime blobs generation. + * @requires vm.opt.VerifyOops == null | vm.opt.VerifyOops == false + * @comment VerifyOops flag switch off AOT code generation. Skip it. + * @library /test/lib /test/setup_aot + * @build AOTCodeTest JavacBenchApp + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app.jar + * JavacBenchApp + * JavacBenchApp$ClassFile + * JavacBenchApp$FileManager + * JavacBenchApp$SourceFile + * @run driver/timeout=1500 AOTCodeTest Z + */ + +import java.util.ArrayList; +import java.util.List; + +import jdk.test.lib.cds.CDSAppTester; +import jdk.test.lib.process.OutputAnalyzer; + +public class AOTCodeTest { + private static String gcName = null; + public static void main(String... args) throws Exception { + if (args.length == 0) { + throw new RuntimeException("Expected GC name"); + } + Tester t = new Tester(args[0]); + t.run(new String[] {"AOT", "--two-step-training"}); + } + + static class Tester extends CDSAppTester { + private String gcName; + + public Tester(String name) { + super("AOTCodeTest"); + gcName = name; + } + + public List getGCArgs() { + List args = new ArrayList(); + args.add("-Xmx100M"); + switch (gcName) { + case "G1": + case "Parallel": + case "Serial": + case "Shenandoah": + case "Z": + args.add("-XX:+Use" + gcName + "GC"); + return args; + default: + throw new RuntimeException("Unexpected GC name " + gcName); + } + } + + @Override + public String classpath(RunMode runMode) { + return "app.jar"; + } + + @Override + public String[] vmArgs(RunMode runMode) { + List args = getGCArgs(); + // Add flags for logs + args.addAll(List.of("-Xlog:aot+codecache+init=debug", + "-Xlog:aot+codecache+exit=debug", + "-Xlog:aot+codecache+stubs=debug")); + // Add diagnostic flags + args.addAll(List.of("-XX:+UnlockDiagnosticVMOptions", + "-XX:+AbortVMOnAOTCodeFailure")); + return args.toArray(new String[args.size()]); + } + + @Override + public String[] appCommandLine(RunMode runMode) { + return new String[] { "JavacBenchApp", "10" }; + } + + @Override + public void checkExecution(OutputAnalyzer out, RunMode runMode) throws Exception { + if (runMode == RunMode.ASSEMBLY) { + out.shouldMatch("aot,codecache,exit.*\\s+AOT code cache size: [1-9]\\d+ bytes"); + } else if (runMode == RunMode.PRODUCTION) { + out.shouldMatch("aot,codecache,init.*\\s+Loaded [1-9]\\d+ AOT code entries from AOT Code Cache"); + out.shouldMatch("aot,codecache,stubs.*\\s+Read blob.*kind=Adapter.*"); + out.shouldMatch("aot,codecache,stubs.*\\s+Read blob.*kind=SharedBlob.*"); + out.shouldMatch("aot,codecache,stubs.*\\s+Read blob.*kind=C1Blob.*"); + } + } + } +} diff --git a/test/setup_aot/HelloWorld.java b/test/setup_aot/HelloWorld.java new file mode 100644 index 00000000000..e243dfb4e8e --- /dev/null +++ b/test/setup_aot/HelloWorld.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +public class HelloWorld { + public static void main(String args[]) { + System.out.println("HelloWorld"); + } +} From 21213024501cb3f19b2c42bd56f5553807dace9b Mon Sep 17 00:00:00 2001 From: Leo Korinth Date: Wed, 15 Apr 2026 14:50:24 +0000 Subject: [PATCH 298/359] 8380164: Fix implicit conversion in nativeInst_aarch64.hpp Co-authored-by: Andrew Haley Reviewed-by: aph, aseoane --- src/hotspot/cpu/aarch64/nativeInst_aarch64.hpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/hotspot/cpu/aarch64/nativeInst_aarch64.hpp b/src/hotspot/cpu/aarch64/nativeInst_aarch64.hpp index fc7274714ad..ab9896fa426 100644 --- a/src/hotspot/cpu/aarch64/nativeInst_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/nativeInst_aarch64.hpp @@ -97,7 +97,7 @@ protected: #define MACOS_WX_WRITE MACOS_AARCH64_ONLY(os::thread_wx_enable_write()) void set_char_at(int offset, char c) { MACOS_WX_WRITE; *addr_at(offset) = (u_char)c; } void set_int_at(int offset, jint i) { MACOS_WX_WRITE; *(jint*)addr_at(offset) = i; } - void set_uint_at(int offset, jint i) { MACOS_WX_WRITE; *(juint*)addr_at(offset) = i; } + void set_uint_at(int offset, juint i) { MACOS_WX_WRITE; *(juint*)addr_at(offset) = i; } void set_ptr_at(int offset, address ptr) { MACOS_WX_WRITE; *(address*)addr_at(offset) = ptr; } void set_oop_at(int offset, oop o) { MACOS_WX_WRITE; *(oop*)addr_at(offset) = o; } #undef MACOS_WX_WRITE @@ -178,13 +178,11 @@ public: address destination() const; void set_destination(address dest) { - int offset = dest - instruction_address(); - unsigned int insn = 0b100101 << 26; + int64_t offset = dest - instruction_address(); + juint insn = 0b100101u << 26u; assert((offset & 3) == 0, "should be"); - offset >>= 2; - offset &= (1 << 26) - 1; // mask off insn part - insn |= offset; - set_int_at(displacement_offset, insn); + Instruction_aarch64::spatch(reinterpret_cast
(&insn), 25, 0, offset >> 2); + set_uint_at(displacement_offset, insn); } void verify_alignment() { ; } From 29434cc6512819a0b0e7f831fee8623995cbc5bc Mon Sep 17 00:00:00 2001 From: Vladimir Ivanov Date: Wed, 15 Apr 2026 16:37:37 +0000 Subject: [PATCH 299/359] 8376421: C2: Missing branch on SubTypeCheck node Reviewed-by: kvn, dfenacci --- src/hotspot/share/opto/parse2.cpp | 20 +++-- ...stSubTypeCheckInterfaceNotImplemented.java | 76 +++++++++++++++++++ 2 files changed, 88 insertions(+), 8 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/types/TestSubTypeCheckInterfaceNotImplemented.java diff --git a/src/hotspot/share/opto/parse2.cpp b/src/hotspot/share/opto/parse2.cpp index ae20418942d..d732e6f04e1 100644 --- a/src/hotspot/share/opto/parse2.cpp +++ b/src/hotspot/share/opto/parse2.cpp @@ -1833,17 +1833,21 @@ void Parse::sharpen_type_after_if(BoolTest::mask btest, &obj, &cast_type)) { assert(obj != nullptr && cast_type != nullptr, "missing type check info"); const Type* obj_type = _gvn.type(obj); - const TypeOopPtr* tboth = obj_type->join_speculative(cast_type)->isa_oopptr(); - if (tboth != nullptr && tboth != obj_type && tboth->higher_equal(obj_type)) { + const Type* tboth = obj_type->filter_speculative(cast_type); + assert(tboth->higher_equal(obj_type) && tboth->higher_equal(cast_type), "sanity"); + if (tboth == Type::TOP && KillPathsReachableByDeadTypeNode) { + // Let dead type node cleaning logic prune effectively dead path for us. + // CheckCastPP::Value() == TOP and it will trigger the cleanup during GVN. + // Don't materialize the cast when cleanup is disabled, because + // it kills data and control leaving IR in broken state. + tboth = cast_type; + } + if (tboth != Type::TOP && tboth != obj_type) { int obj_in_map = map()->find_edge(obj); - JVMState* jvms = this->jvms(); if (obj_in_map >= 0 && - (jvms->is_loc(obj_in_map) || jvms->is_stk(obj_in_map))) { + (jvms()->is_loc(obj_in_map) || jvms()->is_stk(obj_in_map))) { TypeNode* ccast = new CheckCastPPNode(control(), obj, tboth); - const Type* tcc = ccast->as_Type()->type(); - assert(tcc != obj_type && tcc->higher_equal(obj_type), "must improve"); - // Delay transform() call to allow recovery of pre-cast value - // at the control merge. + // Delay transform() call to allow recovery of pre-cast value at the control merge. _gvn.set_type_bottom(ccast); record_for_igvn(ccast); // Here's the payoff. diff --git a/test/hotspot/jtreg/compiler/types/TestSubTypeCheckInterfaceNotImplemented.java b/test/hotspot/jtreg/compiler/types/TestSubTypeCheckInterfaceNotImplemented.java new file mode 100644 index 00000000000..f2828257a2e --- /dev/null +++ b/test/hotspot/jtreg/compiler/types/TestSubTypeCheckInterfaceNotImplemented.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8376421 + * @summary "C2: Missing branch on SubTypeCheck node" + * + * @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions + * -XX:+KillPathsReachableByDeadTypeNode + * compiler.types.TestSubTypeCheckInterfaceNotImplemented + * + * @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions + * -XX:-KillPathsReachableByDeadTypeNode + * compiler.types.TestSubTypeCheckInterfaceNotImplemented + */ + +package compiler.types; + +public class TestSubTypeCheckInterfaceNotImplemented { + static abstract class A {} + static abstract class B extends A {} + static final class C extends B {} + + interface I {} + static final class BJ1 extends A implements I {} + static final class BJ2 extends A implements I {} + + static boolean testHelper2(B o) { + return true; + } + static boolean testHelper1(Object o) { + if (o instanceof B) { + return testHelper2((B)o); // a call to place "o" on JVMS, so the map is updated after the check + } else { + return false; + } + } + + static boolean test(A a) { + if (a instanceof I) { + return testHelper1((I)a); // "a" always fails instanceof check against B + } else { + return false; + } + } + + public static void main(String[] args) { + for (int i = 0; i < 20_000; i++) { + testHelper1(new C()); // pollute profile + + test(new BJ1()); test(new BJ2()); test(new C()); + } + } +} From 5acbf8baea3f1a982bdba29b51c8531caa919748 Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Wed, 15 Apr 2026 19:02:28 +0000 Subject: [PATCH 300/359] 8381871: GenShen: ShenandoahGCHeuristics flag not reset after ignoring non-adaptive value Reviewed-by: xpeng, kdnilsen, ysr, serb, wkemper --- .../gc/shenandoah/shenandoahArguments.cpp | 1 + .../options/TestGenerationalHeuristics.java | 84 +++++++++++++++++++ 2 files changed, 85 insertions(+) create mode 100644 test/hotspot/jtreg/gc/shenandoah/options/TestGenerationalHeuristics.java diff --git a/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp b/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp index c1fa4b964b7..e9d6a686694 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp @@ -200,6 +200,7 @@ void ShenandoahArguments::initialize() { && strcmp(ShenandoahGCHeuristics, "adaptive") != 0) { log_warning(gc)("Ignoring -XX:ShenandoahGCHeuristics input: %s, because generational shenandoah only" " supports adaptive heuristics", ShenandoahGCHeuristics); + FLAG_SET_ERGO(ShenandoahGCHeuristics, "adaptive"); } FullGCForwarding::initialize_flags(MaxHeapSize); diff --git a/test/hotspot/jtreg/gc/shenandoah/options/TestGenerationalHeuristics.java b/test/hotspot/jtreg/gc/shenandoah/options/TestGenerationalHeuristics.java new file mode 100644 index 00000000000..822c3806347 --- /dev/null +++ b/test/hotspot/jtreg/gc/shenandoah/options/TestGenerationalHeuristics.java @@ -0,0 +1,84 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * @test id=generational + * @bug 8381871 + * @summary Test that ShenandoahGCHeuristics is always adaptive in generational mode + * @requires vm.gc.Shenandoah + * @library /test/lib + * @run driver TestGenerationalHeuristics + */ + +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.process.OutputAnalyzer; + +public class TestGenerationalHeuristics { + public static void main(String[] args) throws Exception { + { + OutputAnalyzer output = ProcessTools.executeLimitedTestJava( + "-XX:+UseShenandoahGC", + "-XX:ShenandoahGCMode=generational", + "-XX:ShenandoahGCHeuristics=adaptive", + "-XX:+PrintFlagsFinal", + "-version"); + output.shouldMatch("ShenandoahGCHeuristics(.*)= adaptive "); + output.shouldHaveExitValue(0); + } + + { + OutputAnalyzer output = ProcessTools.executeLimitedTestJava( + "-XX:+UseShenandoahGC", + "-XX:ShenandoahGCMode=generational", + "-XX:ShenandoahGCHeuristics=static", + "-XX:+PrintFlagsFinal", + "-version"); + output.shouldMatch("ShenandoahGCHeuristics(.*)= adaptive "); + output.shouldHaveExitValue(0); + } + + { + OutputAnalyzer output = ProcessTools.executeLimitedTestJava( + "-XX:+UseShenandoahGC", + "-XX:ShenandoahGCMode=generational", + "-XX:ShenandoahGCHeuristics=aggressive", + "-XX:+PrintFlagsFinal", + "-version"); + output.shouldMatch("ShenandoahGCHeuristics(.*)= adaptive "); + output.shouldHaveExitValue(0); + } + + { + OutputAnalyzer output = ProcessTools.executeLimitedTestJava( + "-XX:+UseShenandoahGC", + "-XX:ShenandoahGCMode=generational", + "-XX:ShenandoahGCHeuristics=compact", + "-XX:+PrintFlagsFinal", + "-version"); + output.shouldMatch("ShenandoahGCHeuristics(.*)= adaptive "); + output.shouldHaveExitValue(0); + } + } + +} From 2a8e3b8e66651cc6ba2f9c53aae32dde41e72a21 Mon Sep 17 00:00:00 2001 From: Vladimir Kozlov Date: Wed, 15 Apr 2026 19:02:58 +0000 Subject: [PATCH 301/359] 8382174: Clarify the meaning of address cast in ADD() macro Reviewed-by: aseoane, adinn, asmehra, dfenacci --- .../cpu/aarch64/stubGenerator_aarch64.cpp | 2 +- .../cpu/aarch64/stubRoutines_aarch64.cpp | 7 ++-- src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp | 2 +- .../x86/stubGenerator_x86_64_constants.cpp | 5 +-- .../cpu/x86/stubGenerator_x86_64_exp.cpp | 15 +++++---- .../cpu/x86/stubGenerator_x86_64_fmod.cpp | 2 +- .../cpu/x86/stubGenerator_x86_64_ghash.cpp | 2 +- .../cpu/x86/stubGenerator_x86_64_log.cpp | 32 ++++++++++-------- .../cpu/x86/stubGenerator_x86_64_poly1305.cpp | 2 +- .../x86/stubGenerator_x86_64_poly_mont.cpp | 2 +- .../cpu/x86/stubGenerator_x86_64_pow.cpp | 33 +++++++++++-------- .../cpu/x86/stubGenerator_x86_64_sha3.cpp | 2 +- .../cpu/x86/stubGenerator_x86_64_sin.cpp | 2 +- .../cpu/x86/stubGenerator_x86_64_sinh.cpp | 26 ++++++++------- .../cpu/x86/stubGenerator_x86_64_tan.cpp | 8 +++-- .../cpu/x86/stubGenerator_x86_64_tanh.cpp | 22 ++++++++----- src/hotspot/cpu/x86/stubRoutines_x86.cpp | 2 +- 17 files changed, 93 insertions(+), 73 deletions(-) diff --git a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp index 5d9b2f1d826..fddb37b7b8d 100644 --- a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp @@ -12825,7 +12825,7 @@ class StubGenerator: public StubCodeGenerator { #if INCLUDE_CDS static void init_AOTAddressTable(GrowableArray
& external_addresses) { // external data defined in this file -#define ADD(addr) external_addresses.append((address)addr); +#define ADD(addr) external_addresses.append((address)(addr)); ADD(_sha256_round_consts); ADD(_sha512_round_consts); ADD(_sha3_round_consts); diff --git a/src/hotspot/cpu/aarch64/stubRoutines_aarch64.cpp b/src/hotspot/cpu/aarch64/stubRoutines_aarch64.cpp index aaf31d4f911..f02b681ca10 100644 --- a/src/hotspot/cpu/aarch64/stubRoutines_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/stubRoutines_aarch64.cpp @@ -435,10 +435,8 @@ void StubRoutines::init_AOTAddressTable() { AOTCodeCache::publish_external_addresses(external_addresses); } - -#define ADD(addr) external_addresses.append((address)addr); - void StubRoutines::aarch64::init_AOTAddressTable(GrowableArray
& external_addresses) { +#define ADD(addr) external_addresses.append((address)(addr)); ADD(_kyberConsts); ADD(_dilithiumConsts); // this is added in generic code @@ -449,7 +447,6 @@ void StubRoutines::aarch64::init_AOTAddressTable(GrowableArray
& externa ADD(_dcos_coef); ADD(_two_over_pi); ADD(_pio2); -} - #undef ADD +} #endif // INCLUDE_CDS diff --git a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp index 29925e71aaf..5c05b3702bb 100644 --- a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp @@ -74,7 +74,7 @@ static jlong *double_signflip_pool = double_quadword(&fp_signmask_pool[4*2], (jl #if INCLUDE_CDS // publish external addresses defined in this file void LIR_Assembler::init_AOTAddressTable(GrowableArray
& external_addresses) { -#define ADD(addr) external_addresses.append((address)addr); +#define ADD(addr) external_addresses.append((address)(addr)); ADD(float_signmask_pool); ADD(double_signmask_pool); ADD(float_signflip_pool); diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_constants.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_constants.cpp index 45c13b7b397..19e1ca680b3 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_constants.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_constants.cpp @@ -247,8 +247,9 @@ void StubGenerator::init_AOTAddressTable_constants(GrowableArray
& exter ADD(_SC_2); ADD(_SC_3); ADD(_SC_4); - ADD(_PI_4); - ADD(((address)_PI_4+8)); + // Use value which was already cast to (address): StubGenerator::PI_4; + ADD(PI_4); + ADD(PI_4 + 8); ADD(_PI32INV); ADD(_NEG_ZERO); ADD(_P_1); diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_exp.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_exp.cpp index 2ed9858bf0c..3c8babcbecf 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_exp.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_exp.cpp @@ -397,13 +397,14 @@ address StubGenerator::generate_libmExp() { #if INCLUDE_CDS void StubGenerator::init_AOTAddressTable_exp(GrowableArray
& external_addresses) { -#define ADD(addr) external_addresses.append((address)addr); - ADD(_cv); - ADD(((address)_cv+16)); - ADD(((address)_cv+32)); - ADD(((address)_cv+48)); - ADD(((address)_cv+64)); - ADD(((address)_cv+80)); +#define ADD(addr) external_addresses.append((address)(addr)); + address cv = (address)_cv; + ADD(cv); + ADD(cv + 16); + ADD(cv + 32); + ADD(cv + 48); + ADD(cv + 64); + ADD(cv + 80); ADD(_mmask); ADD(_bias); ADD(_Tbl_addr); diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_fmod.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_fmod.cpp index f73c8ed459e..f53985a13b7 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_fmod.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_fmod.cpp @@ -537,7 +537,7 @@ address StubGenerator::generate_libmFmod() { #if INCLUDE_CDS void StubGenerator::init_AOTAddressTable_fmod(GrowableArray
& external_addresses) { -#define ADD(addr) external_addresses.append((address)addr); +#define ADD(addr) external_addresses.append((address)(addr)); ADD(CONST_NaN); ADD(CONST_1p260); ADD(CONST_MAX); diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_ghash.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_ghash.cpp index 557fe623351..9ebab07589e 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_ghash.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_ghash.cpp @@ -558,7 +558,7 @@ void StubGenerator::generateHtbl_eight_blocks(Register htbl) { #if INCLUDE_CDS void StubGenerator::init_AOTAddressTable_ghash(GrowableArray
& external_addresses) { -#define ADD(addr) external_addresses.append((address)addr); +#define ADD(addr) external_addresses.append((address)(addr)); ADD(GHASH_SHUFFLE_MASK); ADD(GHASH_LONG_SWAP_MASK); ADD(GHASH_BYTE_SWAP_MASK); diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_log.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_log.cpp index 8849597c94b..07683a51e3d 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_log.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_log.cpp @@ -729,22 +729,28 @@ address StubGenerator::generate_libmLog10() { #if INCLUDE_CDS void StubGenerator::init_AOTAddressTable_log(GrowableArray
& external_addresses) { -#define ADD(addr) external_addresses.append((address)addr); +#define ADD(addr) external_addresses.append((address)(addr)); + address log2 = (address)_log2; + address coeff = (address)_coeff; + address LOG10_E = (address)_LOG10_E; + address log2_log10 = (address)_log2_log10; + address coeff_log10 = (address)_coeff_log10; + ADD(_L_tbl); - ADD(_log2); - ADD(((address)_log2+8)); - ADD(_coeff); - ADD(((address)_coeff+16)); - ADD(((address)_coeff+32)); + ADD(log2); + ADD(log2 + 8); + ADD(coeff); + ADD(coeff + 16); + ADD(coeff + 32); ADD(_HIGHSIGMASK_log10); - ADD(_LOG10_E); - ADD(((address)_LOG10_E+8)); + ADD(LOG10_E); + ADD(LOG10_E + 8); ADD(_L_tbl_log10); - ADD(_log2_log10); - ADD(((address)_log2_log10+8)); - ADD(_coeff_log10); - ADD(((address)_coeff_log10+16)); - ADD(((address)_coeff_log10+32)); + ADD(log2_log10); + ADD(log2_log10 + 8); + ADD(coeff_log10); + ADD(coeff_log10 + 16); + ADD(coeff_log10 + 32); #undef ADD } #endif // INCLUDE_CDS diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_poly1305.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_poly1305.cpp index 1d0e961c82d..ea7e6d64254 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_poly1305.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_poly1305.cpp @@ -1709,7 +1709,7 @@ void StubGenerator::poly1305_msg_mul_reduce_vec4_avx2( #if INCLUDE_CDS void StubGenerator::init_AOTAddressTable_poly1305(GrowableArray
& external_addresses) { -#define ADD(addr) external_addresses.append((address)addr); +#define ADD(addr) external_addresses.append((address)(addr)); ADD(POLY1305_PAD_MSG); ADD(POLY1305_MASK42); ADD(POLY1305_MASK44); diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_poly_mont.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_poly_mont.cpp index 4648fe03aa0..308a8042993 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_poly_mont.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_poly_mont.cpp @@ -788,7 +788,7 @@ address StubGenerator::generate_intpoly_assign() { #if INCLUDE_CDS void StubGenerator::init_AOTAddressTable_poly_mont(GrowableArray
& external_addresses) { -#define ADD(addr) external_addresses.append((address)addr); +#define ADD(addr) external_addresses.append((address)(addr)); // use accessors to retrieve all correct addresses ADD(shift_1L()); ADD(shift_1R()); diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_pow.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_pow.cpp index 5ff09e2b377..a9a6dc10da4 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_pow.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_pow.cpp @@ -1875,25 +1875,30 @@ address StubGenerator::generate_libmPow() { #if INCLUDE_CDS void StubGenerator::init_AOTAddressTable_pow(GrowableArray
& external_addresses) { -#define ADD(addr) external_addresses.append((address)addr); +#define ADD(addr) external_addresses.append((address)(addr)); + address HIGHMASK_Y = (address)_HIGHMASK_Y; + address e_coeff = (address)_e_coeff; + address coeff_h = (address)_coeff_h; + address coeff_pow = (address)_coeff_pow; + ADD(_HIGHSIGMASK); ADD(_LOG2_E); - ADD(_HIGHMASK_Y); - ADD((address)_HIGHMASK_Y+8); + ADD(HIGHMASK_Y); + ADD(HIGHMASK_Y + 8); ADD(_T_exp); - ADD(_e_coeff); - ADD((address)_e_coeff+16); - ADD((address)_e_coeff+32); - ADD(_coeff_h); - ADD((address)_coeff_h+8); + ADD(e_coeff); + ADD(e_coeff + 16); + ADD(e_coeff + 32); + ADD(coeff_h); + ADD(coeff_h + 8); ADD(_HIGHMASK_LOG_X); ADD(_HALFMASK); - ADD(_coeff_pow); - ADD((address)_coeff_pow+16); - ADD((address)_coeff_pow+32); - ADD((address)_coeff_pow+48); - ADD((address)_coeff_pow+64); - ADD((address)_coeff_pow+80); + ADD(coeff_pow); + ADD(coeff_pow + 16); + ADD(coeff_pow + 32); + ADD(coeff_pow + 48); + ADD(coeff_pow + 64); + ADD(coeff_pow + 80); ADD(_L_tbl_pow); ADD(_log2_pow); ADD(_DOUBLE2); diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_sha3.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_sha3.cpp index 075d25dcac8..58f81652a0c 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_sha3.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_sha3.cpp @@ -530,7 +530,7 @@ void StubGenerator::generate_sha3_stubs() { #if INCLUDE_CDS void StubGenerator::init_AOTAddressTable_sha3(GrowableArray
& external_addresses) { -#define ADD(addr) external_addresses.append((address)addr); +#define ADD(addr) external_addresses.append((address)(addr)); ADD(round_constsAddr()); ADD(permsAndRotsAddr()); #undef ADD diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_sin.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_sin.cpp index eaeaea2c566..00c759a369b 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_sin.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_sin.cpp @@ -661,7 +661,7 @@ address StubGenerator::generate_libmSin() { #if INCLUDE_CDS void StubGenerator::init_AOTAddressTable_sin(GrowableArray
& external_addresses) { -#define ADD(addr) external_addresses.append((address)addr); +#define ADD(addr) external_addresses.append((address)(addr)); ADD(_ALL_ONES); #undef ADD } diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_sinh.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_sinh.cpp index f6e1d241948..9969866cfc7 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_sinh.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_sinh.cpp @@ -535,21 +535,25 @@ address StubGenerator::generate_libmSinh() { #if INCLUDE_CDS void StubGenerator::init_AOTAddressTable_sinh(GrowableArray
& external_addresses) { -#define ADD(addr) external_addresses.append((address)addr); - ADD(_L2E); - ADD(_L2E + 8); +#define ADD(addr) external_addresses.append((address)(addr)); + address L2E = (address)_L2E; + address cv = (address)_cv; + address pv = (address)_pv; + + ADD(L2E); + ADD(L2E + 8); ADD(_HALFMASK); ADD(_Shifter); - ADD(_cv); - ADD(_cv + 16); - ADD(_cv + 32); - ADD(_cv + 48); - ADD(_cv + 64); + ADD(cv); + ADD(cv + 16); + ADD(cv + 32); + ADD(cv + 48); + ADD(cv + 64); ADD(_T2f); ADD(_T2_neg_f); - ADD(_pv); - ADD(_pv + 16); - ADD(_pv + 32); + ADD(pv); + ADD(pv + 16); + ADD(pv + 32); ADD(_MASK3); #undef ADD } diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_tan.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_tan.cpp index 3bfa5a7277f..9f91b9e8f84 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_tan.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_tan.cpp @@ -1041,7 +1041,9 @@ address StubGenerator::generate_libmTan() { #if INCLUDE_CDS void StubGenerator::init_AOTAddressTable_tan(GrowableArray
& external_addresses) { -#define ADD(addr) external_addresses.append((address)addr); +#define ADD(addr) external_addresses.append((address)(addr)); + address PI_4_tan = (address)_PI_4_tan; + ADD(_MUL16); ADD(_sign_mask_tan); ADD(_PI32INV_tan); @@ -1055,8 +1057,8 @@ void StubGenerator::init_AOTAddressTable_tan(GrowableArray
& external_ad ADD(_Q_7_tan); ADD(_Q_5_tan); ADD(_Q_3_tan); - ADD(_PI_4_tan); - ADD(((address)_PI_4_tan+8)); + ADD(PI_4_tan); + ADD(PI_4_tan + 8); ADD(_QQ_2_tan); #undef ADD } diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_tanh.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_tanh.cpp index dcf5f3eb824..4f2fe8a460b 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_tanh.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_tanh.cpp @@ -511,20 +511,24 @@ address StubGenerator::generate_libmTanh() { #if INCLUDE_CDS void StubGenerator::init_AOTAddressTable_tanh(GrowableArray
& external_addresses) { -#define ADD(addr) external_addresses.append((address)addr); - ADD(_L2E); - ADD(_L2E + 8); +#define ADD(addr) external_addresses.append((address)(addr)); + address L2E = (address)_L2E; + address cv = (address)_cv; + address pv = (address)_pv; + + ADD(L2E); + ADD(L2E + 8); ADD(_HALFMASK); ADD(_ONEMASK); ADD(_TWOMASK); ADD(_Shifter); - ADD(_cv); - ADD(_cv + 16); - ADD(_cv + 32); + ADD(cv); + ADD(cv + 16); + ADD(cv + 32); ADD(_T2_neg_f); - ADD(_pv); - ADD(_pv + 16); - ADD(_pv + 32); + ADD(pv); + ADD(pv + 16); + ADD(pv + 32); ADD(_MASK3); ADD(_RMASK); #undef ADD diff --git a/src/hotspot/cpu/x86/stubRoutines_x86.cpp b/src/hotspot/cpu/x86/stubRoutines_x86.cpp index aaee01437af..ce11925dde2 100644 --- a/src/hotspot/cpu/x86/stubRoutines_x86.cpp +++ b/src/hotspot/cpu/x86/stubRoutines_x86.cpp @@ -439,7 +439,7 @@ void StubRoutines::init_AOTAddressTable() { // publish addresses of external data defined in this file which may // be referenced from stub or code void StubRoutines::x86::init_AOTAddressTable(GrowableArray
& external_addresses) { -#define ADD(addr) external_addresses.append((address)addr); +#define ADD(addr) external_addresses.append((address)(addr)); ADD(&_mxcsr_std); ADD(&_mxcsr_rz); ADD(crc_by128_masks_addr()); From a2e840fd7413cbcbd663a30cb5681557e6142319 Mon Sep 17 00:00:00 2001 From: Rui Li Date: Wed, 15 Apr 2026 19:03:28 +0000 Subject: [PATCH 302/359] 8342786: Shenandoah: Emit AllocationRequiringGC jfr events Reviewed-by: kdnilsen, serb, wkemper --- .../gc/shenandoah/shenandoahController.cpp | 6 ++- ...tressAllocationGCEventsWithShenandoah.java | 49 +++++++++++++++++++ ...ssBigAllocationGCEventsWithShenandoah.java | 49 +++++++++++++++++++ 3 files changed, 102 insertions(+), 2 deletions(-) create mode 100644 test/hotspot/jtreg/gc/stress/jfr/TestStressAllocationGCEventsWithShenandoah.java create mode 100644 test/hotspot/jtreg/gc/stress/jfr/TestStressBigAllocationGCEventsWithShenandoah.java diff --git a/src/hotspot/share/gc/shenandoah/shenandoahController.cpp b/src/hotspot/share/gc/shenandoah/shenandoahController.cpp index 50aabad7d42..0096aad2570 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahController.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahController.cpp @@ -23,13 +23,13 @@ * */ +#include "gc/shared/allocTracer.hpp" #include "gc/shared/gc_globals.hpp" #include "gc/shenandoah/shenandoahCollectorPolicy.hpp" #include "gc/shenandoah/shenandoahController.hpp" #include "gc/shenandoah/shenandoahHeap.hpp" #include "gc/shenandoah/shenandoahHeapRegion.inline.hpp" - void ShenandoahController::update_gc_id() { _gc_id.add_then_fetch((size_t)1); } @@ -45,10 +45,12 @@ void ShenandoahController::handle_alloc_failure(const ShenandoahAllocRequest& re const GCCause::Cause cause = is_humongous ? GCCause::_shenandoah_humongous_allocation_failure : GCCause::_allocation_failure; ShenandoahHeap* const heap = ShenandoahHeap::heap(); + size_t req_byte = req.size() * HeapWordSize; if (heap->cancel_gc(cause)) { - log_info(gc)("Failed to allocate %s, " PROPERFMT, req.type_string(), PROPERFMTARGS(req.size() * HeapWordSize)); + log_info(gc)("Failed to allocate %s, " PROPERFMT, req.type_string(), PROPERFMTARGS(req_byte)); request_gc(cause); } + AllocTracer::send_allocation_requiring_gc_event(req_byte, checked_cast(get_gc_id())); if (block) { MonitorLocker ml(&_alloc_failure_waiters_lock); diff --git a/test/hotspot/jtreg/gc/stress/jfr/TestStressAllocationGCEventsWithShenandoah.java b/test/hotspot/jtreg/gc/stress/jfr/TestStressAllocationGCEventsWithShenandoah.java new file mode 100644 index 00000000000..743e59bca61 --- /dev/null +++ b/test/hotspot/jtreg/gc/stress/jfr/TestStressAllocationGCEventsWithShenandoah.java @@ -0,0 +1,49 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +package jdk.jfr.event.gc.detailed; + +/** + * @test id=default + * @key randomness + * @requires vm.hasJFR + * @requires vm.gc.Shenandoah + * @library /test/lib /test/jdk + * @run main/othervm -XX:+UseShenandoahGC -Xmx64m -XX:ActiveProcessorCount=1 jdk.jfr.event.gc.detailed.TestStressAllocationGCEventsWithShenandoah + */ + + /** + * @test id=generational + * @key randomness + * @requires vm.hasJFR + * @requires vm.gc.Shenandoah + * @library /test/lib /test/jdk + * @run main/othervm -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational -Xmx64m -XX:ActiveProcessorCount=1 jdk.jfr.event.gc.detailed.TestStressAllocationGCEventsWithShenandoah + */ +public class TestStressAllocationGCEventsWithShenandoah { + + public static void main(String[] args) throws Exception { + new StressAllocationGCEvents().run(args); + } +} diff --git a/test/hotspot/jtreg/gc/stress/jfr/TestStressBigAllocationGCEventsWithShenandoah.java b/test/hotspot/jtreg/gc/stress/jfr/TestStressBigAllocationGCEventsWithShenandoah.java new file mode 100644 index 00000000000..cb7e4b5d1ee --- /dev/null +++ b/test/hotspot/jtreg/gc/stress/jfr/TestStressBigAllocationGCEventsWithShenandoah.java @@ -0,0 +1,49 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +package jdk.jfr.event.gc.detailed; + +/** + * @test id=default + * @key randomness + * @requires vm.hasJFR + * @requires vm.gc.Shenandoah + * @library /test/lib /test/jdk + * @run main/othervm -XX:+UseShenandoahGC -Xmx256m -XX:ActiveProcessorCount=1 jdk.jfr.event.gc.detailed.TestStressBigAllocationGCEventsWithShenandoah 1048576 + */ + + /** + * @test id=generational + * @key randomness + * @requires vm.hasJFR + * @requires vm.gc.Shenandoah + * @library /test/lib /test/jdk + * @run main/othervm -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational -Xmx256m -XX:ActiveProcessorCount=1 jdk.jfr.event.gc.detailed.TestStressBigAllocationGCEventsWithShenandoah 1048576 + */ +public class TestStressBigAllocationGCEventsWithShenandoah { + + public static void main(String[] args) throws Exception { + new StressAllocationGCEvents().run(args); + } +} From f87bb766a79a4f33a5ac9dd3337d31368c1d5b8f Mon Sep 17 00:00:00 2001 From: Chris Plummer Date: Wed, 15 Apr 2026 19:35:52 +0000 Subject: [PATCH 303/359] 8381385: nsk/jdi/ClassLoaderReference/visibleClasses/visibleclasses002/ fails with --enable-preview and Java Usage Tracker enabled Reviewed-by: dholmes, lmesnik --- .../visibleClasses/visibleclasses002.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassLoaderReference/visibleClasses/visibleclasses002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassLoaderReference/visibleClasses/visibleclasses002.java index 8fe41faa886..78cbe664da3 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassLoaderReference/visibleClasses/visibleclasses002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ClassLoaderReference/visibleClasses/visibleclasses002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -138,7 +138,9 @@ public class visibleclasses002 { } } } catch (ClassNotLoadedException e) { - throw new Failure("Unexpected ClassNotLoadedException while getting componentType() of : " + refType); + // ArrayType.componentType() can throw ClassNotLoadedException if the + // type is loaded but not yet prepared. Just swallow the exception. + display("ClassNotLoadedException while getting componentType() of " + refType); } } From f2289d84d3b99686e90756921738d406f543337f Mon Sep 17 00:00:00 2001 From: Chris Plummer Date: Wed, 15 Apr 2026 21:35:02 +0000 Subject: [PATCH 304/359] 8381609: com/sun/jdi/EATests.java should not synchronize on an Integer instance Reviewed-by: rrich, phubner, lmesnik, sspitsyn --- test/jdk/com/sun/jdi/EATests.java | 42 +------------------------------ 1 file changed, 1 insertion(+), 41 deletions(-) diff --git a/test/jdk/com/sun/jdi/EATests.java b/test/jdk/com/sun/jdi/EATests.java index 3a936f288cc..f5289e6b011 100644 --- a/test/jdk/com/sun/jdi/EATests.java +++ b/test/jdk/com/sun/jdi/EATests.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2020, 2025 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -80,20 +81,6 @@ * -XX:-DoEscapeAnalysis -XX:-EliminateAllocations -XX:+EliminateLocks -XX:+EliminateNestedLocks * -XX:+IgnoreUnrecognizedVMOptions -XX:+DeoptimizeObjectsALot * - * @bug 8324881 - * @comment Regression test for using the wrong thread when logging during re-locking from deoptimization. - * - * @comment DiagnoseSyncOnValueBasedClasses=2 will cause logging when locking on \@ValueBased objects. - * @run driver EATests - * -XX:+UnlockDiagnosticVMOptions - * -Xms256m -Xmx256m - * -Xbootclasspath/a:. - * -XX:CompileCommand=dontinline,*::dontinline_* - * -XX:+WhiteBoxAPI - * -Xbatch - * -XX:+DoEscapeAnalysis -XX:+EliminateAllocations -XX:+EliminateLocks -XX:+EliminateNestedLocks - * -XX:DiagnoseSyncOnValueBasedClasses=2 - * * @comment Re-lock may inflate monitors when re-locking, which cause monitorinflation trace logging. * @run driver EATests * -XX:+UnlockDiagnosticVMOptions @@ -259,7 +246,6 @@ class EATestsTarget { new EAGetOwnedMonitorsTarget() .run(); new EAEntryCountTarget() .run(); new EARelockingObjectCurrentlyWaitingOnTarget() .run(); - new EARelockingValueBasedTarget() .run(); // Test cases that require deoptimization even though neither // locks nor allocations are eliminated at the point where @@ -385,7 +371,6 @@ public class EATests extends TestScaffold { new EAGetOwnedMonitors() .run(this); new EAEntryCount() .run(this); new EARelockingObjectCurrentlyWaitingOn() .run(this); - new EARelockingValueBased() .run(this); // Test cases that require deoptimization even though neither // locks nor allocations are eliminated at the point where @@ -2402,31 +2387,6 @@ class EARelockingObjectCurrentlyWaitingOnTarget extends EATestCaseBaseTarget { } -///////////////////////////////////////////////////////////////////////////// - -/** - * Test relocking eliminated @ValueBased object. - */ -class EARelockingValueBased extends EATestCaseBaseDebugger { - - public void runTestCase() throws Exception { - BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V"); - printStack(bpe.thread()); - @SuppressWarnings("unused") - ObjectReference o = getLocalRef(bpe.thread().frame(1), Integer.class.getName(), "l1"); - } -} - -class EARelockingValueBasedTarget extends EATestCaseBaseTarget { - - public void dontinline_testMethod() { - Integer l1 = new Integer(255); - synchronized (l1) { - dontinline_brkpt(); - } - } -} - ///////////////////////////////////////////////////////////////////////////// // // Test cases that require deoptimization even though neither locks From 533a8a8d2605f19f5f6f867c3ff5d649305d0ee5 Mon Sep 17 00:00:00 2001 From: William Kemper Date: Wed, 15 Apr 2026 21:54:39 +0000 Subject: [PATCH 305/359] 8376839: GenShen: Improve performance of evacuations into the old generation Reviewed-by: kdnilsen --- .../gc/shenandoah/shenandoahConcurrentGC.cpp | 23 +++ .../gc/shenandoah/shenandoahConcurrentGC.hpp | 4 +- .../gc/shenandoah/shenandoahDegeneratedGC.cpp | 5 + .../share/gc/shenandoah/shenandoahFreeSet.cpp | 3 +- .../shenandoahGenerationalEvacuationTask.cpp | 1 + .../shenandoah/shenandoahGenerationalHeap.cpp | 4 - .../share/gc/shenandoah/shenandoahHeap.cpp | 25 +++ .../share/gc/shenandoah/shenandoahHeap.hpp | 1 + .../gc/shenandoah/shenandoahHeapRegion.cpp | 6 + .../gc/shenandoah/shenandoahHeapRegion.hpp | 6 +- .../shenandoahHeapRegionClosures.cpp | 5 + .../shenandoah/shenandoahInPlacePromoter.cpp | 3 + .../gc/shenandoah/shenandoahOldGeneration.cpp | 33 +++- .../gc/shenandoah/shenandoahOldGeneration.hpp | 37 +++- .../share/gc/shenandoah/shenandoahPLAB.cpp | 8 - .../gc/shenandoah/shenandoahPhaseTimings.hpp | 3 +- .../shenandoah/shenandoahScanRemembered.cpp | 165 +++++++++++------- .../shenandoah/shenandoahScanRemembered.hpp | 7 + 18 files changed, 248 insertions(+), 91 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp index f0125c38cae..ba0aa1a1304 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp @@ -112,6 +112,24 @@ void ShenandoahConcurrentGC::entry_concurrent_update_refs_prepare(ShenandoahHeap heap->concurrent_prepare_for_update_refs(); } +void ShenandoahConcurrentGC::entry_update_card_table() { + ShenandoahHeap* const heap = ShenandoahHeap::heap(); + TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters()); + + static const char* msg = "Concurrent update cards"; + ShenandoahConcurrentPhase gc_phase(msg, ShenandoahPhaseTimings::conc_update_card_table); + EventMark em("%s", msg); + + ShenandoahWorkerScope scope(heap->workers(), + ShenandoahWorkerPolicy::calc_workers_for_conc_evac(), + "concurrent update cards"); + + // Heap needs to be parsable here. + // Also, parallel heap region iterate must have a phase set. + assert(ShenandoahTimingsTracker::is_current_phase_valid(), "Current phase must be set"); + ShenandoahGenerationalHeap::heap()->old_generation()->update_card_table(); +} + bool ShenandoahConcurrentGC::collect(GCCause::Cause cause) { ShenandoahHeap* const heap = ShenandoahHeap::heap(); _generation->ref_processor()->set_soft_reference_policy( @@ -206,6 +224,11 @@ bool ShenandoahConcurrentGC::collect(GCCause::Cause cause) { // Perform update-refs phase. entry_concurrent_update_refs_prepare(heap); + + if (ShenandoahHeap::heap()->mode()->is_generational()) { + entry_update_card_table(); + } + if (ShenandoahVerify) { vmop_entry_init_update_refs(); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.hpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.hpp index 54d43416fdb..ba228901d72 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.hpp @@ -59,8 +59,6 @@ public: bool collect(GCCause::Cause cause) override; ShenandoahDegenPoint degen_point() const; - void entry_concurrent_update_refs_prepare(ShenandoahHeap* heap); - // Return true if this cycle found enough immediate garbage to skip evacuation bool abbreviated() const { return _abbreviated; } @@ -95,6 +93,8 @@ protected: void entry_cleanup_early(); void entry_evacuate(); void entry_update_thread_roots(); + void entry_update_card_table(); + void entry_concurrent_update_refs_prepare(ShenandoahHeap* heap); void entry_update_refs(); void entry_cleanup_complete(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp index 1873d818093..84b22f13d47 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp @@ -277,6 +277,11 @@ void ShenandoahDegenGC::op_degenerated() { _abbreviated = true; } + // labs are retired, walk the old regions and update remembered set + if (ShenandoahHeap::heap()->mode()->is_generational()) { + ShenandoahGenerationalHeap::heap()->old_generation()->update_card_table(); + } + case _degenerated_update_refs: if (heap->has_forwarded_objects()) { op_update_refs(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp index a579d6d3694..592c5bffa5a 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp @@ -1569,7 +1569,7 @@ HeapWord* ShenandoahFreeSet::try_allocate_in(ShenandoahHeapRegion* r, Shenandoah // We must call try_recycle_under_lock() even if !r->is_trash(). The reason is that if r is being recycled at this // moment by a GC worker thread, it may appear to be not trash even though it has not yet been fully recycled. If // we proceed without waiting for the worker to finish recycling the region, the worker thread may overwrite the - // region's affiliation with FREE after we set the region's affiliation to req.afiliation() below + // region's affiliation with FREE after we set the region's affiliation to req.affiliation() below r->try_recycle_under_lock(); in_new_region = r->is_empty(); if (in_new_region) { @@ -1585,7 +1585,6 @@ HeapWord* ShenandoahFreeSet::try_allocate_in(ShenandoahHeapRegion* r, Shenandoah // concurrent preparations for mixed evacuations are completed), we mark this region as not requiring any // coalesce-and-fill processing. r->end_preemptible_coalesce_and_fill(); - _heap->old_generation()->clear_cards_for(r); } #ifdef ASSERT ShenandoahMarkingContext* const ctx = _heap->marking_context(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalEvacuationTask.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalEvacuationTask.cpp index 6912750378e..ca15c6db443 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalEvacuationTask.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalEvacuationTask.cpp @@ -133,3 +133,4 @@ void ShenandoahGenerationalEvacuationTask::evacuate_and_promote_regions() { } } } + diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp index d5cfa4b7fb9..a51449e91f4 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp @@ -363,10 +363,6 @@ oop ShenandoahGenerationalHeap::try_evacuate_object(oop p, Thread* thread, uint // Record that the evacuation succeeded evac_tracker()->end_evacuation(thread, size * HeapWordSize, FROM_GENERATION, TO_GENERATION); } - - if (TO_GENERATION == OLD_GENERATION) { - old_generation()->handle_evacuation(copy, size); - } } else { // Failed to evacuate. We need to deal with the object that is left behind. Since this // new allocation is certainly after TAMS, it will be considered live in the next cycle. diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index 5bf76505506..75d3ade4e49 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -1955,6 +1955,26 @@ void ShenandoahHeap::heap_region_iterate(ShenandoahHeapRegionClosure* blk) const } } +class ShenandoahHeapRegionIteratorTask : public WorkerTask { +private: + ShenandoahRegionIterator _regions; + ShenandoahHeapRegionClosure* _closure; + +public: + ShenandoahHeapRegionIteratorTask(ShenandoahHeapRegionClosure* closure) + : WorkerTask("Shenandoah Heap Region Iterator") + , _closure(closure) {} + + void work(uint worker_id) override { + ShenandoahParallelWorkerSession worker_session(worker_id); + ShenandoahHeapRegion* region = _regions.next(); + while (region != nullptr) { + _closure->heap_region_do(region); + region = _regions.next(); + } + } +}; + class ShenandoahParallelHeapRegionTask : public WorkerTask { private: ShenandoahHeap* const _heap; @@ -2011,6 +2031,11 @@ void ShenandoahHeap::parallel_heap_region_iterate(ShenandoahHeapRegionClosure* b } } +void ShenandoahHeap::heap_region_iterator(ShenandoahHeapRegionClosure* closure) const { + ShenandoahHeapRegionIteratorTask task(closure); + workers()->run_task(&task); +} + class ShenandoahRendezvousHandshakeClosure : public HandshakeClosure { public: inline ShenandoahRendezvousHandshakeClosure(const char* name) : HandshakeClosure(name) {} diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp index d4604be0aec..ab7dd00b774 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp @@ -298,6 +298,7 @@ public: void heap_region_iterate(ShenandoahHeapRegionClosure* blk) const; void parallel_heap_region_iterate(ShenandoahHeapRegionClosure* blk) const; + void heap_region_iterator(ShenandoahHeapRegionClosure* blk) const; inline ShenandoahMmuTracker* mmu_tracker() { return &_mmu_tracker; }; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp index afc6b24e168..3db11000af5 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp @@ -67,6 +67,7 @@ ShenandoahHeapRegion::ShenandoahHeapRegion(HeapWord* start, size_t index, bool c _new_top(nullptr), _empty_time(os::elapsedTime()), _top_before_promoted(nullptr), + _top_at_evac_start(start), _state(committed ? _empty_committed : _empty_uncommitted), _top(start), _tlab_allocs(0), @@ -565,12 +566,17 @@ void ShenandoahHeapRegion::recycle_internal() { assert(_recycling.is_set() && is_trash(), "Wrong state"); ShenandoahHeap* heap = ShenandoahHeap::heap(); + _top_at_evac_start = _bottom; _mixed_candidate_garbage_words = 0; set_top(bottom()); clear_live_data(); reset_alloc_metadata(); heap->marking_context()->reset_top_at_mark_start(this); set_update_watermark(bottom()); + if (is_old()) { + heap->old_generation()->clear_cards_for(this); + } + if (ZapUnusedHeapArea) { SpaceMangler::mangle_region(MemRegion(bottom(), end())); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp index 3a0ac042f57..569b64f756b 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp @@ -246,6 +246,7 @@ private: double _empty_time; HeapWord* _top_before_promoted; + HeapWord* _top_at_evac_start; // Seldom updated fields Atomic _state; @@ -365,12 +366,15 @@ public: } // Returns true iff this region was promoted in place subsequent to the most recent start of concurrent old marking. - inline bool was_promoted_in_place() { + bool was_promoted_in_place() const { return _promoted_in_place; } inline void restore_top_before_promote(); inline size_t garbage_before_padded_for_promote() const; + HeapWord* get_top_at_evac_start() const { return _top_at_evac_start; } + void record_top_at_evac_start() { _top_at_evac_start = _top; } + // If next available memory is not aligned on address that is multiple of alignment, fill the empty space // so that returned object is aligned on an address that is a multiple of alignment_in_bytes. Requested // size is in words. It is assumed that this->is_old(). A pad object is allocated, filled, and registered diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionClosures.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionClosures.cpp index 3c6fe1a3df1..7554a9c9a2c 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionClosures.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionClosures.cpp @@ -80,6 +80,11 @@ void ShenandoahFinalMarkUpdateRegionStateClosure::heap_region_do(ShenandoahHeapR // Remember limit for updating refs. It's guaranteed that we get no // from-space-refs written from here on. r->set_update_watermark_at_safepoint(r->top()); + + if (r->is_old()) { + // Record where we need to start updating the remembered set + r->record_top_at_evac_start(); + } } else { assert(!r->has_live(), "Region %zu should have no live data", r->index()); assert(_ctx == nullptr || _ctx->top_at_mark_start(r) == r->top(), diff --git a/src/hotspot/share/gc/shenandoah/shenandoahInPlacePromoter.cpp b/src/hotspot/share/gc/shenandoah/shenandoahInPlacePromoter.cpp index 10d61221e87..153193fa3a3 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahInPlacePromoter.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahInPlacePromoter.cpp @@ -238,6 +238,9 @@ void ShenandoahInPlacePromoter::promote(ShenandoahHeapRegion* region) const { // is_collector_free range. We'll add it to that range below. region->restore_top_before_promote(); + // We also need to record where those allocations begin so that we can later update the remembered set. + region->record_top_at_evac_start(); + assert(region->used() + pip_pad_bytes + pip_unpadded == region_size_bytes, "invariant"); // The update_watermark was likely established while we had the artificially high value of top. Make it sane now. diff --git a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp index 4ad7d2a1ae5..37de5966554 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp @@ -318,6 +318,11 @@ void ShenandoahOldGeneration::heap_region_iterate(ShenandoahHeapRegionClosure* c ShenandoahHeap::heap()->heap_region_iterate(&old_regions_cl); } +void ShenandoahOldGeneration::heap_region_iterator(ShenandoahHeapRegionClosure* cl) { + ShenandoahIncludeRegionClosure old_regions_cl(cl); + ShenandoahHeap::heap()->heap_region_iterator(&old_regions_cl); +} + void ShenandoahOldGeneration::set_concurrent_mark_in_progress(bool in_progress) { ShenandoahHeap::heap()->set_concurrent_old_mark_in_progress(in_progress); } @@ -326,6 +331,12 @@ bool ShenandoahOldGeneration::is_concurrent_mark_in_progress() { return ShenandoahHeap::heap()->is_concurrent_old_mark_in_progress(); } +void ShenandoahOldGeneration::record_tops_at_evac_start() { + for_each_region([](ShenandoahHeapRegion* region) { + region->record_top_at_evac_start(); + }); +} + void ShenandoahOldGeneration::cancel_marking() { if (is_concurrent_mark_in_progress()) { log_debug(gc)("Abandon SATB buffers"); @@ -662,15 +673,19 @@ void ShenandoahOldGeneration::log_failed_promotion(LogStream& ls, Thread* thread } } -void ShenandoahOldGeneration::handle_evacuation(HeapWord* obj, size_t words) const { - // Only register the copy of the object that won the evacuation race. - _card_scan->register_object_without_lock(obj); - - // Mark the entire range of the evacuated object as dirty. At next remembered set scan, - // we will clear dirty bits that do not hold interesting pointers. It's more efficient to - // do this in batch, in a background GC thread than to try to carefully dirty only cards - // that hold interesting pointers right now. - _card_scan->mark_range_as_dirty(obj, words); +void ShenandoahOldGeneration::update_card_table() { + for_each_region([this](ShenandoahHeapRegion* region) { + if (region->is_regular()) { + // Humongous regions are promoted in place, remembered set maintenance is handled there + // Regular regions that are promoted in place have their rset maintenance handled for + // the objects in the region when it was promoted. We record TEAS for such a region + // when the in-place-promotion is completed. Such a region may be used for additional + // promotions in the same cycle it was itself promoted. + if (region->top() > region->get_top_at_evac_start()) { + _card_scan->update_card_table(region->get_top_at_evac_start(), region->top()); + } + } + }); } bool ShenandoahOldGeneration::has_unprocessed_collection_candidates() { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.hpp b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.hpp index 0069d38a84e..942f93c5c68 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.hpp @@ -172,8 +172,8 @@ public: void handle_failed_promotion(Thread* thread, size_t size) const; void log_failed_promotion(LogStream& ls, Thread* thread, size_t size) const; - // A successful evacuation re-dirties the cards and registers the object with the remembered set - void handle_evacuation(HeapWord* obj, size_t words) const; + // Iterate over recently promoted objects to update card table and object registrations + void update_card_table(); // Clear the flag after it is consumed by the control thread bool clear_failed_evacuation() { @@ -199,11 +199,36 @@ public: // Mark card for this location as dirty void mark_card_as_dirty(void* location); + template + class ShenandoahHeapRegionLambda : public ShenandoahHeapRegionClosure { + T _region_lambda; + public: + explicit ShenandoahHeapRegionLambda(T region_lambda) : _region_lambda(region_lambda) {} + + void heap_region_do(ShenandoahHeapRegion* r) override { + _region_lambda(r); + } + + bool is_thread_safe() override { + return true; + } + + size_t parallel_region_stride() override { + // Temporarily override to force parallelism when updating card table + return 8; + } + }; + + template + void for_each_region(LambdaT lambda) { + ShenandoahHeapRegionLambda l(lambda); + heap_region_iterator(&l); + } + void parallel_heap_region_iterate(ShenandoahHeapRegionClosure* cl) override; - void parallel_heap_region_iterate_free(ShenandoahHeapRegionClosure* cl) override; - void heap_region_iterate(ShenandoahHeapRegionClosure* cl) override; + void heap_region_iterator(ShenandoahHeapRegionClosure* cl); bool contains(ShenandoahAffiliation affiliation) const override; bool contains(ShenandoahHeapRegion* region) const override; @@ -212,6 +237,10 @@ public: void set_concurrent_mark_in_progress(bool in_progress) override; bool is_concurrent_mark_in_progress() override; + // For old regions, objects between top at evac start and top represent promoted objects. + // These objects will need to have their cards dirtied and their offsets within the cards registered. + void record_tops_at_evac_start(); + bool entry_coalesce_and_fill(); // Global collections touch old regions, so the old generation needs to be informed of this. diff --git a/src/hotspot/share/gc/shenandoah/shenandoahPLAB.cpp b/src/hotspot/share/gc/shenandoah/shenandoahPLAB.cpp index 412cfa9447e..5049113b665 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahPLAB.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahPLAB.cpp @@ -210,12 +210,4 @@ void ShenandoahPLAB::retire() { // plab->retire() overwrites unused memory between plab->top() and plab->hard_end() with a dummy object to make memory parsable. // It adds the size of this unused memory, in words, to plab->waste(). _plab->retire(); - if (top != nullptr && _plab->waste() > original_waste && _heap->is_in_old(top)) { - // If retiring the plab created a filler object, then we need to register it with our card scanner so it can - // safely walk the region backing the plab. - log_debug(gc, plab)("retire_plab() is registering remnant of size %zu at " PTR_FORMAT, - (_plab->waste() - original_waste) * HeapWordSize, p2i(top)); - // No lock is necessary because the PLAB memory is aligned on card boundaries. - _heap->old_generation()->card_scan()->register_object_without_lock(top); - } } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.hpp b/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.hpp index e890008b916..a454de68f00 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.hpp @@ -109,6 +109,7 @@ class outputStream; f(conc_strong_roots, "Concurrent Strong Roots") \ SHENANDOAH_PAR_PHASE_DO(conc_strong_roots_, " CSR: ", f) \ f(conc_evac, "Concurrent Evacuation") \ + f(conc_update_card_table, "Concurrent Update Cards") \ f(conc_final_roots, "Concurrent Final Roots") \ f(promote_in_place, " Promote Regions") \ f(final_roots_gross, "Pause Verify Final Roots (G)") \ @@ -254,7 +255,7 @@ public: void flush_cycle_to_global(); static const char* phase_name(Phase phase) { - assert(phase >= 0 && phase < _num_phases, "Out of bound"); + assert(phase >= 0 && phase < _num_phases, "Out of bounds: %d", phase); return _phase_names[phase]; } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.cpp b/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.cpp index 9e160d5b294..8d7ba2dc46f 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.cpp @@ -31,6 +31,33 @@ #include "logging/log.hpp" #include "runtime/threads.hpp" +// A closure that takes an oop in the old generation and, if it's pointing +// into the young generation, dirties the corresponding remembered set entry. +class ShenandoahDirtyRememberedSetClosure : public BasicOopIterateClosure { +protected: + ShenandoahGenerationalHeap* const _heap; + ShenandoahScanRemembered* const _scanner; + +public: + ShenandoahDirtyRememberedSetClosure() : + _heap(ShenandoahGenerationalHeap::heap()), + _scanner(_heap->old_generation()->card_scan()) {} + + template + void work(T* p) { + assert(_heap->is_in_old(p), "Expecting to get an old gen address"); + if (T o = RawAccess<>::oop_load(p); !CompressedOops::is_null(o)) { + if (const oop obj = CompressedOops::decode_not_null(o); _heap->is_in_young(obj)) { + // Dirty the card containing the cross-generational pointer. + _scanner->mark_card_as_dirty((HeapWord*) p); + } + } + } + + void do_oop(narrowOop* p) override { work(p); } + void do_oop(oop* p) override { work(p); } +}; + size_t ShenandoahDirectCardMarkRememberedSet::last_valid_index() const { return _card_table->last_valid_index(); } @@ -161,7 +188,6 @@ void ShenandoahCardCluster::register_object_without_lock(HeapWord* address) { uint8_t offset_in_card = checked_cast(pointer_delta(address, card_start_address)); if (!starts_object(card_at_start)) { - set_starts_object_bit(card_at_start); set_first_start(card_at_start, offset_in_card); set_last_start(card_at_start, offset_in_card); } else { @@ -172,6 +198,49 @@ void ShenandoahCardCluster::register_object_without_lock(HeapWord* address) { } } +void ShenandoahCardCluster::update_card_table(HeapWord* start, HeapWord* end) { + HeapWord* address = start; + HeapWord* previous_address = nullptr; + uint8_t previous_offset = 0; + size_t previous_card_index = -1; + ShenandoahDirtyRememberedSetClosure make_cards_dirty; + + log_debug(gc, remset)("Update remembered set from " PTR_FORMAT ", to " PTR_FORMAT, p2i(start), p2i(end)); + _rs->mark_range_as_dirty(start, pointer_delta(end, start)); + + while (address < end) { + + // Compute card and offset in card for this object + const size_t object_card_index = _rs->card_index_for_addr(address); + const HeapWord* card_start_address = _rs->addr_for_card_index(object_card_index); + const uint8_t offset_in_card = checked_cast(pointer_delta(address, card_start_address)); + + if (object_card_index != previous_card_index) { + if (previous_address != nullptr) { + // Register the previous object on the previous card, we are starting a new card here + set_last_start(previous_card_index, previous_offset); + } + + previous_card_index = object_card_index; + if (!starts_object(object_card_index)) { + // The previous cycle may have recorded an earlier start in this card. Do not overwrite it. + set_first_start(object_card_index, offset_in_card); + } + } + + previous_offset = offset_in_card; + previous_address = address; + + const oop obj = cast_to_oop(address); + address += obj->size(); + } + + // Register the last object seen in this range. + if (previous_address != nullptr) { + set_last_start(previous_card_index, previous_offset); + } +} + void ShenandoahCardCluster::coalesce_objects(HeapWord* address, size_t length_in_words) { size_t card_at_start = _rs->card_index_for_addr(address); @@ -641,36 +710,6 @@ void ShenandoahScanRemembered::merge_worker_card_stats_cumulative( } #endif -// A closure that takes an oop in the old generation and, if it's pointing -// into the young generation, dirties the corresponding remembered set entry. -// This is only used to rebuild the remembered set after a full GC. -class ShenandoahDirtyRememberedSetClosure : public BasicOopIterateClosure { -protected: - ShenandoahGenerationalHeap* const _heap; - ShenandoahScanRemembered* const _scanner; - -public: - ShenandoahDirtyRememberedSetClosure() : - _heap(ShenandoahGenerationalHeap::heap()), - _scanner(_heap->old_generation()->card_scan()) {} - - template - inline void work(T* p) { - assert(_heap->is_in_old(p), "Expecting to get an old gen address"); - T o = RawAccess<>::oop_load(p); - if (!CompressedOops::is_null(o)) { - oop obj = CompressedOops::decode_not_null(o); - if (_heap->is_in_young(obj)) { - // Dirty the card containing the cross-generational pointer. - _scanner->mark_card_as_dirty((HeapWord*) p); - } - } - } - - virtual void do_oop(narrowOop* p) { work(p); } - virtual void do_oop(oop* p) { work(p); } -}; - ShenandoahDirectCardMarkRememberedSet::ShenandoahDirectCardMarkRememberedSet(ShenandoahCardTable* card_table, size_t total_card_count) : LogCardValsPerIntPtr(log2i_exact(sizeof(intptr_t)) - log2i_exact(sizeof(CardValue))), LogCardSizeInWords(log2i_exact(CardTable::card_size_in_words())) { @@ -1039,38 +1078,44 @@ void ShenandoahReconstructRememberedSetTask::work(uint worker_id) { ShenandoahDirtyRememberedSetClosure dirty_cards_for_cross_generational_pointers; while (r != nullptr) { - if (r->is_old() && r->is_active()) { - HeapWord* obj_addr = r->bottom(); - if (r->is_humongous_start()) { - // First, clear the remembered set - oop obj = cast_to_oop(obj_addr); - size_t size = obj->size(); - - size_t num_regions = ShenandoahHeapRegion::required_regions(size * HeapWordSize); - size_t region_index = r->index(); - ShenandoahHeapRegion* humongous_region = heap->get_region(region_index); - while (num_regions-- != 0) { - scanner->reset_object_range(humongous_region->bottom(), humongous_region->end()); - region_index++; - humongous_region = heap->get_region(region_index); - } - - // Then register the humongous object and DIRTY relevant remembered set cards - scanner->register_object_without_lock(obj_addr); - obj->oop_iterate(&dirty_cards_for_cross_generational_pointers); - } else if (!r->is_humongous()) { - scanner->reset_object_range(r->bottom(), r->end()); - - // Then iterate over all objects, registering object and DIRTYing relevant remembered set cards - HeapWord* t = r->top(); - while (obj_addr < t) { + if (r->is_active()) { + if (r->is_old()) { + HeapWord* obj_addr = r->bottom(); + if (r->is_humongous_start()) { + // First, clear the remembered set oop obj = cast_to_oop(obj_addr); + size_t size = obj->size(); + + size_t num_regions = ShenandoahHeapRegion::required_regions(size * HeapWordSize); + size_t region_index = r->index(); + ShenandoahHeapRegion* humongous_region = heap->get_region(region_index); + while (num_regions-- != 0) { + scanner->reset_object_range(humongous_region->bottom(), humongous_region->end()); + region_index++; + humongous_region = heap->get_region(region_index); + } + + // Then register the humongous object and DIRTY relevant remembered set cards scanner->register_object_without_lock(obj_addr); - obj_addr += obj->oop_iterate_size(&dirty_cards_for_cross_generational_pointers); - } - } // else, ignore humongous continuation region + obj->oop_iterate(&dirty_cards_for_cross_generational_pointers); + } else if (!r->is_humongous()) { + scanner->reset_object_range(r->bottom(), r->end()); + + // Then iterate over all objects, registering object and DIRTYing relevant remembered set cards + HeapWord* t = r->top(); + while (obj_addr < t) { + oop obj = cast_to_oop(obj_addr); + scanner->register_object_without_lock(obj_addr); + obj_addr += obj->oop_iterate_size(&dirty_cards_for_cross_generational_pointers); + } + } // else, ignore humongous continuation region + } else { + // The region is young, but it may become old again and we don't want stale remembered set data. + assert(r->is_young(), "Region: %zu, is active but free", r->index()); + heap->old_generation()->clear_cards_for(r); + } } - // else, this region is FREE or YOUNG or inactive and we can ignore it. + // else, this region is FREE or inactive and we can ignore it. r = _regions->next(); } } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.hpp b/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.hpp index c2c117e86e6..53f00e64a03 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.hpp @@ -603,6 +603,9 @@ public: // as address. void register_object_without_lock(HeapWord* address); + // Dirty cards and register objects for the given range in memory. + void update_card_table(HeapWord* start, HeapWord* end); + // During the reference updates phase of GC, we walk through each old-gen memory region that was // not part of the collection set and we invalidate all unmarked objects. As part of this effort, // we coalesce neighboring dead objects in order to make future remembered set scanning more @@ -814,6 +817,10 @@ public: } } + void update_card_table(HeapWord* start, HeapWord* end) const { + _scc->update_card_table(start, end); + } + // Return true iff this object is "properly" registered. bool verify_registration(HeapWord* address, ShenandoahMarkingContext* ctx); From a2261a4b7c84909f8c116552f32a6fb5553b0ce6 Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Thu, 16 Apr 2026 05:17:06 +0000 Subject: [PATCH 306/359] 8382196: Clean up C++ iterator style in compactHashtable.hpp and trainingData.hpp Reviewed-by: kvn, qamai --- src/hotspot/share/classfile/compactHashtable.hpp | 7 +------ src/hotspot/share/oops/trainingData.hpp | 13 +++---------- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/src/hotspot/share/classfile/compactHashtable.hpp b/src/hotspot/share/classfile/compactHashtable.hpp index 81f2951289d..1711c5f8cd3 100644 --- a/src/hotspot/share/classfile/compactHashtable.hpp +++ b/src/hotspot/share/classfile/compactHashtable.hpp @@ -307,14 +307,9 @@ public: template inline void iterate(ITER* iter) const { iterate([&](V v) { iter->do_value(v); }); } - template - inline void iterate(const Function& function) const { // lambda enabled API - iterate(const_cast(function)); - } - // Iterate through the values in the table, stopping when the lambda returns false. template - inline void iterate(Function& function) const { // lambda enabled API + inline void iterate(Function function) const { // lambda enabled API for (u4 i = 0; i < _bucket_count; i++) { u4 bucket_info = _buckets[i]; u4 bucket_offset = BUCKET_OFFSET(bucket_info); diff --git a/src/hotspot/share/oops/trainingData.hpp b/src/hotspot/share/oops/trainingData.hpp index bd696f52a8b..a6decdce7f0 100644 --- a/src/hotspot/share/oops/trainingData.hpp +++ b/src/hotspot/share/oops/trainingData.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -217,11 +217,7 @@ public: return *prior; } template - void iterate(const Function& fn) const { // lambda enabled API - iterate(const_cast(fn)); - } - template - void iterate(Function& fn) const { // lambda enabled API + void iterate(Function fn) const { // lambda enabled API return _table.iterate_all([&](const TrainingData::Key* k, TrainingData* td) { fn(td); }); } int size() const { return _table.number_of_entries(); } @@ -304,10 +300,7 @@ private: } template - static void iterate(const Function& fn) { iterate(const_cast(fn)); } - - template - static void iterate(Function& fn) { // lambda enabled API + static void iterate(Function fn) { // lambda enabled API TrainingDataLocker l; if (have_data()) { archived_training_data_dictionary()->iterate_all(fn); From 01bfd427a322c6f92643c7920bbd1b1b35141a69 Mon Sep 17 00:00:00 2001 From: Xiaolong Peng Date: Thu, 16 Apr 2026 06:08:06 +0000 Subject: [PATCH 307/359] 8381382: Shenandoah: assert(capacity > 0) failed: free regions must have allocation capacity Reviewed-by: kdnilsen, wkemper --- .../gc/shenandoah/shenandoahHeapRegion.cpp | 20 +++++++++++++------ .../gc/shenandoah/shenandoahHeapRegion.hpp | 2 +- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp index 3db11000af5..c031569b7c6 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp @@ -568,7 +568,6 @@ void ShenandoahHeapRegion::recycle_internal() { _top_at_evac_start = _bottom; _mixed_candidate_garbage_words = 0; - set_top(bottom()); clear_live_data(); reset_alloc_metadata(); heap->marking_context()->reset_top_at_mark_start(this); @@ -580,16 +579,21 @@ void ShenandoahHeapRegion::recycle_internal() { if (ZapUnusedHeapArea) { SpaceMangler::mangle_region(MemRegion(bottom(), end())); } - - make_empty(); + set_top(bottom()); set_affiliation(FREE); + + // Lastly, set region state to empty + make_empty(); } // Upon return, this region has been recycled. We try to recycle it. // We may fail if some other thread recycled it before we do. void ShenandoahHeapRegion::try_recycle_under_lock() { shenandoah_assert_heaplocked(); - if (is_trash() && _recycling.try_set()) { + if (!is_trash()) { + return; + } + if (_recycling.try_set()) { if (is_trash()) { // At freeset rebuild time, which precedes recycling of collection set, we treat all cset regions as // part of capacity, as empty, as fully available, and as unaffiliated. This provides short-lived optimism @@ -609,6 +613,7 @@ void ShenandoahHeapRegion::try_recycle_under_lock() { os::naked_yield(); } } + assert(!is_trash(), "Must not"); } } @@ -616,7 +621,10 @@ void ShenandoahHeapRegion::try_recycle_under_lock() { // some GC worker thread has taken responsibility to recycle the region, eventually. void ShenandoahHeapRegion::try_recycle() { shenandoah_assert_not_heaplocked(); - if (is_trash() && _recycling.try_set()) { + if (!is_trash()) { + return; + } + if (_recycling.try_set()) { // Double check region state after win the race to set recycling flag if (is_trash()) { // At freeset rebuild time, which precedes recycling of collection set, we treat all cset regions as @@ -840,7 +848,7 @@ void ShenandoahHeapRegion::set_state(RegionState to) { evt.set_to(to); evt.commit(); } - _state.store_relaxed(to); + _state.release_store(to); } void ShenandoahHeapRegion::record_pin() { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp index 569b64f756b..e27bbbb737d 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp @@ -218,7 +218,7 @@ public: bool is_alloc_allowed() const { auto cur_state = state(); return is_empty_state(cur_state) || cur_state == _regular || cur_state == _pinned; } bool is_stw_move_allowed() const { auto cur_state = state(); return cur_state == _regular || cur_state == _cset || (ShenandoahHumongousMoves && cur_state == _humongous_start); } - RegionState state() const { return _state.load_relaxed(); } + RegionState state() const { return _state.load_acquire(); } int state_ordinal() const { return region_state_to_ordinal(state()); } void record_pin(); From 8688c0b65516f0a035ae8d25790489981475d07f Mon Sep 17 00:00:00 2001 From: Anton Seoane Ampudia Date: Thu, 16 Apr 2026 11:18:22 +0000 Subject: [PATCH 308/359] 8379129: C2 crash in LoadNode::can_split_through_phi_base during Escape Analysis (JDK 25.0.1+8) Reviewed-by: kvn, rcastanedalo, dlong --- src/hotspot/share/opto/memnode.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/opto/memnode.cpp b/src/hotspot/share/opto/memnode.cpp index c7fe4508473..a49d4708d32 100644 --- a/src/hotspot/share/opto/memnode.cpp +++ b/src/hotspot/share/opto/memnode.cpp @@ -1671,11 +1671,15 @@ bool LoadNode::can_split_through_phi_base(PhaseGVN* phase) { intptr_t ignore = 0; Node* base = AddPNode::Ideal_base_and_offset(address, phase, ignore); + if (base == nullptr) { + return false; + } + if (base->is_CastPP()) { base = base->in(1); } - if (req() > 3 || base == nullptr || !base->is_Phi()) { + if (req() > 3 || !base->is_Phi()) { return false; } From 04bb3a91dbfb8fb9db93ea9609210e036a4c5d10 Mon Sep 17 00:00:00 2001 From: Matthew Donovan Date: Thu, 16 Apr 2026 14:11:07 +0000 Subject: [PATCH 309/359] 8381176: Utilities.expectedNegoAppProtocol chooses client ALPN protocol over server's Reviewed-by: djelinski, myankelevich --- .../net/ssl/TLSCommon/interop/Utilities.java | 10 ++++----- .../javax/net/ssl/compatibility/AlpnTest.java | 21 ++++++++++++++++++- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/test/jdk/javax/net/ssl/TLSCommon/interop/Utilities.java b/test/jdk/javax/net/ssl/TLSCommon/interop/Utilities.java index 34cccb5356c..0a825d6cc7d 100644 --- a/test/jdk/javax/net/ssl/TLSCommon/interop/Utilities.java +++ b/test/jdk/javax/net/ssl/TLSCommon/interop/Utilities.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -430,10 +430,10 @@ public class Utilities { public static String expectedNegoAppProtocol(String[] serverAppProtocols, String[] clientAppProtocols) { if (serverAppProtocols != null && clientAppProtocols != null) { - for(String clientAppProtocol : clientAppProtocols) { - for(String serverAppProtocol : serverAppProtocols) { - if (clientAppProtocol.equals(serverAppProtocol)) { - return clientAppProtocol; + for(String serverAppProtocol : serverAppProtocols) { + for(String clientAppProtocol : clientAppProtocols) { + if (serverAppProtocol.equals(clientAppProtocol)) { + return serverAppProtocol; } } } diff --git a/test/jdk/javax/net/ssl/compatibility/AlpnTest.java b/test/jdk/javax/net/ssl/compatibility/AlpnTest.java index 71a60fe5435..86b75f4d2c3 100644 --- a/test/jdk/javax/net/ssl/compatibility/AlpnTest.java +++ b/test/jdk/javax/net/ssl/compatibility/AlpnTest.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 @@ -36,6 +36,8 @@ * @run main/manual AlpnTest false */ +import jtreg.SkippedException; + import java.util.ArrayList; import java.util.List; import java.util.Set; @@ -98,6 +100,19 @@ public class AlpnTest extends ExtInteropTest { clientCase.setCipherSuites(cipherSuite); clientCase.setAppProtocols("h2"); + testCases.add( + new TestCase(serverCase, clientCase)); + + serverCase = ExtUseCase.newInstance(); + serverCase.setCertTuple(certTuple); + serverCase.setAppProtocols("http/1.1", "h2"); + + clientCase = ExtUseCase.newInstance(); + clientCase.setCertTuple(certTuple); + clientCase.setProtocols(protocol); + clientCase.setCipherSuites(cipherSuite); + clientCase.setAppProtocols("h2", "http/1.1"); + testCases.add( new TestCase(serverCase, clientCase)); } @@ -171,6 +186,10 @@ public class AlpnTest extends ExtInteropTest { Boolean defaultJdkAsServer = Boolean.valueOf(args[0]); Set jdkInfos = Utils.jdkInfoList(); + if (jdkInfos.isEmpty()) { + throw new SkippedException("No JDKs to test"); + } + for (JdkInfo jdkInfo : jdkInfos) { AlpnTest test = new AlpnTest( defaultJdkAsServer ? JdkInfo.DEFAULT : jdkInfo, From 26df25ef2db23ce815ca8d3a1fc2f4018ece6a81 Mon Sep 17 00:00:00 2001 From: Vladimir Kozlov Date: Thu, 16 Apr 2026 14:19:26 +0000 Subject: [PATCH 310/359] 8382045: Increase AOT C strings table size in not product VM Reviewed-by: adinn, asmehra --- src/hotspot/share/code/aotCodeCache.cpp | 12 ++++++------ src/hotspot/share/code/codeBlob.hpp | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/hotspot/share/code/aotCodeCache.cpp b/src/hotspot/share/code/aotCodeCache.cpp index c2838917516..d4f12936e96 100644 --- a/src/hotspot/share/code/aotCodeCache.cpp +++ b/src/hotspot/share/code/aotCodeCache.cpp @@ -2184,7 +2184,7 @@ void AOTCodeAddressTable::set_stubgen_stubs_complete() { #ifdef PRODUCT #define MAX_STR_COUNT 200 #else -#define MAX_STR_COUNT 500 +#define MAX_STR_COUNT 2000 #endif #define _c_str_max MAX_STR_COUNT static const int _c_str_base = _all_max; @@ -2296,7 +2296,7 @@ const char* AOTCodeAddressTable::add_C_string(const char* str) { int AOTCodeAddressTable::id_for_C_string(address str) { if (str == nullptr) { - return -1; + return BAD_ADDRESS_ID; } MutexLocker ml(AOTCodeCStrings_lock, Mutex::_no_safepoint_check_flag); for (int i = 0; i < _C_strings_count; i++) { @@ -2314,7 +2314,7 @@ int AOTCodeAddressTable::id_for_C_string(address str) { return id; } } - return -1; + return BAD_ADDRESS_ID; } address AOTCodeAddressTable::address_for_C_string(int idx) { @@ -2381,13 +2381,13 @@ int AOTCodeAddressTable::id_for_address(address addr, RelocIterator reloc, CodeB } // Seach for C string id = id_for_C_string(addr); - if (id >= 0) { + if (id != BAD_ADDRESS_ID) { return id + _c_str_base; } if (StubRoutines::contains(addr) || CodeCache::find_blob(addr) != nullptr) { // Search for a matching stub entry id = search_address(addr, _stubs_addr, _stubs_max); - if (id < 0) { + if (id == BAD_ADDRESS_ID) { StubCodeDesc* desc = StubCodeDesc::desc_for(addr); if (desc == nullptr) { desc = StubCodeDesc::desc_for(addr + frame::pc_return_offset); @@ -2400,7 +2400,7 @@ int AOTCodeAddressTable::id_for_address(address addr, RelocIterator reloc, CodeB } else { // Search in runtime functions id = search_address(addr, _extrs_addr, _extrs_length); - if (id < 0) { + if (id == BAD_ADDRESS_ID) { ResourceMark rm; const int buflen = 1024; char* func_name = NEW_RESOURCE_ARRAY(char, buflen); diff --git a/src/hotspot/share/code/codeBlob.hpp b/src/hotspot/share/code/codeBlob.hpp index d372e72fc23..709623de308 100644 --- a/src/hotspot/share/code/codeBlob.hpp +++ b/src/hotspot/share/code/codeBlob.hpp @@ -226,7 +226,7 @@ public: nmethod* as_nmethod() const { assert(is_nmethod(), "must be nmethod"); return (nmethod*) this; } CodeBlob* as_codeblob() const { return (CodeBlob*) this; } // we may want to force an actual buffer blob or subtype instance - BufferBlob* as_buffer_blob(bool strict = true) const { assert(is_buffer_blob(), "must be %sbuffer blob", (strict ? "strict " : "")); return (BufferBlob*) this; } + BufferBlob* as_buffer_blob(bool strict = true) const { assert(is_buffer_blob(strict), "must be %sbuffer blob", (strict ? "strict " : "")); return (BufferBlob*) this; } AdapterBlob* as_adapter_blob() const { assert(is_adapter_blob(), "must be adapter blob"); return (AdapterBlob*) this; } ExceptionBlob* as_exception_blob() const { assert(is_exception_stub(), "must be exception stub"); return (ExceptionBlob*) this; } // this will always return a subtype instance From 91cde7f160f46d04caa08781eed331875532bce1 Mon Sep 17 00:00:00 2001 From: Yasumasa Suenaga Date: Thu, 16 Apr 2026 14:42:01 +0000 Subject: [PATCH 311/359] 8382327: Disable some SA tests for mixed jstack on musl C Reviewed-by: mbaesken, kevinw --- test/hotspot/jtreg/serviceability/sa/ClhsdbPstack.java | 4 ++++ .../jtreg/serviceability/sa/TestJhsdbJstackMixed.java | 6 ++++++ .../serviceability/sa/TestJhsdbJstackMixedWithXComp.java | 9 ++++++++- .../serviceability/sa/TestJhsdbJstackPrintVMLocks.java | 5 +++++ 4 files changed, 23 insertions(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/serviceability/sa/ClhsdbPstack.java b/test/hotspot/jtreg/serviceability/sa/ClhsdbPstack.java index 51738be3554..6921a7ec0ca 100644 --- a/test/hotspot/jtreg/serviceability/sa/ClhsdbPstack.java +++ b/test/hotspot/jtreg/serviceability/sa/ClhsdbPstack.java @@ -54,6 +54,10 @@ import jtreg.SkippedException; public class ClhsdbPstack { public static void main(String[] args) throws Exception { + if (Platform.isMusl()) { + throw new SkippedException("This test does not work on musl libc."); + } + boolean withCore = Boolean.parseBoolean(args[0]); System.out.println("Starting ClhsdbPstack test: withCore==" + withCore); diff --git a/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixed.java b/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixed.java index e3808aa6706..a5750edf360 100644 --- a/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixed.java +++ b/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixed.java @@ -33,6 +33,8 @@ import jdk.test.lib.Utils; import jdk.test.lib.apps.LingeredApp; import jdk.test.lib.process.OutputAnalyzer; +import jtreg.SkippedException; + /** * @test * @key randomness @@ -174,6 +176,10 @@ public class TestJhsdbJstackMixed { } public static void main(String... args) throws Exception { + if (Platform.isMusl()) { + throw new SkippedException("This test does not work on musl libc."); + } + SATestUtils.skipIfCannotAttach(); // throws SkippedException if attach not expected to work. LingeredApp app = null; diff --git a/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixedWithXComp.java b/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixedWithXComp.java index a3880bc9f0e..70a9e67e406 100644 --- a/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixedWithXComp.java +++ b/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixedWithXComp.java @@ -1,6 +1,6 @@ /* * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2025, NTT DATA + * Copyright (c) 2025, 2026, 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 @@ -27,11 +27,14 @@ import java.util.Arrays; import java.util.List; import jdk.test.lib.JDKToolLauncher; +import jdk.test.lib.Platform; import jdk.test.lib.SA.SATestUtils; import jdk.test.lib.Utils; import jdk.test.lib.apps.LingeredApp; import jdk.test.lib.process.OutputAnalyzer; +import jtreg.SkippedException; + /** * @test id=xcomp * @bug 8370176 @@ -111,6 +114,10 @@ public class TestJhsdbJstackMixedWithXComp { } public static void main(String... args) throws Exception { + if (Platform.isMusl()) { + throw new SkippedException("This test does not work on musl libc."); + } + SATestUtils.skipIfCannotAttach(); // throws SkippedException if attach not expected to work. LingeredApp app = null; diff --git a/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackPrintVMLocks.java b/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackPrintVMLocks.java index f6580d71e05..e0774917f80 100644 --- a/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackPrintVMLocks.java +++ b/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackPrintVMLocks.java @@ -22,6 +22,7 @@ */ import jdk.test.lib.JDKToolLauncher; +import jdk.test.lib.Platform; import jdk.test.lib.SA.SATestUtils; import jdk.test.lib.apps.LingeredApp; import jdk.test.lib.process.OutputAnalyzer; @@ -43,6 +44,10 @@ public class TestJhsdbJstackPrintVMLocks { final static int MAX_ATTEMPTS = 5; public static void main(String[] args) throws Exception { + if (Platform.isMusl()) { + throw new SkippedException("This test does not work on musl libc."); + } + SATestUtils.skipIfCannotAttach(); // throws SkippedException if attach not expected to work. LingeredApp theApp = null; From 35ad47b4c09d0812f3f7c57ac7932c1533790fc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Walln=C3=B6fer?= Date: Thu, 16 Apr 2026 14:42:20 +0000 Subject: [PATCH 312/359] 8373922: Enhance Taglet API to support relative URLs 8379520: Make use of new Taglet.toString method in JDK build taglets Reviewed-by: liach --- make/Docs.gmk | 9 +- .../src/classes/build/tools/taglet/JSpec.java | 26 +- .../build/tools/taglet/SealedGraph.java | 58 +++-- .../classes/build/tools/taglet/ToolGuide.java | 29 +-- .../jdk/javadoc/doclet/StandardDoclet.java | 4 +- .../classes/jdk/javadoc/doclet/Taglet.java | 66 ++++- .../formats/html/HtmlDocletWriter.java | 6 +- .../formats/html/taglets/UserTaglet.java | 14 +- .../TestRelativeURLTaglet.java | 229 ++++++++++++++++++ 9 files changed, 344 insertions(+), 97 deletions(-) create mode 100644 test/langtools/jdk/javadoc/doclet/testRelativeURLTaglet/TestRelativeURLTaglet.java diff --git a/make/Docs.gmk b/make/Docs.gmk index a8d40e078e2..9cee8cd40c1 100644 --- a/make/Docs.gmk +++ b/make/Docs.gmk @@ -1,4 +1,4 @@ -# Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. # 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,19 +93,16 @@ JAVADOC_DISABLED_DOCLINT_WARNINGS := missing JAVADOC_DISABLED_DOCLINT_PACKAGES := org.w3c.* javax.smartcardio # The initial set of options for javadoc -# -XDaccessInternalAPI is a temporary workaround, see 8373909 JAVADOC_OPTIONS := -use -keywords -notimestamp \ -serialwarn -encoding utf-8 -docencoding utf-8 -breakiterator \ -splitIndex --system none -javafx --expand-requires transitive \ - --override-methods=summary \ - -XDaccessInternalAPI + --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 \ -serialwarn -encoding utf-8 -breakiterator -splitIndex --system none \ - -html5 -javafx --expand-requires transitive \ - -XDaccessInternalAPI + -html5 -javafx --expand-requires transitive # Should we add DRAFT stamps to the generated javadoc? ifeq ($(VERSION_IS_GA), true) diff --git a/make/jdk/src/classes/build/tools/taglet/JSpec.java b/make/jdk/src/classes/build/tools/taglet/JSpec.java index 7e1e0ca215e..196aaccb32b 100644 --- a/make/jdk/src/classes/build/tools/taglet/JSpec.java +++ b/make/jdk/src/classes/build/tools/taglet/JSpec.java @@ -25,13 +25,13 @@ package build.tools.taglet; +import java.net.URI; import java.util.EnumSet; import java.util.List; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; -import java.lang.reflect.Field; import javax.lang.model.element.Element; @@ -141,6 +141,11 @@ public class JSpec implements Taglet { @Override public String toString(List tags, Element elem) { + throw new UnsupportedOperationException(); + } + + // @Override - requires JDK-8373922 in build JDK + public String toString(List tags, Element elem, URI docRoot) { if (tags.isEmpty()) return ""; @@ -177,7 +182,7 @@ public class JSpec implements Taglet { String preview = m.group("preview"); // null if no preview feature String chapter = m.group("chapter"); String section = m.group("section"); - String rootParent = currentPath().replaceAll("[^/]+", ".."); + String rootParent = docRoot.resolve("..").toString(); String url = preview == null ? String.format("%1$s/specs/%2$s/%2$s-%3$s.html#%2$s-%3$s%4$s", @@ -230,23 +235,6 @@ public class JSpec implements Taglet { return sb.toString(); } - private static ThreadLocal CURRENT_PATH = null; - - private String currentPath() { - if (CURRENT_PATH == null) { - try { - Field f = Class.forName("jdk.javadoc.internal.doclets.formats.html.HtmlDocletWriter") - .getField("CURRENT_PATH"); - @SuppressWarnings("unchecked") - ThreadLocal tl = (ThreadLocal) f.get(null); - CURRENT_PATH = tl; - } catch (ReflectiveOperationException e) { - throw new RuntimeException("Cannot determine current path", e); - } - } - return CURRENT_PATH.get(); - } - private String expand(List trees) { return (new SimpleDocTreeVisitor() { public StringBuilder defaultAction(DocTree tree, StringBuilder sb) { diff --git a/make/jdk/src/classes/build/tools/taglet/SealedGraph.java b/make/jdk/src/classes/build/tools/taglet/SealedGraph.java index 2ffd92e3409..300999b77c0 100644 --- a/make/jdk/src/classes/build/tools/taglet/SealedGraph.java +++ b/make/jdk/src/classes/build/tools/taglet/SealedGraph.java @@ -32,7 +32,9 @@ import jdk.javadoc.doclet.Taglet; import javax.lang.model.element.*; import javax.lang.model.type.DeclaredType; +import javax.lang.model.util.Elements; import java.io.IOException; +import java.net.URI; import java.nio.file.Files; import java.nio.file.Path; import java.util.*; @@ -78,6 +80,11 @@ public final class SealedGraph implements Taglet { @Override public String toString(List tags, Element element) { + throw new UnsupportedOperationException(); + } + + // @Override - requires JDK-8373922 in build JDK + public String toString(List tags, Element element, URI docRoot) { if (sealedDotOutputDir == null || sealedDotOutputDir.isEmpty()) { return ""; } @@ -85,9 +92,15 @@ public final class SealedGraph implements Taglet { return ""; } - ModuleElement module = docletEnvironment.getElementUtils().getModuleOf(element); + Elements util = docletEnvironment.getElementUtils(); + ModuleElement module = util.getModuleOf(element); + + // '.' in .DOT file name is converted to '/' in .SVG path, so we use '-' as separator for nested classes. + // module_package.subpackage.Outer-Inner.dot => module/package/subpackage/Outer-Inner-sealed-graph.svg Path dotFile = Path.of(sealedDotOutputDir, - module.getQualifiedName() + "_" + typeElement.getQualifiedName() + ".dot"); + module.getQualifiedName() + "_" + + util.getPackageOf(element).getQualifiedName() + "." + + packagelessCanonicalName(typeElement).replace(".", "-") + ".dot"); Set exports = module.getDirectives().stream() .filter(ModuleElement.ExportsDirective.class::isInstance) @@ -99,7 +112,7 @@ public final class SealedGraph implements Taglet { .map(Objects::toString) .collect(Collectors.toUnmodifiableSet()); - String dotContent = new Renderer().graph(typeElement, exports); + String dotContent = new Renderer().graph(typeElement, exports, docRoot); try { Files.writeString(dotFile, dotContent, WRITE, CREATE, TRUNCATE_EXISTING); @@ -107,8 +120,8 @@ public final class SealedGraph implements Taglet { throw new RuntimeException(e); } - String simpleTypeName = packagelessCanonicalName(typeElement).replace('.', '/'); - String imageFile = simpleTypeName + "-sealed-graph.svg"; + String simpleTypeName = packagelessCanonicalName(typeElement); + String imageFile = simpleTypeName.replace(".", "-") + "-sealed-graph.svg"; int thumbnailHeight = 100; // also appears in the stylesheet String hoverImage = "" + getImage(simpleTypeName, imageFile, -1, true) @@ -137,12 +150,12 @@ public final class SealedGraph implements Taglet { private final class Renderer { // Generates a graph in DOT format - String graph(TypeElement rootClass, Set exports) { + String graph(TypeElement rootClass, Set exports, URI pathToRoot) { if (!isInPublicApi(rootClass, exports)) { // Alternatively we can return "" for the graph since there is no single root to render throw new IllegalArgumentException("Root not in public API: " + rootClass.getQualifiedName()); } - final State state = new State(rootClass); + final State state = new State(pathToRoot); traverse(state, rootClass, exports); return state.render(); } @@ -168,7 +181,7 @@ public final class SealedGraph implements Taglet { private static final String TOOLTIP = "tooltip"; private static final String LINK = "href"; - private final TypeElement rootNode; + private final URI pathToRoot; private final StringBuilder builder; @@ -193,8 +206,8 @@ public final class SealedGraph implements Taglet { } } - public State(TypeElement rootNode) { - this.rootNode = rootNode; + public State(URI pathToRoot) { + this.pathToRoot = pathToRoot; nodeStyleMap = new LinkedHashMap<>(); builder = new StringBuilder() .append("digraph G {") @@ -217,24 +230,15 @@ public final class SealedGraph implements Taglet { var styles = nodeStyleMap.computeIfAbsent(id(node), n -> new LinkedHashMap<>()); styles.put(LABEL, new StyleItem.PlainString(node.getSimpleName().toString())); styles.put(TOOLTIP, new StyleItem.PlainString(node.getQualifiedName().toString())); - styles.put(LINK, new StyleItem.PlainString(relativeLink(node))); + styles.put(LINK, new StyleItem.PlainString(pathToRoot.resolve(relativeLink(node)).toString())); } - // A permitted class must be in the same package or in the same module. - // This implies the module is always the same. private String relativeLink(TypeElement node) { var util = SealedGraph.this.docletEnvironment.getElementUtils(); - var nodePackage = util.getPackageOf(node); - // Note: SVG files for nested types use the simple names of containing types as parent directories. - // We therefore need to convert all dots in the qualified name to "../" below. - var backNavigator = rootNode.getQualifiedName().toString().chars() - .filter(c -> c == '.') - .mapToObj(c -> "../") - .collect(joining()); - var forwardNavigator = nodePackage.getQualifiedName().toString() - .replace(".", "/"); + var path = util.getModuleOf(node).getQualifiedName().toString() + "/" + + util.getPackageOf(node).getQualifiedName().toString().replace(".", "/"); - return backNavigator + forwardNavigator + "/" + packagelessCanonicalName(node) + ".html"; + return path + "/" + packagelessCanonicalName(node) + ".html"; } public void addEdge(TypeElement node, TypeElement subNode) { @@ -286,14 +290,6 @@ public final class SealedGraph implements Taglet { private String quotedId(TypeElement node) { return "\"" + id(node) + "\""; } - - private String simpleName(String name) { - int lastDot = name.lastIndexOf('.'); - return lastDot < 0 - ? name - : name.substring(lastDot); - } - } private static List permittedSubclasses(TypeElement node, Set exports) { diff --git a/make/jdk/src/classes/build/tools/taglet/ToolGuide.java b/make/jdk/src/classes/build/tools/taglet/ToolGuide.java index 8db2aee3092..7ad4f6b9b9f 100644 --- a/make/jdk/src/classes/build/tools/taglet/ToolGuide.java +++ b/make/jdk/src/classes/build/tools/taglet/ToolGuide.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,13 +25,13 @@ package build.tools.taglet; +import java.net.URI; import java.util.EnumSet; import java.util.List; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; -import java.lang.reflect.Field; import javax.lang.model.element.Element; @@ -91,6 +91,11 @@ public class ToolGuide implements Taglet { @Override public String toString(List tags, Element elem) { + throw new UnsupportedOperationException(); + } + + // @Override - requires JDK-8373922 in build JDK + public String toString(List tags, Element elem, URI docRoot) { if (tags.isEmpty()) return ""; @@ -118,7 +123,7 @@ public class ToolGuide implements Taglet { if (label.isEmpty()) { label = name; } - String rootParent = currentPath().replaceAll("[^/]+", ".."); + String rootParent = docRoot.resolve("..").toString(); String url = String.format("%s/%s/%s.html", rootParent, BASE_URL, name); @@ -141,22 +146,4 @@ public class ToolGuide implements Taglet { return sb.toString(); } - - private static ThreadLocal CURRENT_PATH = null; - - private String currentPath() { - if (CURRENT_PATH == null) { - try { - Field f = Class.forName("jdk.javadoc.internal.doclets.formats.html.HtmlDocletWriter") - .getField("CURRENT_PATH"); - @SuppressWarnings("unchecked") - ThreadLocal tl = (ThreadLocal) f.get(null); - CURRENT_PATH = tl; - } catch (ReflectiveOperationException e) { - throw new RuntimeException("Cannot determine current path", e); - } - } - return CURRENT_PATH.get(); - } - } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/doclet/StandardDoclet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/doclet/StandardDoclet.java index 8f5fec1e4b9..90511db8053 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/doclet/StandardDoclet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/doclet/StandardDoclet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,7 +48,7 @@ import jdk.javadoc.internal.doclets.formats.html.HtmlDoclet; * in documentation comments. * * Taglets invoked by the standard doclet must return strings from - * {@link Taglet#toString(List,Element) Taglet.toString} as follows: + * {@link Taglet#toString(List,Element,java.net.URI) Taglet.toString} as follows: * *
*
Inline Tags diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/doclet/Taglet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/doclet/Taglet.java index 1ad67a89fef..ec079047dfa 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/doclet/Taglet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/doclet/Taglet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * 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.javadoc.doclet; +import java.net.URI; import java.util.List; import java.util.Set; @@ -34,7 +35,7 @@ import com.sun.source.doctree.DocTree; /** * The interface for a custom taglet supported by doclets such as - * the {@link jdk.javadoc.doclet.StandardDoclet standard doclet}. + * the {@linkplain StandardDoclet standard doclet}. * Custom taglets are used to handle custom tags in documentation * comments; custom tags can be instantiated individually as either * block tags, which appear at the end of a comment, @@ -55,10 +56,10 @@ import com.sun.source.doctree.DocTree; * {@link #isInlineTag() isInlineTag}, to determine the characteristics * of the tags supported by the taglet. *
  • As appropriate, the doclet calls the - * {@link #toString(List,Element) toString} method on the taglet object, - * giving it a list of tags and the element for which the tags are part - * of the element's documentation comment, from which the taglet can - * determine the string to be included in the documentation. + * {@link #toString(List,Element,URI) toString} method on the taglet object, + * giving it a list of tags, the element whose documentation comment contains + * the tags, and the root URI of the generated output, from which the taglet + * can determine the string to be included in the documentation. * The doclet will typically specify any requirements on the contents of * the string that is returned. * @@ -126,25 +127,70 @@ public interface Taglet { default void init(DocletEnvironment env, Doclet doclet) { } /** - * Returns the string representation of a series of instances of - * this tag to be included in the generated output. + * Returns the string representation of the specified instances of this tag + * to be included in the generated output. * - *

    If this taglet supports {@link #isInlineTag inline} tags, it will + *

    If this taglet supports {@link #isInlineTag inline} tags, this method will * be called once per instance of the inline tag, each time with a singleton list. * If this taglet supports {@link #isBlockTag block} tags, it will be called once * for each comment containing instances of block tags, with a list of all the instances * of the block tag in that comment. * + * @apiNote Taglets that do not need the root URI of the generated output may + * implement this method only. Taglets that require the root URI to link to other + * doclet-generated resources should override {@link #toString(List, Element, URI)}, + * and optionally throw an exception in the implementation of this method. + * * @param tags the list of instances of this tag * @param element the element to which the enclosing comment belongs * @return the string representation of the tags to be included in * the generated output - * + * @throws UnsupportedOperationException if {@link #toString(List, Element, URI)} + * should be invoked instead * @see User-Defined Taglets * for the Standard Doclet + * @see #toString(List, Element, URI) */ String toString(List tags, Element element); + /** + * Returns the string representation of the specified instances of this tag + * to be included in the generated output. + * + *

    If this taglet supports {@link #isInlineTag inline} tags, this method will + * be called once per instance of the inline tag, each time with a singleton list. + * If this taglet supports {@link #isBlockTag block} tags, it will be called once + * for each comment containing instances of block tags, with a list of all the instances + * of the block tag in that comment. + * + *

    The {@code docRoot} argument identifies the root of the generated output + * as seen by the current resource, and may be used to {@linkplain URI#resolve(String) + * resolve} links to other resources generated by the doclet. + * + * @apiNote The exact form of {@code docRoot} is doclet-specific. For the + * {@linkplain StandardDoclet standard doclet}, it is a relative URI from + * the current resource to the root directory of the generated output. + * Taglets intended for use with other doclets should check the validity + * of the {@code docRoot} argument as appropriate. + * + * @implSpec The default implementation invokes {@link #toString(List, Element) + * toString(tags, element)}. + * + * @param tags the list of instances of this tag + * @param element the element to which the enclosing comment belongs + * @param docRoot the root URI of the generated output + * @return the string representation of the tags to be included in + * the generated output + * @throws IllegalArgumentException if {@code docRoot} is not a valid URI + * @see User-Defined Taglets + * for the Standard Doclet + * @see #toString(List, Element) + * @since 27 + */ + default String toString(List tags, Element element, URI docRoot) { + return toString(tags, element); + } + /** * The kind of location in which a tag may be used. */ diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java index 86ac3a892fd..594c36c4af2 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2026, Oracle and/or its affiliates. All rights reserved. * 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,12 +243,8 @@ public abstract class HtmlDocletWriter { if (generating) { writeGenerating(); } - CURRENT_PATH.set(path.getPath()); } - /** Temporary workaround to share current path with taglets, see 8373909 */ - public static final ThreadLocal CURRENT_PATH = new ThreadLocal<>(); - /** * The top-level method to generate and write the page represented by this writer. * diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/UserTaglet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/UserTaglet.java index d1884c53ccf..8d54aa0585b 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/UserTaglet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/UserTaglet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * 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.javadoc.internal.doclets.formats.html.taglets; +import java.net.URI; import java.util.List; import java.util.Set; @@ -70,7 +71,8 @@ public final class UserTaglet implements Taglet { @Override public Content getInlineTagOutput(Element element, DocTree tag, TagletWriter tagletWriter) { Content output = tagletWriter.getOutputInstance(); - output.add(RawHtml.of(userTaglet.toString(List.of(tag), element))); + URI pathToRoot = getPathToRoot(tagletWriter); + output.add(RawHtml.of(userTaglet.toString(List.of(tag), element, pathToRoot))); return output; } @@ -80,11 +82,17 @@ public final class UserTaglet implements Taglet { var utils = tagletWriter.utils; List tags = utils.getBlockTags(holder, getName()); if (!tags.isEmpty()) { - String tagString = userTaglet.toString(tags, holder); + URI pathToRoot = getPathToRoot(tagletWriter); + String tagString = userTaglet.toString(tags, holder, pathToRoot); if (tagString != null) { output.add(RawHtml.of(tagString)); } } return output; } + + private URI getPathToRoot(TagletWriter tagletWriter) { + var path = tagletWriter.htmlWriter.pathToRoot.getPath(); + return URI.create(path.isEmpty() || path.endsWith("/") ? path : path + "/"); + } } diff --git a/test/langtools/jdk/javadoc/doclet/testRelativeURLTaglet/TestRelativeURLTaglet.java b/test/langtools/jdk/javadoc/doclet/testRelativeURLTaglet/TestRelativeURLTaglet.java new file mode 100644 index 00000000000..72b1de22cd2 --- /dev/null +++ b/test/langtools/jdk/javadoc/doclet/testRelativeURLTaglet/TestRelativeURLTaglet.java @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8373922 + * @summary Enhance Taglet API to support relative URLs + * @library /tools/lib ../../lib + * @modules jdk.javadoc/jdk.javadoc.internal.tool + * jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * @build toolbox.ToolBox javadoc.tester.* + * @run main TestRelativeURLTaglet + */ + +import java.net.URI; +import java.nio.file.Path; +import java.util.EnumSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import javax.lang.model.element.Element; + +import com.sun.source.doctree.DocTree; +import com.sun.source.doctree.UnknownBlockTagTree; +import com.sun.source.doctree.UnknownInlineTagTree; +import javadoc.tester.JavadocTester; +import jdk.javadoc.doclet.Taglet; +import toolbox.ModuleBuilder; +import toolbox.ToolBox; + +public class TestRelativeURLTaglet extends JavadocTester implements Taglet { + + public static void main(String... args) throws Exception { + new TestRelativeURLTaglet().runTests(); + } + + ToolBox tb = new ToolBox(); + + @Test + public void testRelativePackageURL(Path base) throws Exception { + Path src = base.resolve("src"); + tb.writeJavaFiles(src, """ + package p.q; + /** + * First {@test sentence}. + */ + public interface A {} + """, + """ + package p.q.r; + /** + * Comment {@test with} inline {@test tags}. + * + * @test 123 + * @test 456 + */ + public class C {} + """); + tb.writeFile(src.resolve("p/q/doc-files/test.html"), """ + + + HTML {@test file} with {@test inline} tags. + + + """); + + javadoc("-d", base.resolve("out").toString(), + "--source-path", src.toString(), + "-tagletpath", System.getProperty("test.class.path"), + "-taglet", "TestRelativeURLTaglet", + "-subpackages", "p"); + checkExit(Exit.OK); + + checkOutput("p/q/A.html", true, + "First ../../sentence."); + checkOutput("p/q/package-summary.html", true, + "First ../../sentence."); + checkOutput("p/q/doc-files/test.html", true, + "HTML ../../../file with ../../../inline tags."); + checkOutput("p/q/r/C.html", true, + "Comment ../../../with inline ../../../tags.", + "../../../123 ../../../456"); + checkOutput("p/q/r/package-summary.html", true, + "Comment ../../../with inline ../../../tags."); + checkOutput("index-all.html", true, + "First sentence.", + "Comment with inline tags."); + checkOutput("allclasses-index.html", true, + "First sentence.", + "Comment with inline tags."); + } + + @Test + public void testRelativeModuleURL(Path base) throws Exception { + Path src = base.resolve("src"); + new ModuleBuilder(tb, "ma") + .comment("Module {@test ma}.") + .classes( + """ + /** + * Package {@test ma/p/a}. + */ + package p.a; + """, + """ + package p.a; + /** + * Class in {@test ma/p/a}. + * + * @test block1 + * @test block2 + */ + public class A {} + """) + .exports("p.a") + .write(src); + + javadoc("-d", base.resolve("out").toString(), + "--module-source-path", src.toString(), + "-tagletpath", System.getProperty("test.class.path"), + "-taglet", "TestRelativeURLTaglet", + "--module", "ma"); + checkExit(Exit.OK); + + checkOutput("ma/p/a/package-summary.html", true, + "Package ../../../ma/p/a.", + "Class in ../../../ma/p/a."); + checkOutput("ma/p/a/A.html", true, + "Class in ../../../ma/p/a.", + "

    ../../../block1 ../../../block2
    "); + checkOutput("ma/module-summary.html", true, + "Module ../ma.", + "Package ../ma/p/a."); + checkOutput("index-all.html", true, + "Class in ma/p/a.", + "Module ma.", + "Package ma/p/a."); + } + + @Test + public void testUnnamedPackageURL(Path base) throws Exception { + Path src = base.resolve("src"); + tb.writeJavaFiles(src, """ + /** + * Class in unnamed package: {@test tag}. + * + * @test first + * @test second + */ + public class C {} + """); + + javadoc("-d", base.resolve("out").toString(), + "--source-path", src.toString(), + "-tagletpath", System.getProperty("test.class.path"), + "-taglet", "TestRelativeURLTaglet", + src.resolve("C.java").toString()); + checkExit(Exit.OK); + + checkOutput("C.html", true, + "Class in unnamed package: tag.", + "
    first second
    "); + checkOutput("index-all.html", true, + "Class in unnamed package: tag."); + checkOutput("allclasses-index.html", true, + "Class in unnamed package: tag."); + } + + // Taglet implementation + + @Override + public Set getAllowedLocations() { + return EnumSet.allOf(Location.class); + } + + @Override + public boolean isInlineTag() { + return true; + } + + @Override + public boolean isBlockTag() { + return true; + } + + @Override + public String getName() { + return "test"; + } + + @Override + public String toString(List tags, Element element, URI docRoot) { + if (tags.size() == 1 && tags.getFirst() instanceof UnknownInlineTagTree uit) { + return docRoot.resolve(uit.getContent().toString()).toString(); + } else { + return tags.stream() + .map(t -> docRoot.resolve(((UnknownBlockTagTree) t).getContent().toString()).toString()) + .collect(Collectors.joining(" ")); + } + } + + @Override + public String toString(List tags, Element element) { + throw new UnsupportedOperationException(); + } +} + From 8aafaf07e90264f8fef8b0a09cce50e5371c6103 Mon Sep 17 00:00:00 2001 From: Leonid Mesnik Date: Thu, 16 Apr 2026 15:08:49 +0000 Subject: [PATCH 313/359] 8356223: ProblemList-AotJdk.txt should be added automatically if AOT mode is tested Reviewed-by: erikj, epavlova --- make/RunTests.gmk | 3 +++ 1 file changed, 3 insertions(+) diff --git a/make/RunTests.gmk b/make/RunTests.gmk index 02ea632e3ec..d4be5936c41 100644 --- a/make/RunTests.gmk +++ b/make/RunTests.gmk @@ -1020,6 +1020,9 @@ define SetupRunJtregTestBody VM_OPTIONS := $$(JTREG_ALL_OPTIONS) )) $$(call LogWarn, AOT_JDK_CACHE=$$($1_AOT_JDK_CACHE)) $1_JTREG_BASIC_OPTIONS += -vmoption:-XX:AOTCache="$$($1_AOT_JDK_CACHE)" + $1_JTREG_BASIC_OPTIONS += $$(addprefix $$(JTREG_PROBLEM_LIST_PREFIX), $$(wildcard \ + $$(addprefix $$($1_TEST_ROOT)/, ProblemList-AotJdk.txt) \ + )) endif From 0ca24c0e57b0dc40c98533ecbb37a9378bb7aa13 Mon Sep 17 00:00:00 2001 From: Chris Hegarty Date: Thu, 16 Apr 2026 16:19:02 +0000 Subject: [PATCH 314/359] 8382267: VectorMathLibrary uses locale-sensitive String.format to construct native symbol names Reviewed-by: naoto, liach, vlivanov --- .../incubator/vector/VectorMathLibrary.java | 5 +- .../vector/VectorMathLibraryLocaleTest.java | 53 +++++++++++++++++++ 2 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 test/jdk/jdk/incubator/vector/VectorMathLibraryLocaleTest.java diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorMathLibrary.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorMathLibrary.java index 823cebd85a9..59697733d86 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorMathLibrary.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorMathLibrary.java @@ -31,6 +31,7 @@ import jdk.internal.vm.vector.VectorSupport; import java.lang.foreign.MemorySegment; import java.lang.foreign.SymbolLookup; +import java.util.Locale; import java.util.function.IntFunction; import static jdk.incubator.vector.Util.requires; @@ -141,7 +142,7 @@ import static jdk.internal.vm.vector.Utils.debug; String elemType = (vspecies.elementType() == float.class ? "f" : ""); boolean isFloatVector64 = (vspecies.elementType() == float.class) && (vspecies.length() == 2); // FloatVector64 or FloatVectorMax int vlen = (isFloatVector64 ? 4 : vspecies.length()); // reuse 128-bit variant for 64-bit float vectors - return String.format("__jsvml_%s%s%d_ha_%s", op.operatorName(), elemType, vlen, suffix); + return String.format(Locale.ROOT, "__jsvml_%s%s%d_ha_%s", op.operatorName(), elemType, vlen, suffix); } @Override @@ -214,7 +215,7 @@ import static jdk.internal.vm.vector.Utils.debug; boolean isFloatVector64 = (vspecies.elementType() == float.class) && (vspecies.length() == 2); // FloatVector64 or FloatVectorMax int vlen = (isFloatVector64 ? 4 : vspecies.length()); // reuse 128-bit variant for 64-bit float vectors boolean isShapeAgnostic = isRISCV64() || (isAARCH64() && vspecies.vectorBitSize() > 128); - return String.format("%s%s%s_%s%s", op.operatorName(), + return String.format(Locale.ROOT, "%s%s%s_%s%s", op.operatorName(), (vspecies.elementType() == float.class ? "f" : "d"), (isShapeAgnostic ? "x" : Integer.toString(vlen)), precisionLevel(op), diff --git a/test/jdk/jdk/incubator/vector/VectorMathLibraryLocaleTest.java b/test/jdk/jdk/incubator/vector/VectorMathLibraryLocaleTest.java new file mode 100644 index 00000000000..c093df397e5 --- /dev/null +++ b/test/jdk/jdk/incubator/vector/VectorMathLibraryLocaleTest.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8382267 + * @summary VectorMathLibrary symbol names must not use locale-sensitive formatting + * @modules jdk.incubator.vector + * @run main/othervm -ea -Duser.language=ar -Duser.country=SA VectorMathLibraryLocaleTest + */ + +import java.util.Locale; + +import jdk.incubator.vector.FloatVector; +import jdk.incubator.vector.VectorOperators; +import jdk.incubator.vector.VectorSpecies; + +public class VectorMathLibraryLocaleTest { + public static void main(String[] args) { + assert !String.format("%d", 16).equals("16") : "expected non-ASCII digits for locale " + Locale.getDefault(); + + VectorSpecies species = FloatVector.SPECIES_PREFERRED; + FloatVector v = FloatVector.broadcast(species, 1.0f); + + // Without the fix, this throws InternalError due to locale-mangled symbol name. + // The assertion below is just a sanity check on the result. + FloatVector result = v.lanewise(VectorOperators.EXP); + float expected = (float) Math.E; + for (int i = 0; i < species.length(); i++) { + assert result.lane(i) == expected : "lane " + i + ": expected " + expected + ", got " + result.lane(i); + } + } +} From 74c3d426b05ab0a0b2b7d3d6ee3ce9d5f4c977e1 Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Thu, 16 Apr 2026 17:48:31 +0000 Subject: [PATCH 315/359] 8382103: Shenandoah: Optimize ShenandoahLock size for release build Reviewed-by: xpeng, kdnilsen, wkemper --- src/hotspot/share/gc/shenandoah/shenandoahLock.hpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahLock.hpp b/src/hotspot/share/gc/shenandoah/shenandoahLock.hpp index 7c91df191e5..5041419b2c7 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahLock.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahLock.hpp @@ -38,15 +38,19 @@ private: shenandoah_padding(0); Atomic _state; shenandoah_padding(1); +#ifdef ASSERT Atomic _owner; shenandoah_padding(2); +#endif template void contended_lock_internal(JavaThread* java_thread); static void yield_or_sleep(int &yields); public: - ShenandoahLock() : _state(unlocked), _owner(nullptr) {}; + ShenandoahLock() : _state(unlocked) { + DEBUG_ONLY(_owner.store_relaxed(nullptr);) + }; void lock(bool allow_block_for_safepoint = false) { assert(_owner.load_relaxed() != Thread::current(), "reentrant locking attempt, would deadlock"); From d6a255d74ce2b3cb197343208946fdaed11ca08e Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Thu, 16 Apr 2026 17:49:05 +0000 Subject: [PATCH 316/359] 8381933: Possible memory leak in src/hotspot/share/gc/shenandoah/shenandoahHeapRegionCounters.cpp Reviewed-by: kdnilsen, wkemper --- src/hotspot/share/gc/shenandoah/shenandoahHeapRegionCounters.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionCounters.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionCounters.cpp index ff1e3368e87..aaf152e2890 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionCounters.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionCounters.cpp @@ -78,6 +78,7 @@ ShenandoahHeapRegionCounters::ShenandoahHeapRegionCounters() : ShenandoahHeapRegionCounters::~ShenandoahHeapRegionCounters() { if (_name_space != nullptr) FREE_C_HEAP_ARRAY(char, _name_space); + if (_regions_data != nullptr) FREE_C_HEAP_ARRAY(PerfVariable*, _regions_data); } void ShenandoahHeapRegionCounters::write_snapshot(PerfLongVariable** regions, From 70d0651090c52d32349bf8efe0f577870503785f Mon Sep 17 00:00:00 2001 From: Shiv Shah Date: Thu, 16 Apr 2026 17:57:01 +0000 Subject: [PATCH 317/359] 8316439: Several jvmti tests fail with -Xcheck:jni Reviewed-by: lmesnik, dholmes, cjplummer, epavlova, sspitsyn --- .../PopFrame/popframe007/popframe007.cpp | 7 ++++-- .../retransform003/retransform003.cpp | 10 ++++++-- .../jtreg/vmTestbase/nsk/share/aod/aod.cpp | 24 ++++++++++++++++++- 3 files changed, 36 insertions(+), 5 deletions(-) diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/PopFrame/popframe007/popframe007.cpp b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/PopFrame/popframe007/popframe007.cpp index a2e9716a513..4b929fd4d03 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/PopFrame/popframe007/popframe007.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/PopFrame/popframe007/popframe007.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ static jvmtiEventCallbacks callbacks; static jint result = PASSED; static jboolean printdump = JNI_FALSE; static jmethodID mid; +static jclass testThreadClass = nullptr; void JNICALL Breakpoint(jvmtiEnv *jvmti_env, JNIEnv *env, jthread thread, jmethodID method, jlocation location) { @@ -166,6 +167,8 @@ Java_nsk_jvmti_PopFrame_popframe007_getReady(JNIEnv *env, return; } + testThreadClass = (jclass)env->NewGlobalRef(clazz); + err = jvmti->SetBreakpoint(mid, 0); if (err != JVMTI_ERROR_NONE) { printf("(SetBreakpoint) unexpected error: %s (%d)\n", @@ -191,7 +194,7 @@ Java_nsk_jvmti_PopFrame_popframe007_getRes(JNIEnv *env, jclass cls) { JNIEXPORT void JNICALL Java_nsk_jvmti_PopFrame_popframe007_B(JNIEnv *env, jclass cls) { if (mid != nullptr) { - env->CallStaticVoidMethod(cls, mid); + env->CallStaticVoidMethod(testThreadClass, mid); } } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/RetransformClasses/retransform003/retransform003.cpp b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/RetransformClasses/retransform003/retransform003.cpp index cda8481533d..f7ad0b65ff3 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/RetransformClasses/retransform003/retransform003.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/RetransformClasses/retransform003/retransform003.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -113,6 +113,12 @@ ClassFileLoadHook ( loader, method_id, class_name_string)) != nullptr)) return; + if (jni->ExceptionCheck()) { + jni->ExceptionDescribe(); + jni->ExceptionClear(); + return; + } + if (!NSK_VERIFY((method_id = jni->GetStaticMethodID( callback_class, "callback", "(Ljava/lang/String;I)V")) != nullptr)) return; @@ -120,7 +126,7 @@ ClassFileLoadHook ( if (!NSK_VERIFY((class_name_string = jni->NewStringUTF(name)) != nullptr)) return; - jni->CallStaticObjectMethod(callback_class, method_id, class_name_string, agent_id); + NSK_JNI_VERIFY_VOID(jni, jni->CallStaticVoidMethod(callback_class, method_id, class_name_string, agent_id)); } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/aod/aod.cpp b/test/hotspot/jtreg/vmTestbase/nsk/share/aod/aod.cpp index 7f622c24f75..7f82caa7259 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/aod/aod.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/aod/aod.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2026, Oracle and/or its affiliates. All rights reserved. * 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,20 @@ extern "C" { static volatile int internalError = 0; +/* + * Check for pending JNI exceptions after a JNI call. + * If an exception is found, describe it, clear it, and return failure. + */ +static int nsk_aod_checkJNIException(JNIEnv* jni) { + if (jni->ExceptionCheck()) { + jni->ExceptionDescribe(); + jni->ExceptionClear(); + NSK_COMPLAIN0("Unexpected exception after JNI call\n"); + return NSK_FALSE; + } + return NSK_TRUE; +} + /* * This function can be used to inform AOD framework that some non critical for test logic * error happened inside shared function (e.g. JVMTI Deallocate failed). @@ -227,6 +241,10 @@ int nsk_aod_agentLoaded(JNIEnv* jni, const char* agentName) { jni->CallStaticVoidMethod(targetAppClass, agentLoadedMethod, agentNameString); + if (!nsk_aod_checkJNIException(jni)) { + return NSK_FALSE; + } + return NSK_TRUE; } @@ -263,6 +281,10 @@ int nsk_aod_agentFinished(JNIEnv* jni, const char* agentName, int success) { jni->CallStaticVoidMethod(targetAppClass, agentFinishedMethod, agentNameString, success ? JNI_TRUE : JNI_FALSE); + if (!nsk_aod_checkJNIException(jni)) { + return NSK_FALSE; + } + return NSK_TRUE; } From 2c30f120800cd8ad2a54ef17780ed57dd3c336ad Mon Sep 17 00:00:00 2001 From: Matias Saavedra Silva Date: Thu, 16 Apr 2026 18:16:10 +0000 Subject: [PATCH 318/359] 8347248: Rename arg_count to arg_size Reviewed-by: dlong, iklam --- src/hotspot/share/ci/ciMethodData.cpp | 12 ++++++------ src/hotspot/share/oops/methodData.cpp | 4 ++-- src/hotspot/share/oops/methodData.hpp | 2 +- src/hotspot/share/oops/methodData.inline.hpp | 4 ++-- src/hotspot/share/prims/jni.cpp | 3 +-- src/hotspot/share/prims/whitebox.cpp | 4 ++-- 6 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/hotspot/share/ci/ciMethodData.cpp b/src/hotspot/share/ci/ciMethodData.cpp index 533e8659968..5e623e2b965 100644 --- a/src/hotspot/share/ci/ciMethodData.cpp +++ b/src/hotspot/share/ci/ciMethodData.cpp @@ -537,8 +537,8 @@ void ciMethodData::clear_escape_info() { if (mdo != nullptr) { mdo->clear_escape_info(); ArgInfoData *aid = arg_info(); - int arg_count = (aid == nullptr) ? 0 : aid->number_of_args(); - for (int i = 0; i < arg_count; i++) { + int arg_size = (aid == nullptr) ? 0 : aid->size_of_args(); + for (int i = 0; i < arg_size; i++) { set_arg_modified(i, 0); } } @@ -554,8 +554,8 @@ void ciMethodData::update_escape_info() { mdo->set_arg_local(_arg_local); mdo->set_arg_stack(_arg_stack); mdo->set_arg_returned(_arg_returned); - int arg_count = mdo->method()->size_of_parameters(); - for (int i = 0; i < arg_count; i++) { + int arg_size = mdo->method()->size_of_parameters(); + for (int i = 0; i < arg_size; i++) { mdo->set_arg_modified(i, arg_modified(i)); } } @@ -652,7 +652,7 @@ void ciMethodData::set_arg_modified(int arg, uint val) { ArgInfoData *aid = arg_info(); if (aid == nullptr) return; - assert(arg >= 0 && arg < aid->number_of_args(), "valid argument number"); + assert(arg >= 0 && arg < aid->size_of_args(), "valid argument number"); aid->set_arg_modified(arg, val); } @@ -672,7 +672,7 @@ uint ciMethodData::arg_modified(int arg) const { ArgInfoData *aid = arg_info(); if (aid == nullptr) return 0; - assert(arg >= 0 && arg < aid->number_of_args(), "valid argument number"); + assert(arg >= 0 && arg < aid->size_of_args(), "valid argument number"); return aid->arg_modified(arg); } diff --git a/src/hotspot/share/oops/methodData.cpp b/src/hotspot/share/oops/methodData.cpp index ad1049ffa34..dc0b8fa9f81 100644 --- a/src/hotspot/share/oops/methodData.cpp +++ b/src/hotspot/share/oops/methodData.cpp @@ -667,8 +667,8 @@ void MultiBranchData::print_data_on(outputStream* st, const char* extra) const { void ArgInfoData::print_data_on(outputStream* st, const char* extra) const { print_shared(st, "ArgInfoData", extra); - int nargs = number_of_args(); - for (int i = 0; i < nargs; i++) { + int args_size = size_of_args(); + for (int i = 0; i < args_size; i++) { st->print(" 0x%x", arg_modified(i)); } st->cr(); diff --git a/src/hotspot/share/oops/methodData.hpp b/src/hotspot/share/oops/methodData.hpp index 196537359b5..45529618afb 100644 --- a/src/hotspot/share/oops/methodData.hpp +++ b/src/hotspot/share/oops/methodData.hpp @@ -1751,7 +1751,7 @@ public: virtual bool is_ArgInfoData() const { return true; } - int number_of_args() const { + int size_of_args() const { return array_len(); } diff --git a/src/hotspot/share/oops/methodData.inline.hpp b/src/hotspot/share/oops/methodData.inline.hpp index dee14d49253..b417ba867fc 100644 --- a/src/hotspot/share/oops/methodData.inline.hpp +++ b/src/hotspot/share/oops/methodData.inline.hpp @@ -59,7 +59,7 @@ inline uint MethodData::arg_modified(int a) { MutexLocker ml(extra_data_lock(), Mutex::_no_safepoint_check_flag); ArgInfoData* aid = arg_info(); assert(aid != nullptr, "arg_info must be not null"); - assert(a >= 0 && a < aid->number_of_args(), "valid argument number"); + assert(a >= 0 && a < aid->size_of_args(), "valid argument number"); return aid->arg_modified(a); } @@ -68,7 +68,7 @@ inline void MethodData::set_arg_modified(int a, uint v) { MutexLocker ml(extra_data_lock(), Mutex::_no_safepoint_check_flag); ArgInfoData* aid = arg_info(); assert(aid != nullptr, "arg_info must be not null"); - assert(a >= 0 && a < aid->number_of_args(), "valid argument number"); + assert(a >= 0 && a < aid->size_of_args(), "valid argument number"); aid->set_arg_modified(a, v); } diff --git a/src/hotspot/share/prims/jni.cpp b/src/hotspot/share/prims/jni.cpp index 85207fddf29..73082c6047d 100644 --- a/src/hotspot/share/prims/jni.cpp +++ b/src/hotspot/share/prims/jni.cpp @@ -867,8 +867,7 @@ static void jni_invoke_static(JNIEnv *env, JavaValue* result, jobject receiver, // Create object to hold arguments for the JavaCall, and associate it with // the jni parser ResourceMark rm(THREAD); - int number_of_parameters = method->size_of_parameters(); - JavaCallArguments java_args(number_of_parameters); + JavaCallArguments java_args(method->size_of_parameters()); assert(method->is_static(), "method should be static"); diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index f50e6ddb3db..de140fb95ff 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -1280,8 +1280,8 @@ WB_ENTRY(void, WB_ClearMethodState(JNIEnv* env, jobject o, jobject method)) if (mdo != nullptr) { mdo->init(); ResourceMark rm(THREAD); - int arg_count = mdo->method()->size_of_parameters(); - for (int i = 0; i < arg_count; i++) { + int arg_size = mdo->method()->size_of_parameters(); + for (int i = 0; i < arg_size; i++) { mdo->set_arg_modified(i, 0); } mdo->clean_method_data(/*always_clean*/true); From 17ee366ff964ea4e50b419a033bab973c46f601c Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Thu, 16 Apr 2026 18:20:29 +0000 Subject: [PATCH 319/359] 8382150: Shenandoah: Clean up nmethod entry barrier support Reviewed-by: xpeng, kdnilsen, wkemper --- .../gc/shenandoah/shenandoahClosures.hpp | 3 -- .../shenandoah/shenandoahClosures.inline.hpp | 6 +-- .../gc/shenandoah/shenandoahCodeRoots.cpp | 37 ++----------------- .../gc/shenandoah/shenandoahCodeRoots.hpp | 5 +-- .../gc/shenandoah/shenandoahConcurrentGC.cpp | 17 +++------ .../gc/shenandoah/shenandoahRootProcessor.cpp | 5 +-- .../shenandoahRootProcessor.inline.hpp | 6 +-- .../share/gc/shenandoah/shenandoahSTWMark.cpp | 2 +- 8 files changed, 16 insertions(+), 65 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp b/src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp index fefed0340c4..9ab45380c61 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp @@ -180,9 +180,6 @@ public: }; class ShenandoahNMethodAndDisarmClosure : public NMethodToOopClosure { -private: - BarrierSetNMethod* const _bs; - public: inline ShenandoahNMethodAndDisarmClosure(OopClosure* cl); inline void do_nmethod(nmethod* nm); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahClosures.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahClosures.inline.hpp index e8d25b1e5a9..96ecbad1145 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahClosures.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahClosures.inline.hpp @@ -209,15 +209,13 @@ void ShenandoahCleanUpdateWeakOopsClosure::do_oo } ShenandoahNMethodAndDisarmClosure::ShenandoahNMethodAndDisarmClosure(OopClosure* cl) : - NMethodToOopClosure(cl, true /* fix_relocations */), - _bs(BarrierSet::barrier_set()->barrier_set_nmethod()) { -} + NMethodToOopClosure(cl, true /* fix_relocations */) {} void ShenandoahNMethodAndDisarmClosure::do_nmethod(nmethod* nm) { assert(nm != nullptr, "Sanity"); assert(!ShenandoahNMethod::gc_data(nm)->is_unregistered(), "Should not be here"); NMethodToOopClosure::do_nmethod(nm); - _bs->disarm(nm); + ShenandoahNMethod::disarm_nmethod(nm); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.cpp b/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.cpp index 64e135e9a4e..7cf60cdf65c 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.cpp @@ -40,20 +40,6 @@ ShenandoahNMethodTable* ShenandoahCodeRoots::_nmethod_table; int ShenandoahCodeRoots::_disarmed_value = 1; -bool ShenandoahCodeRoots::use_nmethod_barriers_for_mark() { - // Continuations need nmethod barriers for scanning stack chunk nmethods. - if (Continuations::enabled()) return true; - - // Concurrent class unloading needs nmethod barriers. - // When a nmethod is about to be executed, we need to make sure that all its - // metadata are marked. The alternative is to remark thread roots at final mark - // pause, which would cause latency issues. - if (ShenandoahHeap::heap()->unload_classes()) return true; - - // Otherwise, we can go without nmethod barriers. - return false; -} - void ShenandoahCodeRoots::initialize() { _nmethod_table = new ShenandoahNMethodTable(); } @@ -68,27 +54,14 @@ void ShenandoahCodeRoots::unregister_nmethod(nmethod* nm) { _nmethod_table->unregister_nmethod(nm); } -void ShenandoahCodeRoots::arm_nmethods_for_mark() { - if (use_nmethod_barriers_for_mark()) { - BarrierSet::barrier_set()->barrier_set_nmethod()->arm_all_nmethods(); - } -} - -void ShenandoahCodeRoots::arm_nmethods_for_evac() { +void ShenandoahCodeRoots::arm_nmethods() { BarrierSet::barrier_set()->barrier_set_nmethod()->arm_all_nmethods(); } class ShenandoahDisarmNMethodClosure : public NMethodClosure { -private: - BarrierSetNMethod* const _bs; - public: - ShenandoahDisarmNMethodClosure() : - _bs(BarrierSet::barrier_set()->barrier_set_nmethod()) { - } - virtual void do_nmethod(nmethod* nm) { - _bs->disarm(nm); + ShenandoahNMethod::disarm_nmethod(nm); } }; @@ -111,10 +84,8 @@ public: }; void ShenandoahCodeRoots::disarm_nmethods() { - if (use_nmethod_barriers_for_mark()) { - ShenandoahDisarmNMethodsTask task; - ShenandoahHeap::heap()->workers()->run_task(&task); - } + ShenandoahDisarmNMethodsTask task; + ShenandoahHeap::heap()->workers()->run_task(&task); } class ShenandoahNMethodUnlinkClosure : public NMethodClosure { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.hpp b/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.hpp index d29c446f210..d395b4516f4 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.hpp @@ -67,14 +67,11 @@ public: // Concurrent nmethod unloading support static void unlink(WorkerThreads* workers, bool unloading_occurred); static void purge(); - static void arm_nmethods_for_mark(); - static void arm_nmethods_for_evac(); + static void arm_nmethods(); static void disarm_nmethods(); static int disarmed_value() { return _disarmed_value; } static int* disarmed_value_address() { return &_disarmed_value; } - static bool use_nmethod_barriers_for_mark(); - private: static ShenandoahNMethodTable* _nmethod_table; static int _disarmed_value; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp index ba0aa1a1304..af4cec03221 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp @@ -744,9 +744,8 @@ void ShenandoahConcurrentGC::op_init_mark() { // Make above changes visible to worker threads OrderAccess::fence(); - // Arm nmethods for concurrent mark - ShenandoahCodeRoots::arm_nmethods_for_mark(); - + // Arm nmethods/stack for concurrent processing + ShenandoahCodeRoots::arm_nmethods(); ShenandoahStackWatermark::change_epoch_id(); { @@ -805,7 +804,7 @@ void ShenandoahConcurrentGC::op_final_mark() { heap->set_has_forwarded_objects(true); // Arm nmethods/stack for concurrent processing - ShenandoahCodeRoots::arm_nmethods_for_evac(); + ShenandoahCodeRoots::arm_nmethods(); ShenandoahStackWatermark::change_epoch_id(); } else { @@ -1035,14 +1034,10 @@ void ShenandoahConcurrentGC::op_class_unloading() { class ShenandoahEvacUpdateCodeCacheClosure : public NMethodClosure { private: - BarrierSetNMethod* const _bs; ShenandoahEvacuateUpdateMetadataClosure _cl; public: - ShenandoahEvacUpdateCodeCacheClosure() : - _bs(BarrierSet::barrier_set()->barrier_set_nmethod()), - _cl() { - } + ShenandoahEvacUpdateCodeCacheClosure() : _cl() {} void do_nmethod(nmethod* n) { ShenandoahNMethod* data = ShenandoahNMethod::gc_data(n); @@ -1050,8 +1045,8 @@ public: // Setup EvacOOM scope below reentrant lock to avoid deadlock with // nmethod_entry_barrier ShenandoahEvacOOMScope oom; - data->oops_do(&_cl, true/*fix relocation*/); - _bs->disarm(n); + data->oops_do(&_cl, /* fix_relocations = */ true); + ShenandoahNMethod::disarm_nmethod(n); } }; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp index 7b68e6ac625..80825ac43ad 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp @@ -200,9 +200,6 @@ ShenandoahRootAdjuster::ShenandoahRootAdjuster(uint n_workers, ShenandoahPhaseTi void ShenandoahRootAdjuster::roots_do(uint worker_id, OopClosure* oops) { NMethodToOopClosure code_blob_cl(oops, NMethodToOopClosure::FixRelocations); ShenandoahNMethodAndDisarmClosure nmethods_and_disarm_Cl(oops); - NMethodToOopClosure* adjust_code_closure = ShenandoahCodeRoots::use_nmethod_barriers_for_mark() ? - static_cast(&nmethods_and_disarm_Cl) : - static_cast(&code_blob_cl); CLDToOopClosure adjust_cld_closure(oops, ClassLoaderData::_claim_strong); // Process light-weight/limited parallel roots then @@ -211,7 +208,7 @@ void ShenandoahRootAdjuster::roots_do(uint worker_id, OopClosure* oops) { _cld_roots.cld_do(&adjust_cld_closure, worker_id); // Process heavy-weight/fully parallel roots the last - _code_roots.nmethods_do(adjust_code_closure, worker_id); + _code_roots.nmethods_do(&nmethods_and_disarm_Cl, worker_id); _thread_roots.oops_do(oops, nullptr, worker_id); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.inline.hpp index 6aebec28163..4504ac96819 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.inline.hpp @@ -172,10 +172,6 @@ template void ShenandoahRootUpdater::roots_do(uint worker_id, IsAlive* is_alive, KeepAlive* keep_alive) { NMethodToOopClosure update_nmethods(keep_alive, NMethodToOopClosure::FixRelocations); ShenandoahNMethodAndDisarmClosure nmethods_and_disarm_Cl(keep_alive); - NMethodToOopClosure* codes_cl = ShenandoahCodeRoots::use_nmethod_barriers_for_mark() ? - static_cast(&nmethods_and_disarm_Cl) : - static_cast(&update_nmethods); - CLDToOopClosure clds(keep_alive, ClassLoaderData::_claim_strong); // Process light-weight/limited parallel roots then @@ -184,7 +180,7 @@ void ShenandoahRootUpdater::roots_do(uint worker_id, IsAlive* is_alive, KeepAliv _cld_roots.cld_do(&clds, worker_id); // Process heavy-weight/fully parallel roots the last - _code_roots.nmethods_do(codes_cl, worker_id); + _code_roots.nmethods_do(&nmethods_and_disarm_Cl, worker_id); _thread_roots.oops_do(keep_alive, nullptr, worker_id); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp index 117984a6d41..5b4ce6d0bc9 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp @@ -74,7 +74,7 @@ void ShenandoahSTWMark::mark() { // Arm all nmethods. Even though this is STW mark, some marking code // piggybacks on nmethod barriers for special instances. - ShenandoahCodeRoots::arm_nmethods_for_mark(); + ShenandoahCodeRoots::arm_nmethods(); // Weak reference processing ShenandoahReferenceProcessor* rp = _generation->ref_processor(); From 10e23dd5823258cfbf500175dde23be12cdd99bf Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Thu, 16 Apr 2026 18:25:35 +0000 Subject: [PATCH 320/359] 8382257: Shenandoah: Clean up stack watermark barrier support Reviewed-by: kdnilsen, wkemper --- .../shenandoah/mode/shenandoahPassiveMode.cpp | 1 - .../gc/shenandoah/mode/shenandoahSATBMode.cpp | 1 - .../gc/shenandoah/shenandoahBarrierSet.cpp | 22 ++++++++----------- .../gc/shenandoah/shenandoah_globals.hpp | 3 --- .../options/TestSelectiveBarrierFlags.java | 3 +-- .../options/TestWrongBarrierDisable.java | 3 +-- .../options/TestWrongBarrierEnable.java | 4 +--- 7 files changed, 12 insertions(+), 25 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/mode/shenandoahPassiveMode.cpp b/src/hotspot/share/gc/shenandoah/mode/shenandoahPassiveMode.cpp index 41b2703730b..cc098bc5a21 100644 --- a/src/hotspot/share/gc/shenandoah/mode/shenandoahPassiveMode.cpp +++ b/src/hotspot/share/gc/shenandoah/mode/shenandoahPassiveMode.cpp @@ -50,7 +50,6 @@ void ShenandoahPassiveMode::initialize_flags() const { SHENANDOAH_ERGO_DISABLE_FLAG(ShenandoahSATBBarrier); SHENANDOAH_ERGO_DISABLE_FLAG(ShenandoahCASBarrier); SHENANDOAH_ERGO_DISABLE_FLAG(ShenandoahCloneBarrier); - SHENANDOAH_ERGO_DISABLE_FLAG(ShenandoahStackWatermarkBarrier); SHENANDOAH_ERGO_DISABLE_FLAG(ShenandoahCardBarrier); } diff --git a/src/hotspot/share/gc/shenandoah/mode/shenandoahSATBMode.cpp b/src/hotspot/share/gc/shenandoah/mode/shenandoahSATBMode.cpp index 7ac2d7b818f..e27aa90542d 100644 --- a/src/hotspot/share/gc/shenandoah/mode/shenandoahSATBMode.cpp +++ b/src/hotspot/share/gc/shenandoah/mode/shenandoahSATBMode.cpp @@ -42,6 +42,5 @@ void ShenandoahSATBMode::initialize_flags() const { SHENANDOAH_CHECK_FLAG_SET(ShenandoahSATBBarrier); SHENANDOAH_CHECK_FLAG_SET(ShenandoahCASBarrier); SHENANDOAH_CHECK_FLAG_SET(ShenandoahCloneBarrier); - SHENANDOAH_CHECK_FLAG_SET(ShenandoahStackWatermarkBarrier); SHENANDOAH_CHECK_FLAG_UNSET(ShenandoahCardBarrier); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.cpp b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.cpp index cb6ff795c07..0949959b042 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.cpp @@ -149,11 +149,9 @@ void ShenandoahBarrierSet::on_thread_attach(Thread *thread) { BarrierSetNMethod* bs_nm = barrier_set_nmethod(); thread->set_nmethod_disarmed_guard_value(bs_nm->disarmed_guard_value()); - if (ShenandoahStackWatermarkBarrier) { - JavaThread* const jt = JavaThread::cast(thread); - StackWatermark* const watermark = new ShenandoahStackWatermark(jt); - StackWatermarkSet::add_watermark(jt, watermark); - } + JavaThread* const jt = JavaThread::cast(thread); + StackWatermark* const watermark = new ShenandoahStackWatermark(jt); + StackWatermarkSet::add_watermark(jt, watermark); } } @@ -172,14 +170,12 @@ void ShenandoahBarrierSet::on_thread_detach(Thread *thread) { } // SATB protocol requires to keep alive reachable oops from roots at the beginning of GC - if (ShenandoahStackWatermarkBarrier) { - if (_heap->is_concurrent_mark_in_progress()) { - ShenandoahKeepAliveClosure oops; - StackWatermarkSet::finish_processing(JavaThread::cast(thread), &oops, StackWatermarkKind::gc); - } else if (_heap->is_concurrent_weak_root_in_progress() && _heap->is_evacuation_in_progress()) { - ShenandoahContextEvacuateUpdateRootsClosure oops; - StackWatermarkSet::finish_processing(JavaThread::cast(thread), &oops, StackWatermarkKind::gc); - } + if (_heap->is_concurrent_mark_in_progress()) { + ShenandoahKeepAliveClosure oops; + StackWatermarkSet::finish_processing(JavaThread::cast(thread), &oops, StackWatermarkKind::gc); + } else if (_heap->is_concurrent_weak_root_in_progress() && _heap->is_evacuation_in_progress()) { + ShenandoahContextEvacuateUpdateRootsClosure oops; + StackWatermarkSet::finish_processing(JavaThread::cast(thread), &oops, StackWatermarkKind::gc); } } } diff --git a/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp b/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp index bbfa19934d9..2c5ba726ef2 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp @@ -560,9 +560,6 @@ product(bool, ShenandoahLoadRefBarrier, true, DIAGNOSTIC, \ "Turn on/off load-reference barriers in Shenandoah") \ \ - product(bool, ShenandoahStackWatermarkBarrier, true, DIAGNOSTIC, \ - "Turn on/off stack watermark barriers in Shenandoah") \ - \ develop(bool, ShenandoahVerifyOptoBarriers, trueInDebug, \ "Verify no missing barriers in C2.") \ \ diff --git a/test/hotspot/jtreg/gc/shenandoah/options/TestSelectiveBarrierFlags.java b/test/hotspot/jtreg/gc/shenandoah/options/TestSelectiveBarrierFlags.java index fe29a38c422..da66bb8bbe0 100644 --- a/test/hotspot/jtreg/gc/shenandoah/options/TestSelectiveBarrierFlags.java +++ b/test/hotspot/jtreg/gc/shenandoah/options/TestSelectiveBarrierFlags.java @@ -52,8 +52,7 @@ public class TestSelectiveBarrierFlags { new String[] { "ShenandoahLoadRefBarrier" }, new String[] { "ShenandoahSATBBarrier" }, new String[] { "ShenandoahCASBarrier" }, - new String[] { "ShenandoahCloneBarrier" }, - new String[] { "ShenandoahStackWatermarkBarrier" } + new String[] { "ShenandoahCloneBarrier" } }; int size = 1; diff --git a/test/hotspot/jtreg/gc/shenandoah/options/TestWrongBarrierDisable.java b/test/hotspot/jtreg/gc/shenandoah/options/TestWrongBarrierDisable.java index f461bb4ae5c..b5c30f37202 100644 --- a/test/hotspot/jtreg/gc/shenandoah/options/TestWrongBarrierDisable.java +++ b/test/hotspot/jtreg/gc/shenandoah/options/TestWrongBarrierDisable.java @@ -41,8 +41,7 @@ public class TestWrongBarrierDisable { "ShenandoahLoadRefBarrier", "ShenandoahSATBBarrier", "ShenandoahCASBarrier", - "ShenandoahCloneBarrier", - "ShenandoahStackWatermarkBarrier", + "ShenandoahCloneBarrier" }; String[] generational = { diff --git a/test/hotspot/jtreg/gc/shenandoah/options/TestWrongBarrierEnable.java b/test/hotspot/jtreg/gc/shenandoah/options/TestWrongBarrierEnable.java index 348aa5367e9..1bc382dfbb0 100644 --- a/test/hotspot/jtreg/gc/shenandoah/options/TestWrongBarrierEnable.java +++ b/test/hotspot/jtreg/gc/shenandoah/options/TestWrongBarrierEnable.java @@ -41,8 +41,7 @@ public class TestWrongBarrierEnable { "ShenandoahLoadRefBarrier", "ShenandoahSATBBarrier", "ShenandoahCASBarrier", - "ShenandoahCloneBarrier", - "ShenandoahStackWatermarkBarrier", + "ShenandoahCloneBarrier" }; String[] generational = { "ShenandoahCardBarrier" }; String[] all = { @@ -50,7 +49,6 @@ public class TestWrongBarrierEnable { "ShenandoahSATBBarrier", "ShenandoahCASBarrier", "ShenandoahCloneBarrier", - "ShenandoahStackWatermarkBarrier", "ShenandoahCardBarrier" }; From 115075014272d12333d0955b42b11fee6727d514 Mon Sep 17 00:00:00 2001 From: Fei Yang Date: Fri, 17 Apr 2026 00:34:54 +0000 Subject: [PATCH 321/359] 8382199: Remove unused parameter "dst" from CardTableBarrierSetAssembler::store_check() Reviewed-by: chagedorn, jsikstro --- .../gc/shared/cardTableBarrierSetAssembler_aarch64.cpp | 8 ++++---- .../gc/shared/cardTableBarrierSetAssembler_aarch64.hpp | 4 ++-- .../x86/gc/shared/cardTableBarrierSetAssembler_x86.cpp | 8 ++++---- .../x86/gc/shared/cardTableBarrierSetAssembler_x86.hpp | 4 ++-- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/hotspot/cpu/aarch64/gc/shared/cardTableBarrierSetAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/shared/cardTableBarrierSetAssembler_aarch64.cpp index a9c320912cb..7ce4e0f8aed 100644 --- a/src/hotspot/cpu/aarch64/gc/shared/cardTableBarrierSetAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/gc/shared/cardTableBarrierSetAssembler_aarch64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ void CardTableBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet d } } -void CardTableBarrierSetAssembler::store_check(MacroAssembler* masm, Register obj, Address dst, Register tmp1, Register tmp2) { +void CardTableBarrierSetAssembler::store_check(MacroAssembler* masm, Register obj, Register tmp1, Register tmp2) { precond(tmp1 != noreg); precond(tmp2 != noreg); assert_different_registers(obj, tmp1, tmp2); @@ -114,10 +114,10 @@ void CardTableBarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorS if (needs_post_barrier) { // flatten object address if needed if (!precise || (dst.index() == noreg && dst.offset() == 0)) { - store_check(masm, dst.base(), dst, tmp1, tmp2); + store_check(masm, dst.base(), tmp1, tmp2); } else { __ lea(tmp3, dst); - store_check(masm, tmp3, dst, tmp1, tmp2); + store_check(masm, tmp3, tmp1, tmp2); } } } diff --git a/src/hotspot/cpu/aarch64/gc/shared/cardTableBarrierSetAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/gc/shared/cardTableBarrierSetAssembler_aarch64.hpp index e05e9e90e5d..07016381f78 100644 --- a/src/hotspot/cpu/aarch64/gc/shared/cardTableBarrierSetAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/gc/shared/cardTableBarrierSetAssembler_aarch64.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ protected: virtual void store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, Address dst, Register val, Register tmp1, Register tmp2, Register tmp3); - void store_check(MacroAssembler* masm, Register obj, Address dst, Register tmp1, Register tmp2); + void store_check(MacroAssembler* masm, Register obj, Register tmp1, Register tmp2); }; #endif // CPU_AARCH64_GC_SHARED_CARDTABLEBARRIERSETASSEMBLER_AARCH64_HPP diff --git a/src/hotspot/cpu/x86/gc/shared/cardTableBarrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/shared/cardTableBarrierSetAssembler_x86.cpp index 1de147926bb..c05f37a3bea 100644 --- a/src/hotspot/cpu/x86/gc/shared/cardTableBarrierSetAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/gc/shared/cardTableBarrierSetAssembler_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -130,7 +130,7 @@ __ BIND(L_loop); __ BIND(L_done); } -void CardTableBarrierSetAssembler::store_check(MacroAssembler* masm, Register obj, Address dst, Register rscratch) { +void CardTableBarrierSetAssembler::store_check(MacroAssembler* masm, Register obj, Register rscratch) { // Does a store check for the oop in register obj. The content of // register obj is destroyed afterwards. CardTableBarrierSet* ctbs = CardTableBarrierSet::barrier_set(); @@ -192,10 +192,10 @@ void CardTableBarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorS if (needs_post_barrier) { // flatten object address if needed if (!precise || (dst.index() == noreg && dst.disp() == 0)) { - store_check(masm, dst.base(), dst, tmp2); + store_check(masm, dst.base(), tmp2); } else { __ lea(tmp1, dst); - store_check(masm, tmp1, dst, tmp2); + store_check(masm, tmp1, tmp2); } } } diff --git a/src/hotspot/cpu/x86/gc/shared/cardTableBarrierSetAssembler_x86.hpp b/src/hotspot/cpu/x86/gc/shared/cardTableBarrierSetAssembler_x86.hpp index 201c11062f2..c38e16d4d5f 100644 --- a/src/hotspot/cpu/x86/gc/shared/cardTableBarrierSetAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/gc/shared/cardTableBarrierSetAssembler_x86.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ protected: virtual void gen_write_ref_array_pre_barrier(MacroAssembler* masm, DecoratorSet decorators, Register addr, Register count) {} - void store_check(MacroAssembler* masm, Register obj, Address dst, Register rscratch); + void store_check(MacroAssembler* masm, Register obj, Register rscratch); virtual void gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators, Register addr, Register count, Register tmp); From 93aa6462f031f36a71a929175e97e5b745ef94aa Mon Sep 17 00:00:00 2001 From: Jatin Bhateja Date: Fri, 17 Apr 2026 04:34:44 +0000 Subject: [PATCH 322/359] 8367761: [VectorAPI] AssertionError with several vector API mathlib tests with MaxVectorSize=32 Reviewed-by: xgong, sviswanathan, vlivanov --- .../share/classes/jdk/incubator/vector/CPUFeatures.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/CPUFeatures.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/CPUFeatures.java index 0ad7ba1651d..05b5f6f69f4 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/CPUFeatures.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/CPUFeatures.java @@ -74,9 +74,6 @@ import static jdk.internal.vm.vector.Utils.debug; debug("AVX=%b; AVX2=%b; AVX512F=%b; AVX512DQ=%b", SUPPORTS_AVX, SUPPORTS_AVX2, SUPPORTS_AVX512F, SUPPORTS_AVX512DQ); - assert SUPPORTS_AVX512F == (VectorShape.getMaxVectorBitSize(int.class) == 512); - assert SUPPORTS_AVX2 == (VectorShape.getMaxVectorBitSize(byte.class) >= 256); - assert SUPPORTS_AVX == (VectorShape.getMaxVectorBitSize(float.class) >= 256); } } From cbb85a5237a6fbc6ffe6f9e28d27b5df4a35060e Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Fri, 17 Apr 2026 05:47:55 +0000 Subject: [PATCH 323/359] 8382211: Shenandoah: Clean up and wire up final verification Reviewed-by: kdnilsen, wkemper --- .../gc/shenandoah/shenandoahConcurrentGC.cpp | 34 ++++++++++--------- .../gc/shenandoah/shenandoahConcurrentGC.hpp | 10 +++--- .../gc/shenandoah/shenandoahPhaseTimings.hpp | 4 +-- .../share/gc/shenandoah/shenandoahUtils.hpp | 2 +- .../gc/shenandoah/shenandoahVMOperations.cpp | 8 ++--- .../gc/shenandoah/shenandoahVMOperations.hpp | 10 +++--- .../gc/shenandoah/shenandoahVerifier.cpp | 19 ++++++++++- .../gc/shenandoah/shenandoahVerifier.hpp | 1 + src/hotspot/share/runtime/vmOperation.hpp | 2 +- 9 files changed, 55 insertions(+), 35 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp index af4cec03221..6723bb89021 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp @@ -255,8 +255,10 @@ bool ShenandoahConcurrentGC::collect(GCCause::Cause cause) { return false; } - if (VerifyAfterGC) { - vmop_entry_verify_final_roots(); + // In normal cycle, final-update-refs would verify at the end of the cycle. + // In abbreviated cycle, we need to verify separately. + if (ShenandoahVerify) { + vmop_entry_final_verify(); } } @@ -344,14 +346,14 @@ void ShenandoahConcurrentGC::vmop_entry_final_update_refs() { VMThread::execute(&op); } -void ShenandoahConcurrentGC::vmop_entry_verify_final_roots() { +void ShenandoahConcurrentGC::vmop_entry_final_verify() { ShenandoahHeap* const heap = ShenandoahHeap::heap(); TraceCollectorStats tcs(heap->monitoring_support()->stw_collection_counters()); - ShenandoahTimingsTracker timing(ShenandoahPhaseTimings::final_roots_gross); + ShenandoahTimingsTracker timing(ShenandoahPhaseTimings::final_verify_gross); // This phase does not use workers, no need for setup heap->try_inject_alloc_failure(); - VM_ShenandoahFinalRoots op(this); + VM_ShenandoahFinalVerify op(this); VMThread::execute(&op); } @@ -400,12 +402,12 @@ void ShenandoahConcurrentGC::entry_final_update_refs() { op_final_update_refs(); } -void ShenandoahConcurrentGC::entry_verify_final_roots() { - const char* msg = verify_final_roots_event_message(); - ShenandoahPausePhase gc_phase(msg, ShenandoahPhaseTimings::final_roots); +void ShenandoahConcurrentGC::entry_final_verify() { + const char* msg = verify_final_event_message(); + ShenandoahPausePhase gc_phase(msg, ShenandoahPhaseTimings::final_verify); EventMark em("%s", msg); - op_verify_final_roots(); + op_verify_final(); } void ShenandoahConcurrentGC::entry_reset() { @@ -1263,10 +1265,10 @@ bool ShenandoahConcurrentGC::entry_final_roots() { return true; } -void ShenandoahConcurrentGC::op_verify_final_roots() { - if (VerifyAfterGC) { - Universe::verify(); - } +void ShenandoahConcurrentGC::op_verify_final() { + assert(ShenandoahVerify, "Should have been checked before"); + ShenandoahHeap* const heap = ShenandoahHeap::heap(); + heap->verifier()->verify_after_gc(_generation); } void ShenandoahConcurrentGC::op_cleanup_complete() { @@ -1351,11 +1353,11 @@ const char* ShenandoahConcurrentGC::conc_reset_after_collect_event_message() con } } -const char* ShenandoahConcurrentGC::verify_final_roots_event_message() const { +const char* ShenandoahConcurrentGC::verify_final_event_message() const { if (ShenandoahHeap::heap()->unload_classes()) { - SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Pause Verify Final Roots", " (unload classes)"); + SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Pause Verify Final", " (unload classes)"); } else { - SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Pause Verify Final Roots", ""); + SHENANDOAH_RETURN_EVENT_MESSAGE(_generation->type(), "Pause Verify Final", ""); } } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.hpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.hpp index ba228901d72..fde585b4aa9 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.hpp @@ -43,7 +43,7 @@ class ShenandoahConcurrentGC : public ShenandoahGC { friend class VM_ShenandoahFinalMarkStartEvac; friend class VM_ShenandoahInitUpdateRefs; friend class VM_ShenandoahFinalUpdateRefs; - friend class VM_ShenandoahFinalRoots; + friend class VM_ShenandoahFinalVerify; protected: ShenandoahConcurrentMark _mark; @@ -69,7 +69,7 @@ protected: void vmop_entry_final_mark(); void vmop_entry_init_update_refs(); void vmop_entry_final_update_refs(); - void vmop_entry_verify_final_roots(); + void vmop_entry_final_verify(); // Entry methods to normally STW GC operations. These set up logging, monitoring // and workers for next VM operation @@ -77,7 +77,7 @@ protected: void entry_final_mark(); void entry_init_update_refs(); void entry_final_update_refs(); - void entry_verify_final_roots(); + void entry_final_verify(); // Entry methods to normally concurrent GC operations. These set up logging, monitoring // for concurrent operation. @@ -122,7 +122,7 @@ protected: void op_update_thread_roots(); void op_final_update_refs(); - void op_verify_final_roots(); + void op_verify_final(); void op_cleanup_complete(); void op_reset_after_collect(); @@ -143,7 +143,7 @@ private: // passing around the logging/tracing systems const char* init_mark_event_message() const; const char* final_mark_event_message() const; - const char* verify_final_roots_event_message() const; + const char* verify_final_event_message() const; const char* conc_final_roots_event_message() const; const char* conc_mark_event_message() const; const char* conc_reset_event_message() const; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.hpp b/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.hpp index a454de68f00..6a316e2265a 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.hpp @@ -112,8 +112,8 @@ class outputStream; f(conc_update_card_table, "Concurrent Update Cards") \ f(conc_final_roots, "Concurrent Final Roots") \ f(promote_in_place, " Promote Regions") \ - f(final_roots_gross, "Pause Verify Final Roots (G)") \ - f(final_roots, "Pause Verify Final Roots (N)") \ + f(final_verify_gross, "Pause Final Verify (G)") \ + f(final_verify, "Pause Final Verify (N)") \ \ f(init_update_refs_gross, "Pause Init Update Refs (G)") \ f(init_update_refs, "Pause Init Update Refs (N)") \ diff --git a/src/hotspot/share/gc/shenandoah/shenandoahUtils.hpp b/src/hotspot/share/gc/shenandoah/shenandoahUtils.hpp index 6ef4cd7c702..0169941c3d9 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahUtils.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahUtils.hpp @@ -187,7 +187,7 @@ public: type == VM_Operation::VMOp_ShenandoahFinalMarkStartEvac || type == VM_Operation::VMOp_ShenandoahInitUpdateRefs || type == VM_Operation::VMOp_ShenandoahFinalUpdateRefs || - type == VM_Operation::VMOp_ShenandoahFinalRoots || + type == VM_Operation::VMOp_ShenandoahFinalVerify || type == VM_Operation::VMOp_ShenandoahFullGC || type == VM_Operation::VMOp_ShenandoahDegeneratedGC; } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahVMOperations.cpp b/src/hotspot/share/gc/shenandoah/shenandoahVMOperations.cpp index 6b45842f781..97dd7e5cda1 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahVMOperations.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahVMOperations.cpp @@ -135,12 +135,12 @@ void VM_ShenandoahFinalUpdateRefs::doit() { _gc->entry_final_update_refs(); } -VM_ShenandoahFinalRoots::VM_ShenandoahFinalRoots(ShenandoahConcurrentGC* gc) +VM_ShenandoahFinalVerify::VM_ShenandoahFinalVerify(ShenandoahConcurrentGC* gc) : VM_ShenandoahOperation(gc->generation()), _gc(gc) { } -void VM_ShenandoahFinalRoots::doit() { - ShenandoahGCPauseMark mark(_gc_id, "Final Roots", SvcGCMarker::CONCURRENT); +void VM_ShenandoahFinalVerify::doit() { + ShenandoahGCPauseMark mark(_gc_id, "Final Verify", SvcGCMarker::CONCURRENT); set_active_generation(); - _gc->entry_verify_final_roots(); + _gc->entry_final_verify(); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahVMOperations.hpp b/src/hotspot/share/gc/shenandoah/shenandoahVMOperations.hpp index d565a3df22c..f8b99c71b14 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahVMOperations.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahVMOperations.hpp @@ -38,7 +38,7 @@ class ShenandoahFullGC; // - VM_ShenandoahFinalMarkStartEvac: finish up concurrent marking, and start evacuation // - VM_ShenandoahInitUpdateRefs: initiate update references // - VM_ShenandoahFinalUpdateRefs: finish up update references -// - VM_ShenandoahFinalRoots: finish up roots on a non-evacuating cycle +// - VM_ShenandoahFinalVerify: final verification at the end of the cycle // - VM_ShenandoahReferenceOperation: // - VM_ShenandoahFullGC: do full GC // - VM_ShenandoahDegeneratedGC: do STW degenerated GC @@ -127,12 +127,12 @@ public: void doit() override; }; -class VM_ShenandoahFinalRoots: public VM_ShenandoahOperation { +class VM_ShenandoahFinalVerify: public VM_ShenandoahOperation { ShenandoahConcurrentGC* const _gc; public: - explicit VM_ShenandoahFinalRoots(ShenandoahConcurrentGC* gc); - VM_Operation::VMOp_Type type() const override { return VMOp_ShenandoahFinalRoots; } - const char* name() const override { return "Shenandoah Final Roots"; } + explicit VM_ShenandoahFinalVerify(ShenandoahConcurrentGC* gc); + VM_Operation::VMOp_Type type() const override { return VMOp_ShenandoahFinalVerify; } + const char* name() const override { return "Shenandoah Final Verify"; } void doit() override; }; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp index afef11640c9..8299cbe62c6 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp @@ -1180,7 +1180,7 @@ void ShenandoahVerifier::verify_before_update_refs(ShenandoahGeneration* generat ); } -// We have not yet cleanup (reclaimed) the collection set +// We have not yet cleaned up (reclaimed) the collection set void ShenandoahVerifier::verify_after_update_refs(ShenandoahGeneration* generation) { verify_at_safepoint( generation, @@ -1197,6 +1197,23 @@ void ShenandoahVerifier::verify_after_update_refs(ShenandoahGeneration* generati ); } +// We have not yet cleaned up (reclaimed) the collection set +void ShenandoahVerifier::verify_after_gc(ShenandoahGeneration* generation) { + verify_at_safepoint( + generation, + "After GC", + _verify_remembered_disable, // do not verify remembered set + _verify_forwarded_none, // no forwarded references + _verify_marked_complete, // bitmaps might be stale, but alloc-after-mark should be well + _verify_cset_none, // no cset references, all updated + _verify_liveness_disable, // no reliable liveness data anymore + _verify_regions_nocset, // no cset regions, trash regions have appeared + // expect generation and heap sizes to match exactly, including trash + _verify_size_exact_including_trash, + _verify_gcstate_stable // GC state was turned off + ); +} + void ShenandoahVerifier::verify_after_degenerated(ShenandoahGeneration* generation) { verify_at_safepoint( generation, diff --git a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.hpp b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.hpp index 7e683cf7af8..0479d5f67ce 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.hpp @@ -220,6 +220,7 @@ public: void verify_before_evacuation(ShenandoahGeneration* generation); void verify_before_update_refs(ShenandoahGeneration* generation); void verify_after_update_refs(ShenandoahGeneration* generation); + void verify_after_gc(ShenandoahGeneration* generation); void verify_before_fullgc(ShenandoahGeneration* generation); void verify_after_fullgc(ShenandoahGeneration* generation); void verify_after_degenerated(ShenandoahGeneration* generation); diff --git a/src/hotspot/share/runtime/vmOperation.hpp b/src/hotspot/share/runtime/vmOperation.hpp index 5140d0401fb..6078600c16e 100644 --- a/src/hotspot/share/runtime/vmOperation.hpp +++ b/src/hotspot/share/runtime/vmOperation.hpp @@ -90,7 +90,7 @@ template(ShenandoahFinalMarkStartEvac) \ template(ShenandoahInitUpdateRefs) \ template(ShenandoahFinalUpdateRefs) \ - template(ShenandoahFinalRoots) \ + template(ShenandoahFinalVerify) \ template(ShenandoahDegeneratedGC) \ template(Exit) \ template(LinuxDllLoad) \ From 299973160d55f1318dd6c673267b4dcdefb64ac9 Mon Sep 17 00:00:00 2001 From: Rui Li Date: Fri, 17 Apr 2026 05:51:52 +0000 Subject: [PATCH 324/359] 8382295: Shenandoah: wrong denominator in full gc summary Reviewed-by: shade, kdnilsen --- src/hotspot/share/gc/shenandoah/shenandoahCollectorPolicy.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahCollectorPolicy.cpp b/src/hotspot/share/gc/shenandoah/shenandoahCollectorPolicy.cpp index bbd9dca1513..cfa79fc055e 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahCollectorPolicy.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahCollectorPolicy.cpp @@ -257,10 +257,10 @@ void ShenandoahCollectorPolicy::print_gc_stats(outputStream* out) const { out->print_cr("%5zu Full GCs (%.2f%%)", _success_full_gcs, percent_of(_success_full_gcs, completed_gcs)); if (!ExplicitGCInvokesConcurrent) { - out->print_cr(" %5zu invoked explicitly (%.2f%%)", explicit_requests, percent_of(explicit_requests, _success_concurrent_gcs)); + out->print_cr(" %5zu invoked explicitly (%.2f%%)", explicit_requests, percent_of(explicit_requests, _success_full_gcs)); } if (!ShenandoahImplicitGCInvokesConcurrent) { - out->print_cr(" %5zu invoked implicitly (%.2f%%)", implicit_requests, percent_of(implicit_requests, _success_concurrent_gcs)); + out->print_cr(" %5zu invoked implicitly (%.2f%%)", implicit_requests, percent_of(implicit_requests, _success_full_gcs)); } out->print_cr(" %5zu caused by allocation failure (%.2f%%)", _alloc_failure_full, percent_of(_alloc_failure_full, _success_full_gcs)); out->print_cr(" %5zu upgraded from Degenerated GC (%.2f%%)", _alloc_failure_degenerated_upgrade_to_full, percent_of(_alloc_failure_degenerated_upgrade_to_full, _success_full_gcs)); From 5c403a8029fd8d8c0f817b76b7f3abcfbb4bcabf Mon Sep 17 00:00:00 2001 From: Dusan Balek Date: Fri, 17 Apr 2026 06:10:25 +0000 Subject: [PATCH 325/359] 8380912: "Trailing white space will be removed" incorrectly triggered with \u2028 Reviewed-by: jlahoda --- .../tools/javac/parser/TextBlockSupport.java | 6 +- .../langtools/tools/javac/TextBlockU2028.java | 76 +++++++++++++++++++ 2 files changed, 79 insertions(+), 3 deletions(-) create mode 100644 test/langtools/tools/javac/TextBlockU2028.java diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/TextBlockSupport.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/TextBlockSupport.java index d099ceadba0..5112849d45f 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/TextBlockSupport.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/TextBlockSupport.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * 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,8 +56,8 @@ class TextBlockSupport { // No need to check indentation if opting out (last line is empty.) char lastChar = string.charAt(string.length() - 1); boolean optOut = lastChar == '\n' || lastChar == '\r'; - // Split string based at line terminators. - String[] lines = string.split("\\R"); + // Split string using JLS text block line terminators: CRLF, CR, or LF. + String[] lines = string.split("\\r\\n|\\r|\\n"); int length = lines.length; // Extract last line. String lastLine = length == 0 ? "" : lines[length - 1]; diff --git a/test/langtools/tools/javac/TextBlockU2028.java b/test/langtools/tools/javac/TextBlockU2028.java new file mode 100644 index 00000000000..a7abfe43263 --- /dev/null +++ b/test/langtools/tools/javac/TextBlockU2028.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8380912 + * @summary Verify that trailing whitespace warning is not reported for \u2028 + * inside text block content + * @library /tools/lib + * @modules + * jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * @build toolbox.ToolBox toolbox.JavacTask + * @run junit TextBlockU2028 + */ + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import toolbox.JavacTask; +import toolbox.ToolBox; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInfo; + +public class TextBlockU2028 { + Path base; + ToolBox tb = new ToolBox(); + + @Test + void testNoFalseTrailingWhitespaceWarning() throws Exception { + Path classes = base.resolve("classes"); + Files.createDirectories(classes); + new JavacTask(tb) + .options("-d", classes.toString(), "-Xlint:text-blocks", "-XDrawDiagnostics", "-Werror") + .sources(""" + public class Test { + String s = \"\"\" + foo \\u2028 bar + \"\"\"; + } + """) + .run() + .writeAll(); + } + + @BeforeEach + public void setUp(TestInfo info) { + base = Paths.get(".") + .resolve(info.getTestMethod() + .orElseThrow() + .getName()); + } +} From 15a7eabd4af7e2ec60d3cc0511c28d4fb740595d Mon Sep 17 00:00:00 2001 From: jonghoonpark Date: Fri, 17 Apr 2026 06:37:15 +0000 Subject: [PATCH 326/359] 8381924: Fix include guard in lambdaProxyClassDictionary.hpp Reviewed-by: jwaters, stefank --- src/hotspot/share/cds/lambdaProxyClassDictionary.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/cds/lambdaProxyClassDictionary.hpp b/src/hotspot/share/cds/lambdaProxyClassDictionary.hpp index dfb75532917..b20e998bba6 100644 --- a/src/hotspot/share/cds/lambdaProxyClassDictionary.hpp +++ b/src/hotspot/share/cds/lambdaProxyClassDictionary.hpp @@ -22,8 +22,8 @@ * */ -#ifndef SHARE_CDS_LAMBDAPROXYCLASSINFO_HPP -#define SHARE_CDS_LAMBDAPROXYCLASSINFO_HPP +#ifndef SHARE_CDS_LAMBDAPROXYCLASSDICTIONARY_HPP +#define SHARE_CDS_LAMBDAPROXYCLASSDICTIONARY_HPP #include "cds/aotCompressedPointers.hpp" #include "cds/aotMetaspace.hpp" @@ -331,4 +331,4 @@ public: static void print_statistics(outputStream* st, bool is_static_archive); }; -#endif // SHARE_CDS_LAMBDAPROXYCLASSINFO_HPP +#endif // SHARE_CDS_LAMBDAPROXYCLASSDICTIONARY_HPP From ca643010a27292b99c6f2182764bc7cd4ac93b02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Gr=C3=B6nlund?= Date: Fri, 17 Apr 2026 07:51:44 +0000 Subject: [PATCH 327/359] 8382242: JFR: Metadata reconstruction invalidates ConstantMap for java.lang.String Reviewed-by: egahlin --- .../jfr/internal/consumer/ParserFactory.java | 9 +- ...aReconstructionWithRetainedStringPool.java | 106 ++++++++++++++++++ 2 files changed, 112 insertions(+), 3 deletions(-) create mode 100644 test/jdk/jdk/jfr/api/consumer/streaming/TestMetadataReconstructionWithRetainedStringPool.java diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ParserFactory.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ParserFactory.java index e7dd234ca8d..c973dadb3b7 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ParserFactory.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ParserFactory.java @@ -132,9 +132,12 @@ final class ParserFactory { case "short" -> new ShortParser(); case "byte" -> new ByteParser(); case "java.lang.String" -> { - ConstantMap pool = new ConstantMap(ObjectFactory.create(type, timeConverter), type); - ConstantLookup lookup = new ConstantLookup(pool, type); - constantLookups.put(type.getId(), lookup); + ConstantLookup lookup = constantLookups.get(type.getId()); + if (lookup == null) { + ConstantMap pool = new ConstantMap(ObjectFactory.create(type, timeConverter), type); + lookup = new ConstantLookup(pool, type); + constantLookups.put(type.getId(), lookup); + } yield new StringParser(lookup, event); } default -> throw new IOException("Unknown primitive type " + type.getName()); diff --git a/test/jdk/jdk/jfr/api/consumer/streaming/TestMetadataReconstructionWithRetainedStringPool.java b/test/jdk/jdk/jfr/api/consumer/streaming/TestMetadataReconstructionWithRetainedStringPool.java new file mode 100644 index 00000000000..8bbadc6db29 --- /dev/null +++ b/test/jdk/jdk/jfr/api/consumer/streaming/TestMetadataReconstructionWithRetainedStringPool.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jfr.api.consumer.streaming; + +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.CountDownLatch; + +import jdk.jfr.Event; +import jdk.jfr.consumer.RecordingStream; + +/** + * @test + * @summary Test that it is possible to register new metadata in a new segment while retaining the string pool. + * @requires vm.flagless + * @requires vm.hasJFR + * @library /test/lib + * @run main/othervm jdk.jfr.api.consumer.streaming.TestMetadataReconstructionWithRetainedStringPool + */ +public class TestMetadataReconstructionWithRetainedStringPool { + /// Minimum string length required to trigger StringPool usage. + /// Mirrors `jdk.jfr.internal.StringPool.MIN_LIMIT`. + private static final int STRING_POOL_MIN_LIMIT = 16; + private static final int EXPECTED_EVENTS = 3; + + // Condition 1: String length > STRING_POOL_MIN_LIMIT triggers CONSTANT_POOL encoding. + private static final String TEXT = "a".repeat(STRING_POOL_MIN_LIMIT + 1);; + + static final class EventA extends Event { + String text = TEXT; + } + + static final class EventB extends Event { + String text = TEXT; + } + + public static void main(String... args) throws InterruptedException { + var aEventsPosted = new CountDownLatch(1); + var readyToPostEventB = new CountDownLatch(1); + var remaining = new CountDownLatch(EXPECTED_EVENTS); + + try (var rs = new RecordingStream()) { + rs.onEvent(e -> { + String textValue = e.getValue("text"); + if (textValue == null) { + throw new RuntimeException("e.getValue(\"text\") returned null"); + } + remaining.countDown(); + System.out.printf("Event #%d [%s]: text=%s%n", + EXPECTED_EVENTS - remaining.getCount(), + e.getEventType().getName(), + textValue); + }); + + rs.onFlush(() -> { + if (aEventsPosted.getCount() == 0) { + readyToPostEventB.countDown(); + } + }); + + rs.startAsync(); + + // Condition 2: Two distinct event types are required. + // First, load EventA as the initial event type and emit its first event. + // This first event looks into the StringPool pre-cache. Although the + // string length qualifies for pooling, because it isn't pre-cached, + // the first event encodes the string inline. + // The second event finds the string in the pre-cache and adds it to the + // pool. A constant pool ID to the pooled string is encoded in the event. + // + new EventA().commit(); + new EventA().commit(); + aEventsPosted.countDown(); + + // Condition 3: Wait for JFR flush. + // The default flush period is ~1 second. + readyToPostEventB.await(); + + // Load the second event type, EventB, AFTER the flush segment containing the two events of type EventA. + // A new metadata description will be constructed, and we verify that the StringPool added in the previous + // segment is still available for the EventB string pool reference to be resolved correctly. + new EventB().commit(); + remaining.await(); + } + } +} From 787ff6787e9e87ed2de4058e1d3a0e06b2126fd5 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Fri, 17 Apr 2026 07:56:31 +0000 Subject: [PATCH 328/359] 8379620: G1: Typing error in jvmFlagConstraintsG1.cpp Reviewed-by: iwalulya --- src/hotspot/share/gc/g1/jvmFlagConstraintsG1.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/gc/g1/jvmFlagConstraintsG1.cpp b/src/hotspot/share/gc/g1/jvmFlagConstraintsG1.cpp index b56e82fac3c..df6adeb8041 100644 --- a/src/hotspot/share/gc/g1/jvmFlagConstraintsG1.cpp +++ b/src/hotspot/share/gc/g1/jvmFlagConstraintsG1.cpp @@ -70,7 +70,7 @@ JVMFlag::Error G1RemSetHowlMaxNumBucketsConstraintFunc(uint value, bool verbose) } if (!is_power_of_2(G1RemSetHowlMaxNumBuckets)) { JVMFlag::printError(verbose, - "G1RemSetMaxHowlNumBuckets (%u) must be a power of two.\n", + "G1RemSetHowlMaxNumBuckets (%u) must be a power of two.\n", value); return JVMFlag::VIOLATES_CONSTRAINT; } From 877425a15825ae4e1eafa4c90807e05679e48474 Mon Sep 17 00:00:00 2001 From: Volkan Yazici Date: Fri, 17 Apr 2026 08:18:40 +0000 Subject: [PATCH 329/359] 8380989: HttpRequest.Builder#headers() throws an exception if an empty array is passed Reviewed-by: dfuchs --- .../jdk/internal/net/http/HttpRequestBuilderImpl.java | 4 ++-- test/jdk/java/net/httpclient/HttpRequestBuilderTest.java | 6 +++--- test/jdk/java/net/httpclient/RequestBuilderTest.java | 3 +-- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/HttpRequestBuilderImpl.java b/src/java.net.http/share/classes/jdk/internal/net/http/HttpRequestBuilderImpl.java index ef0e2b152bb..c39edf878c9 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/HttpRequestBuilderImpl.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/HttpRequestBuilderImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -145,7 +145,7 @@ public class HttpRequestBuilderImpl implements HttpRequest.Builder { @Override public HttpRequestBuilderImpl headers(String... params) { requireNonNull(params); - if (params.length == 0 || params.length % 2 != 0) { + if (params.length % 2 != 0) { throw newIAE("wrong number, %d, of parameters", params.length); } for (int i = 0; i < params.length; i += 2) { diff --git a/test/jdk/java/net/httpclient/HttpRequestBuilderTest.java b/test/jdk/java/net/httpclient/HttpRequestBuilderTest.java index 4544c85c5e8..dd1e2495382 100644 --- a/test/jdk/java/net/httpclient/HttpRequestBuilderTest.java +++ b/test/jdk/java/net/httpclient/HttpRequestBuilderTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * 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,8 +112,8 @@ public class HttpRequestBuilderTest { builder = test1("headers", builder, builder::headers, (String[]) null, NullPointerException.class); - builder = test1("headers", builder, builder::headers, new String[0], - IllegalArgumentException.class); + builder = test1("headers", builder, builder::headers, new String[0] + /* no expected exceptions */); builder = test1("headers", builder, builder::headers, (String[]) new String[] {null, "bar"}, diff --git a/test/jdk/java/net/httpclient/RequestBuilderTest.java b/test/jdk/java/net/httpclient/RequestBuilderTest.java index 6ba00fcd10f..9285bb55bb8 100644 --- a/test/jdk/java/net/httpclient/RequestBuilderTest.java +++ b/test/jdk/java/net/httpclient/RequestBuilderTest.java @@ -202,11 +202,10 @@ public class RequestBuilderTest { public void testHeaders() { HttpRequest.Builder builder = newBuilder(uri); - String[] empty = new String[0]; - assertThrows(IAE, () -> builder.headers(empty).build()); assertThrows(IAE, () -> builder.headers("1").build()); assertThrows(IAE, () -> builder.headers("1", "2", "3").build()); assertThrows(IAE, () -> builder.headers("1", "2", "3", "4", "5").build()); + assertEquals(0, builder.headers(new String[0]).build().headers().map().size()); assertEquals(0, builder.build().headers().map().size()); List requests = List.of( From 8a710ae20178c39ecab1e3aaac72916534ad7811 Mon Sep 17 00:00:00 2001 From: Artur Barashev Date: Fri, 17 Apr 2026 13:27:25 +0000 Subject: [PATCH 330/359] 8372526: Add support for ZLIB TLS Certificate Compression Co-authored-by: Xue-Lei Andrew Fan Reviewed-by: jnimeh, xuelei --- .../share/classes/sun/security/ssl/Alert.java | 4 +- .../sun/security/ssl/CertificateMessage.java | 47 ++- .../sun/security/ssl/CertificateRequest.java | 7 +- .../security/ssl/CompressCertExtension.java | 306 ++++++++++++++++++ .../security/ssl/CompressedCertificate.java | 264 +++++++++++++++ .../security/ssl/CompressionAlgorithm.java | 182 +++++++++++ .../sun/security/ssl/HandshakeContext.java | 7 +- .../sun/security/ssl/QuicTLSEngineImpl.java | 1 + .../sun/security/ssl/SSLContextImpl.java | 10 + .../sun/security/ssl/SSLExtension.java | 23 +- .../sun/security/ssl/SSLHandshake.java | 19 +- .../classes/sun/security/ssl/ServerHello.java | 7 +- test/jdk/java/net/httpclient/HeadTest.java | 17 +- .../net/httpclient/LargeHandshakeTest.java | 35 +- .../BoundDecompressMemory.java | 86 +++++ .../ClientCertCompressionExt.java | 157 +++++++++ .../CompressedCertMsg.java | 151 +++++++++ .../CompressedCertMsgCache.java | 197 +++++++++++ .../jdk/test/lib/security/SecurityUtils.java | 39 ++- 19 files changed, 1518 insertions(+), 41 deletions(-) create mode 100644 src/java.base/share/classes/sun/security/ssl/CompressCertExtension.java create mode 100644 src/java.base/share/classes/sun/security/ssl/CompressedCertificate.java create mode 100644 src/java.base/share/classes/sun/security/ssl/CompressionAlgorithm.java create mode 100644 test/jdk/sun/security/ssl/CertificateCompression/BoundDecompressMemory.java create mode 100644 test/jdk/sun/security/ssl/CertificateCompression/ClientCertCompressionExt.java create mode 100644 test/jdk/sun/security/ssl/CertificateCompression/CompressedCertMsg.java create mode 100644 test/jdk/sun/security/ssl/CertificateCompression/CompressedCertMsgCache.java diff --git a/src/java.base/share/classes/sun/security/ssl/Alert.java b/src/java.base/share/classes/sun/security/ssl/Alert.java index fb06b02a5d4..e9588a09b3d 100644 --- a/src/java.base/share/classes/sun/security/ssl/Alert.java +++ b/src/java.base/share/classes/sun/security/ssl/Alert.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -281,6 +281,8 @@ public enum Alert { // consumer so the state machine doesn't expect it. tc.handshakeContext.handshakeConsumers.remove( SSLHandshake.CERTIFICATE.id); + tc.handshakeContext.handshakeConsumers.remove( + SSLHandshake.COMPRESSED_CERTIFICATE.id); tc.handshakeContext.handshakeConsumers.remove( SSLHandshake.CERTIFICATE_VERIFY.id); } diff --git a/src/java.base/share/classes/sun/security/ssl/CertificateMessage.java b/src/java.base/share/classes/sun/security/ssl/CertificateMessage.java index c6897d71aa6..af5007d7899 100644 --- a/src/java.base/share/classes/sun/security/ssl/CertificateMessage.java +++ b/src/java.base/share/classes/sun/security/ssl/CertificateMessage.java @@ -781,14 +781,6 @@ final class CertificateMessage { } } - T13CertificateMessage(HandshakeContext handshakeContext, - byte[] requestContext, List certificates) { - super(handshakeContext); - - this.requestContext = requestContext.clone(); - this.certEntries = certificates; - } - T13CertificateMessage(HandshakeContext handshakeContext, ByteBuffer m) throws IOException { super(handshakeContext); @@ -925,16 +917,26 @@ final class CertificateMessage { HandshakeMessage message) throws IOException { // The producing happens in handshake context only. HandshakeContext hc = (HandshakeContext)context; - if (hc.sslConfig.isClientMode) { - return onProduceCertificate( - (ClientHandshakeContext)context, message); - } else { - return onProduceCertificate( + T13CertificateMessage cm = hc.sslConfig.isClientMode ? + onProduceCertificate( + (ClientHandshakeContext)context, message) : + onProduceCertificate( (ServerHandshakeContext)context, message); + + // Output the handshake message. + if (hc.certDeflater == null) { + cm.write(hc.handshakeOutput); + hc.handshakeOutput.flush(); + } else { + // Replace with CompressedCertificate message + CompressedCertificate.handshakeProducer.produce(hc, cm); } + + // The handshake message has been delivered. + return null; } - private byte[] onProduceCertificate(ServerHandshakeContext shc, + private T13CertificateMessage onProduceCertificate(ServerHandshakeContext shc, HandshakeMessage message) throws IOException { ClientHelloMessage clientHello = (ClientHelloMessage)message; @@ -993,12 +995,7 @@ final class CertificateMessage { SSLLogger.fine("Produced server Certificate message", cm); } - // Output the handshake message. - cm.write(shc.handshakeOutput); - shc.handshakeOutput.flush(); - - // The handshake message has been delivered. - return null; + return cm; } private static SSLPossession choosePossession( @@ -1045,7 +1042,7 @@ final class CertificateMessage { return pos; } - private byte[] onProduceCertificate(ClientHandshakeContext chc, + private T13CertificateMessage onProduceCertificate(ClientHandshakeContext chc, HandshakeMessage message) throws IOException { ClientHelloMessage clientHello = (ClientHelloMessage)message; SSLPossession pos = choosePossession(chc, clientHello); @@ -1091,12 +1088,7 @@ final class CertificateMessage { SSLLogger.fine("Produced client Certificate message", cm); } - // Output the handshake message. - cm.write(chc.handshakeOutput); - chc.handshakeOutput.flush(); - - // The handshake message has been delivered. - return null; + return cm; } } @@ -1116,6 +1108,7 @@ final class CertificateMessage { HandshakeContext hc = (HandshakeContext)context; // clean up this consumer + hc.handshakeConsumers.remove(SSLHandshake.COMPRESSED_CERTIFICATE.id); hc.handshakeConsumers.remove(SSLHandshake.CERTIFICATE.id); // Ensure that the Certificate message has not been sent w/o diff --git a/src/java.base/share/classes/sun/security/ssl/CertificateRequest.java b/src/java.base/share/classes/sun/security/ssl/CertificateRequest.java index 039399560cd..2eceb4d9ebd 100644 --- a/src/java.base/share/classes/sun/security/ssl/CertificateRequest.java +++ b/src/java.base/share/classes/sun/security/ssl/CertificateRequest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -956,6 +956,11 @@ final class CertificateRequest { // update // shc.certRequestContext = crm.requestContext.clone(); + if (shc.certInflaters != null && !shc.certInflaters.isEmpty()) { + shc.handshakeConsumers.put( + SSLHandshake.COMPRESSED_CERTIFICATE.id, + SSLHandshake.COMPRESSED_CERTIFICATE); + } shc.handshakeConsumers.put(SSLHandshake.CERTIFICATE.id, SSLHandshake.CERTIFICATE); shc.handshakeConsumers.put(SSLHandshake.CERTIFICATE_VERIFY.id, diff --git a/src/java.base/share/classes/sun/security/ssl/CompressCertExtension.java b/src/java.base/share/classes/sun/security/ssl/CompressCertExtension.java new file mode 100644 index 00000000000..eff97857ef0 --- /dev/null +++ b/src/java.base/share/classes/sun/security/ssl/CompressCertExtension.java @@ -0,0 +1,306 @@ +/* + * Copyright (C) 2022 THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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 sun.security.ssl; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.text.MessageFormat; +import java.util.Locale; +import java.util.Map; +import java.util.function.Function; +import javax.net.ssl.SSLProtocolException; +import sun.security.ssl.SSLExtension.ExtensionConsumer; +import sun.security.ssl.SSLExtension.SSLExtensionSpec; +import sun.security.ssl.SSLHandshake.HandshakeMessage; + +/** + * Pack of the "compress_certificate" extensions [RFC 5246]. + */ +final class CompressCertExtension { + + static final HandshakeProducer chNetworkProducer = + new CHCompressCertificateProducer(); + static final ExtensionConsumer chOnLoadConsumer = + new CHCompressCertificateConsumer(); + + static final HandshakeProducer crNetworkProducer = + new CRCompressCertificateProducer(); + static final ExtensionConsumer crOnLoadConsumer = + new CRCompressCertificateConsumer(); + + static final SSLStringizer ccStringizer = + new CompressCertificateStringizer(); + + /** + * The "signature_algorithms" extension. + */ + static final class CertCompressionSpec implements SSLExtensionSpec { + + private final int[] compressionAlgorithms; // non-null + + CertCompressionSpec( + Map> certInflaters) { + compressionAlgorithms = new int[certInflaters.size()]; + int i = 0; + for (Integer id : certInflaters.keySet()) { + compressionAlgorithms[i++] = id; + } + } + + CertCompressionSpec(HandshakeContext hc, + ByteBuffer buffer) throws IOException { + if (buffer.remaining() < 2) { // 2: the length of the list + throw hc.conContext.fatal(Alert.DECODE_ERROR, + new SSLProtocolException( + "Invalid compress_certificate: insufficient data")); + } + + byte[] algs = Record.getBytes8(buffer); + if (buffer.hasRemaining()) { + throw hc.conContext.fatal(Alert.DECODE_ERROR, + new SSLProtocolException( + "Invalid compress_certificate: unknown extra data")); + } + + if (algs.length == 0 || (algs.length & 0x01) != 0) { + throw hc.conContext.fatal(Alert.DECODE_ERROR, + new SSLProtocolException( + "Invalid compress_certificate: incomplete data")); + } + + int[] compressionAlgs = new int[algs.length / 2]; + for (int i = 0, j = 0; i < algs.length; ) { + byte hash = algs[i++]; + byte sign = algs[i++]; + compressionAlgs[j++] = ((hash & 0xFF) << 8) | (sign & 0xFF); + } + + this.compressionAlgorithms = compressionAlgs; + } + + @Override + public String toString() { + MessageFormat messageFormat = new MessageFormat( + "\"compression algorithms\": '['{0}']'", Locale.ENGLISH); + + if (compressionAlgorithms.length == 0) { + Object[] messageFields = { + "" + }; + return messageFormat.format(messageFields); + } else { + StringBuilder builder = new StringBuilder(512); + boolean isFirst = true; + for (int ca : compressionAlgorithms) { + if (isFirst) { + isFirst = false; + } else { + builder.append(", "); + } + + builder.append(CompressionAlgorithm.nameOf(ca)); + } + + Object[] messageFields = { + builder.toString() + }; + + return messageFormat.format(messageFields); + } + } + } + + private static final + class CompressCertificateStringizer implements SSLStringizer { + + @Override + public String toString(HandshakeContext hc, ByteBuffer buffer) { + try { + return (new CertCompressionSpec(hc, buffer)).toString(); + } catch (IOException ioe) { + // For debug logging only, so please swallow exceptions. + return ioe.getMessage(); + } + } + } + + /** + * Network data producer of a "compress_certificate" extension in + * the ClientHello handshake message. + */ + private static final + class CHCompressCertificateProducer implements HandshakeProducer { + + // Prevent instantiation of this class. + private CHCompressCertificateProducer() { + // blank + } + + @Override + public byte[] produce(ConnectionContext context, + HandshakeMessage message) throws IOException { + // The producing happens in client side only. + return produceCompCertExt(context, + SSLExtension.CH_COMPRESS_CERTIFICATE); + } + } + + /** + * Network data consumer of a "compress_certificate" extension in + * the ClientHello handshake message. + */ + private static final + class CHCompressCertificateConsumer implements ExtensionConsumer { + + // Prevent instantiation of this class. + private CHCompressCertificateConsumer() { + // blank + } + + @Override + public void consume(ConnectionContext context, + HandshakeMessage message, ByteBuffer buffer) + throws IOException { + // The consuming happens in server side only. + consumeCompCertExt(context, buffer, + SSLExtension.CH_COMPRESS_CERTIFICATE); + } + } + + /** + * Network data producer of a "compress_certificate" extension in + * the CertificateRequest handshake message. + */ + private static final + class CRCompressCertificateProducer implements HandshakeProducer { + + // Prevent instantiation of this class. + private CRCompressCertificateProducer() { + // blank + } + + @Override + public byte[] produce(ConnectionContext context, + HandshakeMessage message) throws IOException { + // The producing happens in server side only. + return produceCompCertExt(context, + SSLExtension.CR_COMPRESS_CERTIFICATE); + } + } + + /** + * Network data consumer of a "compress_certificate" extension in + * the CertificateRequest handshake message. + */ + private static final + class CRCompressCertificateConsumer implements ExtensionConsumer { + + // Prevent instantiation of this class. + private CRCompressCertificateConsumer() { + // blank + } + + @Override + public void consume(ConnectionContext context, + HandshakeMessage message, ByteBuffer buffer) + throws IOException { + // The consuming happens in client side only. + consumeCompCertExt(context, buffer, + SSLExtension.CR_COMPRESS_CERTIFICATE); + } + } + + private static byte[] produceCompCertExt( + ConnectionContext context, SSLExtension extension) + throws IOException { + + HandshakeContext hc = (HandshakeContext) context; + // Is it a supported and enabled extension? + if (!hc.sslConfig.isAvailable(extension)) { + if (SSLLogger.isOn() && SSLLogger.isOn(SSLLogger.Opt.HANDSHAKE)) { + SSLLogger.fine("Ignore unavailable " + + "compress_certificate extension"); + } + return null; + } + + // Produce the extension. + hc.certInflaters = CompressionAlgorithm.getInflaters(); + + if (hc.certInflaters.isEmpty()) { + if (SSLLogger.isOn() && SSLLogger.isOn(SSLLogger.Opt.HANDSHAKE)) { + SSLLogger.warning("Unable to produce the extension: " + + "no certificate compression inflaters defined"); + } + return null; + } + + int vectorLen = CompressionAlgorithm.sizeInRecord() * + hc.certInflaters.size(); + byte[] extData = new byte[vectorLen + 1]; + ByteBuffer m = ByteBuffer.wrap(extData); + Record.putInt8(m, vectorLen); + for (Integer algId : hc.certInflaters.keySet()) { + Record.putInt16(m, algId); + } + + // Update the context. + hc.handshakeExtensions.put( + extension, new CertCompressionSpec(hc.certInflaters)); + + return extData; + } + + private static void consumeCompCertExt(ConnectionContext context, + ByteBuffer buffer, SSLExtension extension) throws IOException { + + HandshakeContext hc = (HandshakeContext) context; + // Is it a supported and enabled extension? + if (!hc.sslConfig.isAvailable(extension)) { + if (SSLLogger.isOn() && SSLLogger.isOn(SSLLogger.Opt.HANDSHAKE)) { + SSLLogger.fine("Ignore unavailable " + + "compress_certificate extension"); + } + return; // ignore the extension + } + + // Parse the extension. + CertCompressionSpec spec = new CertCompressionSpec(hc, buffer); + + // Update the context. + hc.certDeflater = CompressionAlgorithm.selectDeflater( + spec.compressionAlgorithms); + + if (hc.certDeflater == null) { + if (SSLLogger.isOn() && SSLLogger.isOn(SSLLogger.Opt.HANDSHAKE)) { + SSLLogger.fine("Ignore, no supported " + + "certificate compression algorithms"); + } + } + // No impact on session resumption. + } +} diff --git a/src/java.base/share/classes/sun/security/ssl/CompressedCertificate.java b/src/java.base/share/classes/sun/security/ssl/CompressedCertificate.java new file mode 100644 index 00000000000..067a0344c9d --- /dev/null +++ b/src/java.base/share/classes/sun/security/ssl/CompressedCertificate.java @@ -0,0 +1,264 @@ +/* + * Copyright (C) 2022 THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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 sun.security.ssl; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.text.MessageFormat; +import java.util.Locale; +import java.util.function.Function; +import javax.net.ssl.SSLProtocolException; +import sun.security.ssl.SSLHandshake.HandshakeMessage; +import sun.security.util.Cache; +import sun.security.util.Cache.EqualByteArray; +import sun.security.util.HexDumpEncoder; + +/** + * Pack of the CompressedCertificate handshake message. + */ +final class CompressedCertificate { + + static final SSLConsumer handshakeConsumer = + new CompressedCertConsumer(); + static final HandshakeProducer handshakeProducer = + new CompressedCertProducer(); + + record CompCertCacheKey(EqualByteArray eba, int algId) {} + + /** + * The CompressedCertificate handshake message for TLS 1.3. + */ + static final class CompressedCertMessage extends HandshakeMessage { + + private final int algorithmId; + private final int uncompressedLength; + private final byte[] compressedCert; + + CompressedCertMessage(HandshakeContext context, + int algorithmId, int uncompressedLength, + byte[] compressedCert) { + super(context); + + this.algorithmId = algorithmId; + this.uncompressedLength = uncompressedLength; + this.compressedCert = compressedCert; + } + + CompressedCertMessage(HandshakeContext handshakeContext, + ByteBuffer m) throws IOException { + super(handshakeContext); + + // struct { + // CertificateCompressionAlgorithm algorithm; + // uint24 uncompressed_length; + // opaque compressed_certificate_message<1..2^24-1>; + // } CompressedCertificate; + if (m.remaining() < 9) { + throw new SSLProtocolException( + "Invalid CompressedCertificate message: " + + "insufficient data (length=" + m.remaining() + + ")"); + } + this.algorithmId = Record.getInt16(m); + this.uncompressedLength = Record.getInt24(m); + this.compressedCert = Record.getBytes24(m); + + if (m.hasRemaining()) { + throw handshakeContext.conContext.fatal( + Alert.HANDSHAKE_FAILURE, + "Invalid CompressedCertificate message: " + + "unknown extra data"); + } + } + + @Override + public SSLHandshake handshakeType() { + return SSLHandshake.COMPRESSED_CERTIFICATE; + } + + @Override + public int messageLength() { + return 8 + compressedCert.length; + } + + @Override + public void send(HandshakeOutStream hos) throws IOException { + hos.putInt16(algorithmId); + hos.putInt24(uncompressedLength); + hos.putBytes24(compressedCert); + } + + @Override + public String toString() { + MessageFormat messageFormat = new MessageFormat( + """ + "CompressedCertificate": '{' + "algorithm": "{0}", + "uncompressed_length": {1} + "compressed_certificate_message": [ + {2} + ] + '}'""", + Locale.ENGLISH); + + HexDumpEncoder hexEncoder = new HexDumpEncoder(); + Object[] messageFields = { + CompressionAlgorithm.nameOf(algorithmId), + uncompressedLength, + Utilities.indent(hexEncoder.encode(compressedCert), " ") + }; + + return messageFormat.format(messageFields); + } + } + + /** + * The "CompressedCertificate" handshake message producer for TLS 1.3. + */ + private static final + class CompressedCertProducer implements HandshakeProducer { + + // Prevent instantiation of this class. + private CompressedCertProducer() { + // blank + } + + // Note this is a special producer, which can only be called from + // the CertificateMessage producer. The input 'message' parameter + // represents the Certificate handshake message. + @Override + public byte[] produce(ConnectionContext context, + HandshakeMessage message) throws IOException { + // The producing happens in handshake context only. + HandshakeContext hc = (HandshakeContext) context; + + // Compress the Certificate message. + HandshakeOutStream hos = new HandshakeOutStream(null); + message.send(hos); + byte[] certMsg = hos.toByteArray(); + byte[] compressedCertMsg; + + // First byte is the size of certificate_request_context which + // should be random if present. Don't cache a randomized message. + if (certMsg[0] != 0) { + compressedCertMsg = hc.certDeflater.getValue().apply(certMsg); + } else { + Cache cache = + hc.sslContext.getCompCertCache(); + CompCertCacheKey key = new CompCertCacheKey( + new EqualByteArray(certMsg), hc.certDeflater.getKey()); + compressedCertMsg = cache.get(key); + + if (compressedCertMsg == null) { + compressedCertMsg = + hc.certDeflater.getValue().apply(certMsg); + + if (SSLLogger.isOn() + && SSLLogger.isOn(SSLLogger.Opt.HANDSHAKE)) { + SSLLogger.fine("Caching CompressedCertificate message"); + } + + cache.put(key, compressedCertMsg); + } + } + + if (compressedCertMsg == null || compressedCertMsg.length == 0) { + throw hc.conContext.fatal(Alert.HANDSHAKE_FAILURE, + "No compressed Certificate data"); + } + + CompressedCertMessage ccm = new CompressedCertMessage(hc, + hc.certDeflater.getKey(), certMsg.length, + compressedCertMsg); + + if (SSLLogger.isOn() && SSLLogger.isOn(SSLLogger.Opt.HANDSHAKE)) { + SSLLogger.fine( + "Produced CompressedCertificate handshake message", + ccm); + } + + ccm.write(hc.handshakeOutput); + hc.handshakeOutput.flush(); + + // The handshake message has been delivered. + return null; + } + } + + /** + * The "CompressedCertificate" handshake message consumer for TLS 1.3. + */ + private static final class CompressedCertConsumer implements SSLConsumer { + + // Prevent instantiation of this class. + private CompressedCertConsumer() { + // blank + } + + @Override + public void consume(ConnectionContext context, + ByteBuffer message) throws IOException { + // The consuming happens in handshake context only. + HandshakeContext hc = (HandshakeContext) context; + + // clean up this consumer + hc.handshakeConsumers.remove( + SSLHandshake.COMPRESSED_CERTIFICATE.id); + hc.handshakeConsumers.remove(SSLHandshake.CERTIFICATE.id); + + // Parse the handshake message + CompressedCertMessage ccm = new CompressedCertMessage(hc, message); + if (SSLLogger.isOn() && SSLLogger.isOn(SSLLogger.Opt.HANDSHAKE)) { + SSLLogger.fine( + "Consuming CompressedCertificate handshake message", + ccm); + } + + // check the compression algorithm + Function inflater = + hc.certInflaters.get(ccm.algorithmId); + if (inflater == null) { + throw hc.conContext.fatal(Alert.BAD_CERTIFICATE, + "Unsupported certificate compression algorithm"); + } + + // decompress + byte[] certificateMessage = inflater.apply(ccm.compressedCert); + + // check the uncompressed length + if (certificateMessage == null || + certificateMessage.length != ccm.uncompressedLength) { + throw hc.conContext.fatal(Alert.BAD_CERTIFICATE, + "Improper certificate compression"); + } + + // Call the Certificate handshake message consumer. + CertificateMessage.t13HandshakeConsumer.consume(hc, + ByteBuffer.wrap(certificateMessage)); + } + } +} diff --git a/src/java.base/share/classes/sun/security/ssl/CompressionAlgorithm.java b/src/java.base/share/classes/sun/security/ssl/CompressionAlgorithm.java new file mode 100644 index 00000000000..3e9ef154424 --- /dev/null +++ b/src/java.base/share/classes/sun/security/ssl/CompressionAlgorithm.java @@ -0,0 +1,182 @@ +/* + * Copyright (C) 2022 THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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 sun.security.ssl; + +import java.io.ByteArrayOutputStream; +import java.util.AbstractMap; +import java.util.Map; +import java.util.function.Function; +import java.util.zip.Deflater; +import java.util.zip.Inflater; + +/** + * Enum for TLS certificate compression algorithms. + * This class also defines internally supported inflate/deflate functions. + */ + +enum CompressionAlgorithm { + ZLIB(1); // Currently only ZLIB is supported. + + final int id; + + CompressionAlgorithm(int id) { + this.id = id; + } + + static CompressionAlgorithm nameOf(int id) { + for (CompressionAlgorithm ca : CompressionAlgorithm.values()) { + if (ca.id == id) { + return ca; + } + } + + return null; + } + + // Return the size of a compression algorithms structure in TLS record. + static int sizeInRecord() { + return 2; + } + + // The size of compression/decompression buffer. + private static final int BUF_SIZE = 1024; + + private static final Map> DEFLATORS = + Map.of(ZLIB.id, (input) -> { + try (Deflater deflater = new Deflater(); + ByteArrayOutputStream outputStream = + new ByteArrayOutputStream(input.length)) { + + deflater.setInput(input); + deflater.finish(); + byte[] buffer = new byte[BUF_SIZE]; + + while (!deflater.finished()) { + int compressedSize = deflater.deflate(buffer); + outputStream.write(buffer, 0, compressedSize); + } + + return outputStream.toByteArray(); + } catch (Exception e) { + if (SSLLogger.isOn() + && SSLLogger.isOn(SSLLogger.Opt.HANDSHAKE)) { + SSLLogger.warning("Exception during certificate " + + "compression: ", e); + } + return null; + } + }); + + static Map.Entry> selectDeflater( + int[] compressionAlgorithmIds) { + + for (var entry : DEFLATORS.entrySet()) { + for (int id : compressionAlgorithmIds) { + if (id == entry.getKey()) { + return new AbstractMap.SimpleImmutableEntry<>(entry); + } + } + } + + return null; + } + + private static final Map> INFLATORS = + Map.of(ZLIB.id, (input) -> { + try (Inflater inflater = new Inflater(); + ByteArrayOutputStream outputStream = + new ByteArrayOutputStream(input.length)) { + + inflater.setInput(input); + byte[] buffer = new byte[BUF_SIZE]; + + while (!inflater.finished()) { + int decompressedSize = inflater.inflate(buffer); + + if (decompressedSize == 0) { + if (inflater.needsDictionary()) { + if (SSLLogger.isOn() + && SSLLogger.isOn( + SSLLogger.Opt.HANDSHAKE)) { + SSLLogger.warning("Compressed input " + + "requires a dictionary"); + } + + return null; + } + + if (inflater.needsInput()) { + if (SSLLogger.isOn() + && SSLLogger.isOn( + SSLLogger.Opt.HANDSHAKE)) { + SSLLogger.warning( + "Incomplete compressed input"); + } + + return null; + } + + // Else just break the loop. + break; + } + + outputStream.write(buffer, 0, decompressedSize); + + // Bound the memory usage. + if (outputStream.size() + > SSLConfiguration.maxHandshakeMessageSize) { + if (SSLLogger.isOn() + && SSLLogger.isOn( + SSLLogger.Opt.HANDSHAKE)) { + SSLLogger.warning("The size of the " + + "uncompressed certificate message " + + "exceeds maximum allowed size of " + + SSLConfiguration.maxHandshakeMessageSize + + " bytes; compressed size: " + + input.length); + } + + return null; + } + } + + return outputStream.toByteArray(); + } catch (Exception e) { + if (SSLLogger.isOn() + && SSLLogger.isOn(SSLLogger.Opt.HANDSHAKE)) { + SSLLogger.warning( + "Exception during certificate decompression: ", + e); + } + return null; + } + }); + + static Map> getInflaters() { + return INFLATORS; + } +} diff --git a/src/java.base/share/classes/sun/security/ssl/HandshakeContext.java b/src/java.base/share/classes/sun/security/ssl/HandshakeContext.java index 54a2650c058..fbf2c00bbb4 100644 --- a/src/java.base/share/classes/sun/security/ssl/HandshakeContext.java +++ b/src/java.base/share/classes/sun/security/ssl/HandshakeContext.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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.security.AlgorithmConstraints; import java.security.CryptoPrimitive; import java.util.*; import java.util.AbstractMap.SimpleImmutableEntry; +import java.util.function.Function; import javax.crypto.SecretKey; import javax.net.ssl.SNIServerName; import javax.net.ssl.SSLHandshakeException; @@ -131,6 +132,10 @@ abstract class HandshakeContext implements ConnectionContext { List peerRequestedSignatureSchemes; List peerRequestedCertSignSchemes; + // CertificateCompressionAlgorithm + Map> certInflaters; + Map.Entry> certDeflater; + // Known authorities X500Principal[] peerSupportedAuthorities = null; diff --git a/src/java.base/share/classes/sun/security/ssl/QuicTLSEngineImpl.java b/src/java.base/share/classes/sun/security/ssl/QuicTLSEngineImpl.java index b5f1eff179c..3384bf5f089 100644 --- a/src/java.base/share/classes/sun/security/ssl/QuicTLSEngineImpl.java +++ b/src/java.base/share/classes/sun/security/ssl/QuicTLSEngineImpl.java @@ -73,6 +73,7 @@ public final class QuicTLSEngineImpl implements QuicTLSEngine, SSLTransport { SSLHandshake.ENCRYPTED_EXTENSIONS.id, HANDSHAKE, SSLHandshake.CERTIFICATE_REQUEST.id, HANDSHAKE, SSLHandshake.CERTIFICATE.id, HANDSHAKE, + SSLHandshake.COMPRESSED_CERTIFICATE.id, HANDSHAKE, SSLHandshake.CERTIFICATE_VERIFY.id, HANDSHAKE, SSLHandshake.FINISHED.id, HANDSHAKE, SSLHandshake.NEW_SESSION_TICKET.id, ONE_RTT); diff --git a/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java b/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java index a1cc3ee112f..fdeb94bb496 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java @@ -34,7 +34,9 @@ import java.util.concurrent.locks.ReentrantLock; import java.util.stream.Collectors; import javax.net.ssl.*; import sun.security.provider.certpath.AlgorithmChecker; +import sun.security.ssl.CompressedCertificate.CompCertCacheKey; import sun.security.ssl.SSLAlgorithmConstraints.SIGNATURE_CONSTRAINTS_MODE; +import sun.security.util.Cache; import sun.security.validator.Validator; /** @@ -73,6 +75,10 @@ public abstract class SSLContextImpl extends SSLContextSpi { private final ReentrantLock contextLock = new ReentrantLock(); + // Avoid compressing local certificates repeatedly for every handshake. + private final Cache compCertCache = + Cache.newSoftMemoryCache(12); + SSLContextImpl() { ephemeralKeyManager = new EphemeralKeyManager(); clientCache = new SSLSessionContextImpl(false); @@ -225,6 +231,10 @@ public abstract class SSLContextImpl extends SSLContextSpi { return ephemeralKeyManager; } + Cache getCompCertCache() { + return compCertCache; + } + // Used for DTLS in server mode only. HelloCookieManager getHelloCookieManager(ProtocolVersion protocolVersion) { if (helloCookieManagerBuilder == null) { diff --git a/src/java.base/share/classes/sun/security/ssl/SSLExtension.java b/src/java.base/share/classes/sun/security/ssl/SSLExtension.java index aacb9420748..b13edc0359c 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLExtension.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLExtension.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -270,6 +270,27 @@ enum SSLExtension implements SSLStringizer { // Extensions defined in RFC 7924 (TLS Cached Information Extension) CACHED_INFO (0x0019, "cached_info"), + // Extensions defined in RFC 8879 (TLS Certificate Compression) + CH_COMPRESS_CERTIFICATE (0x001B, "compress_certificate", + SSLHandshake.CLIENT_HELLO, + ProtocolVersion.PROTOCOLS_OF_13, + CompressCertExtension.chNetworkProducer, + CompressCertExtension.chOnLoadConsumer, + null, + null, + null, + CompressCertExtension.ccStringizer), + + CR_COMPRESS_CERTIFICATE (0x001B, "compress_certificate", + SSLHandshake.CERTIFICATE_REQUEST, + ProtocolVersion.PROTOCOLS_OF_13, + CompressCertExtension.crNetworkProducer, + CompressCertExtension.crOnLoadConsumer, + null, + null, + null, + CompressCertExtension.ccStringizer), + // Extensions defined in RFC 5077 (TLS Session Resumption without Server-Side State) CH_SESSION_TICKET (0x0023, "session_ticket", SSLHandshake.CLIENT_HELLO, diff --git a/src/java.base/share/classes/sun/security/ssl/SSLHandshake.java b/src/java.base/share/classes/sun/security/ssl/SSLHandshake.java index 7c78f6c3005..2c6b58bafa5 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLHandshake.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLHandshake.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -370,7 +370,22 @@ enum SSLHandshake implements SSLConsumer, HandshakeProducer { }), // RFC 8879 - TLS Certificate Compression - COMPRESSED_CERTIFICATE ((byte)0x19, "compressed_certificate"), + @SuppressWarnings({"unchecked", "rawtypes"}) + COMPRESSED_CERTIFICATE ((byte)0x19, "compressed_certificate", + (new Map.Entry[] { + new SimpleImmutableEntry<>( + CompressedCertificate.handshakeConsumer, + ProtocolVersion.PROTOCOLS_OF_13 + ) + }), + (new Map.Entry[] { + // Note that the producing of this message is delegated to + // CertificateMessage producer. + new SimpleImmutableEntry<>( + CertificateMessage.t13HandshakeProducer, + ProtocolVersion.PROTOCOLS_OF_13 + ) + })), // RFC 8870 - Encrypted Key Transport for DTLS/Secure RTP EKT_KEY ((byte)0x1A, "ekt_key"), diff --git a/src/java.base/share/classes/sun/security/ssl/ServerHello.java b/src/java.base/share/classes/sun/security/ssl/ServerHello.java index 6980c216697..4bd2b0a059f 100644 --- a/src/java.base/share/classes/sun/security/ssl/ServerHello.java +++ b/src/java.base/share/classes/sun/security/ssl/ServerHello.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1461,6 +1461,11 @@ final class ServerHello { chc.handshakeConsumers.put( SSLHandshake.CERTIFICATE_REQUEST.id, SSLHandshake.CERTIFICATE_REQUEST); + if (chc.certInflaters != null && !chc.certInflaters.isEmpty()) { + chc.handshakeConsumers.put( + SSLHandshake.COMPRESSED_CERTIFICATE.id, + SSLHandshake.COMPRESSED_CERTIFICATE); + } chc.handshakeConsumers.put( SSLHandshake.CERTIFICATE.id, SSLHandshake.CERTIFICATE); diff --git a/test/jdk/java/net/httpclient/HeadTest.java b/test/jdk/java/net/httpclient/HeadTest.java index c0bef240520..5694e4f6016 100644 --- a/test/jdk/java/net/httpclient/HeadTest.java +++ b/test/jdk/java/net/httpclient/HeadTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,14 +22,25 @@ */ /* - * @test - * @bug 8203433 8276559 + * @test id=withCertificateCompression + * @bug 8203433 8276559 8372526 * @summary Tests Client handles HEAD and 304 responses correctly. * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.test.lib.net.SimpleSSLContext * @run junit/othervm -Djdk.httpclient.HttpClient.log=trace,headers,requests ${test.main.class} */ +/* + * @test id=withoutCertificateCompression + * @bug 8203433 8276559 8372526 + * @summary Tests Client handles HEAD and 304 responses correctly. + * @library /test/lib /test/jdk/java/net/httpclient/lib + * @build jdk.test.lib.net.SimpleSSLContext + * @run junit/othervm -Djdk.tls.client.disableExtensions=compress_certificate + * -Djdk.tls.server.disableExtensions=compress_certificate + * -Djdk.httpclient.HttpClient.log=trace,headers,requests HeadTest + */ + import jdk.test.lib.net.SimpleSSLContext; import javax.net.ssl.SSLContext; diff --git a/test/jdk/java/net/httpclient/LargeHandshakeTest.java b/test/jdk/java/net/httpclient/LargeHandshakeTest.java index 59cdad27cbc..ec4cd8be4aa 100644 --- a/test/jdk/java/net/httpclient/LargeHandshakeTest.java +++ b/test/jdk/java/net/httpclient/LargeHandshakeTest.java @@ -66,9 +66,9 @@ import static java.net.http.HttpClient.Version.HTTP_3; import static java.net.http.HttpOption.Http3DiscoveryMode.HTTP_3_URI_ONLY; import static java.net.http.HttpOption.H3_DISCOVERY; -/** - * @test - * @bug 8231449 +/* + * @test id=withCertificateCompression + * @bug 8231449 8372526 * @summary This test verifies that the HttpClient works correctly when the server * sends a large certificate. This test will not pass without * the fix for JDK-8231449. To regenerate the certificate, modify the @@ -91,6 +91,35 @@ import static java.net.http.HttpOption.H3_DISCOVERY; * ${test.main.class} * */ + +/* + * @test id=withoutCertificateCompression + * @bug 8231449 8372526 + * @summary This test verifies that the HttpClient works correctly when the server + * sends a large certificate. This test will not pass without + * the fix for JDK-8231449. To regenerate the certificate, modify the + * COMMAND constant as you need, possibly changing the start date + * and validity of the certificate in the command, then run the test. + * The test will run with the old certificate, but will print the new command. + * Copy paste the new command printed by this test into a terminal. + * Then modify the at run line to pass the file generated by that command + * as first argument, and copy paste the new values of the COMMAND and + * BASE64_CERT constant printed by the test into the test. + * Then restore the original at run line and test again. + * @library /test/lib /test/jdk/java/net/httpclient/lib + * @build jdk.httpclient.test.lib.common.HttpServerAdapters jdk.test.lib.net.SimpleSSLContext + * DigestEchoServer + * jdk.httpclient.test.lib.common.TestServerConfigurator + * @run main/othervm -Djdk.tls.client.disableExtensions=compress_certificate + * -Djdk.tls.server.disableExtensions=compress_certificate + * -Dtest.requiresHost=true + * -Djdk.httpclient.HttpClient.log=headers + * -Djdk.internal.httpclient.debug=true + * -Djdk.tls.maxHandshakeMessageSize=131072 + * LargeHandshakeTest + * + */ + public class LargeHandshakeTest implements HttpServerAdapters { // Use this command to regenerate the keystore file whose content is diff --git a/test/jdk/sun/security/ssl/CertificateCompression/BoundDecompressMemory.java b/test/jdk/sun/security/ssl/CertificateCompression/BoundDecompressMemory.java new file mode 100644 index 00000000000..92e771f2a4a --- /dev/null +++ b/test/jdk/sun/security/ssl/CertificateCompression/BoundDecompressMemory.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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.test.lib.Asserts.assertEquals; +import static jdk.test.lib.Asserts.assertNotNull; +import static jdk.test.lib.Asserts.assertTrue; +import static jdk.test.lib.Utils.runAndCheckException; +import static jdk.test.lib.security.SecurityUtils.runAndGetLog; + +import java.util.Scanner; +import javax.net.ssl.SSLHandshakeException; + +/* + * @test + * @bug 8372526 + * @summary Bound the memory usage when decompressing CompressedCertificate. + * @modules java.base/sun.security.x509 + * java.base/sun.security.util + * @library /javax/net/ssl/templates + * /test/lib + * @run main/othervm BoundDecompressMemory + */ + +public class BoundDecompressMemory extends CompressedCertMsgCache { + + private static final int MAX_HANDSHAKE_MESSAGE_SIZE = 4096; + + public static void main(String[] args) throws Exception { + System.setProperty("jdk.tls.maxHandshakeMessageSize", + Integer.toString(MAX_HANDSHAKE_MESSAGE_SIZE)); + + String log = runAndGetLog(() -> { + try { + // Use highly compressible subject name for server's certificate. + serverCertSubjectName = "O=Some-Org" + + "A".repeat(MAX_HANDSHAKE_MESSAGE_SIZE) + + ", L=Some-City, ST=Some-State, C=US"; + + setupCertificates(); + serverSslContext = getSSLContext(trustedCert, serverCert, + serverKeys.getPrivate(), "TLSv1.3"); + clientSslContext = getSSLContext(trustedCert, clientCert, + clientKeys.getPrivate(), "TLSv1.3"); + + runAndCheckException(() -> new BoundDecompressMemory().run(), + serverEx -> { + Throwable clientEx = serverEx.getSuppressed()[0]; + assertTrue( + clientEx instanceof SSLHandshakeException); + assertEquals("(bad_certificate) Improper " + + "certificate compression", + clientEx.getMessage()); + } + ); + } catch (Exception _) { + } + }); + + // Check for the specific decompression error message. + assertNotNull(new Scanner(log).findWithinHorizon("The size of the " + + "uncompressed certificate message " + + "exceeds maximum allowed size of " + + MAX_HANDSHAKE_MESSAGE_SIZE + + " bytes; compressed size: \\d+", 0)); + } +} diff --git a/test/jdk/sun/security/ssl/CertificateCompression/ClientCertCompressionExt.java b/test/jdk/sun/security/ssl/CertificateCompression/ClientCertCompressionExt.java new file mode 100644 index 00000000000..2708f1e6872 --- /dev/null +++ b/test/jdk/sun/security/ssl/CertificateCompression/ClientCertCompressionExt.java @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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.test.lib.Asserts.assertEquals; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +/* + * @test + * @bug 8372526 + * @summary Add support for ZLIB TLS Certificate Compression. + * @library /javax/net/ssl/templates + * /test/lib + * + * @run main/othervm ClientCertCompressionExt + * @run main/othervm -Djdk.tls.client.disableExtensions=compress_certificate + * ClientCertCompressionExt + * + */ + +public class ClientCertCompressionExt extends SSLEngineTemplate { + + private static final int CLI_HELLO_MSG = 1; + private static final int COMP_CERT_EXT = 27; + // zlib(1), brotli(2), zstd(3) + private static final List DEFAULT_COMP_ALGS = List.of(1); + + ClientCertCompressionExt() throws Exception { + super(); + } + + public static void main(String[] args) throws Exception { + new ClientCertCompressionExt().runTest( + !System.getProperty("jdk.tls.client.disableExtensions", "") + .contains("compress_certificate")); + } + + private void runTest(boolean shouldProduceExt) throws Exception { + // Produce client_hello + clientEngine.wrap(clientOut, cTOs); + cTOs.flip(); + + checkClientHello(shouldProduceExt); + } + + private void checkClientHello(boolean shouldProduceExt) throws Exception { + List compCertExt = getCompAlgsCliHello( + extractHandshakeMsg(cTOs, CLI_HELLO_MSG, false)); + + if (shouldProduceExt) { + assertEquals(DEFAULT_COMP_ALGS, compCertExt, + "Unexpected compress_certificate extension algorithms: " + + compCertExt); + } else { + assertEquals(compCertExt.size(), 0, + "compress_certificate extension present in ClientHello"); + } + } + + /** + * Parses the ClientHello message and extracts from it a list of + * compression algorithm values. It is assumed that the provided + * ByteBuffer has its position set at the first byte of the ClientHello + * message body (AFTER the handshake header) and contains the entire + * hello message. Upon successful completion of this method the ByteBuffer + * will have its position reset to the initial offset in the buffer. + * If an exception is thrown the position at the time of the exception + * will be preserved. + * + * @param data The ByteBuffer containing the ClientHello bytes. + * @return A List of the compression algorithm values. + */ + private List getCompAlgsCliHello(ByteBuffer data) { + Objects.requireNonNull(data); + data.mark(); + + // Skip over the protocol version and client random + data.position(data.position() + 34); + + // Jump past the session ID (if there is one) + int sessLen = Byte.toUnsignedInt(data.get()); + if (sessLen != 0) { + data.position(data.position() + sessLen); + } + + // Jump past the cipher suites + int csLen = Short.toUnsignedInt(data.getShort()); + if (csLen != 0) { + data.position(data.position() + csLen); + } + + // ...and the compression + int compLen = Byte.toUnsignedInt(data.get()); + if (compLen != 0) { + data.position(data.position() + compLen); + } + + List extSigAlgs = getCompAlgsFromExt(data); + + // We should be at the end of the ClientHello + data.reset(); + return extSigAlgs; + } + + /** + * Gets compression algorithms from the given TLS extension. + * The buffer should be positioned at the start of the extension. + */ + private List getCompAlgsFromExt(ByteBuffer data) { + + List extCompAlgs = new ArrayList<>(); + data.getShort(); // read length + + while (data.hasRemaining()) { + int extType = Short.toUnsignedInt(data.getShort()); + int extLen = Short.toUnsignedInt(data.getShort()); + + if (extType == COMP_CERT_EXT) { + int sigSchemeLen = data.get(); + + for (int ssOff = 0; ssOff < sigSchemeLen; ssOff += 2) { + Integer schemeName = Short.toUnsignedInt(data.getShort()); + extCompAlgs.add(schemeName); + } + } else { + // Not the extension we're looking for. Skip past the + // extension data + data.position(data.position() + extLen); + } + } + + return extCompAlgs; + } +} diff --git a/test/jdk/sun/security/ssl/CertificateCompression/CompressedCertMsg.java b/test/jdk/sun/security/ssl/CertificateCompression/CompressedCertMsg.java new file mode 100644 index 00000000000..265ba3a8fc9 --- /dev/null +++ b/test/jdk/sun/security/ssl/CertificateCompression/CompressedCertMsg.java @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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.test.lib.Asserts.assertEquals; +import static jdk.test.lib.security.SecurityUtils.countSubstringOccurrences; +import static jdk.test.lib.security.SecurityUtils.runAndGetLog; + +import javax.net.ssl.SSLParameters; +import javax.net.ssl.SSLServerSocket; + +/* + * @test + * @bug 8372526 + * @summary Add support for ZLIB TLS Certificate Compression + * @library /javax/net/ssl/templates + * /test/lib + * + * @run main/othervm CompressedCertMsg + * @run main/othervm -Djdk.tls.client.disableExtensions=compress_certificate CompressedCertMsg + * @run main/othervm -Djdk.tls.server.disableExtensions=compress_certificate CompressedCertMsg + * @run main/othervm -Djdk.tls.client.disableExtensions=compress_certificate + * -Djdk.tls.server.disableExtensions=compress_certificate + * CompressedCertMsg + */ + +public class CompressedCertMsg extends SSLSocketTemplate { + + private static final String PRODUCED_COMP_CERT_MSG = + """ + Produced CompressedCertificate handshake message ( + "CompressedCertificate": { + "algorithm": "ZLIB", + """; + + private static final String CONSUMING_COMP_CERT_MSG = + """ + Consuming CompressedCertificate handshake message ( + "CompressedCertificate": { + "algorithm": "ZLIB", + """; + + private static final String IGNORE_EXT_MSG = + """ + Ignore unknown or unsupported extension ( + "compress_certificate (27)": { + """; + + private static final String CH_EXT = + """ + }, + "compress_certificate (27)": { + "compression algorithms": [ZLIB] + }, + """; + + private static final String CR_EXT = + """ + "CertificateRequest": { + "certificate_request_context": "", + "extensions": [ + "compress_certificate (27)": { + "compression algorithms": [ZLIB] + """; + + // Server sends CertificateRequest and gets a certificate + // from the client as well as the client from the server. + @Override + protected void configureServerSocket(SSLServerSocket sslServerSocket) { + SSLParameters sslParameters = sslServerSocket.getSSLParameters(); + sslParameters.setNeedClientAuth(true); + sslServerSocket.setSSLParameters(sslParameters); + } + + public static void main(String[] args) throws Exception { + boolean clientSideEnabled = !System.getProperty( + "jdk.tls.client.disableExtensions", "") + .contains("compress_certificate"); + boolean serverSideEnabled = !System.getProperty( + "jdk.tls.server.disableExtensions", "") + .contains("compress_certificate"); + + // Complete 1 handshake. + String log = runAndGetLog(() -> { + try { + new CompressedCertMsg().run(); + } catch (Exception _) { + } + }); + + // To make the test pass on Windows. + log = log.replace("\r\n", "\n"); + + if (clientSideEnabled && serverSideEnabled) { + // Make sure CompressedCertificate message is produced and consumed + // twice - by the server and by the client. + assertEquals(2, countSubstringOccurrences(log, + PRODUCED_COMP_CERT_MSG)); + assertEquals(2, countSubstringOccurrences(log, + CONSUMING_COMP_CERT_MSG)); + // Extensions are produced and consumed, so they appear in the + // log twice. + assertEquals(2, countSubstringOccurrences(log, CH_EXT)); + assertEquals(2, countSubstringOccurrences(log, CR_EXT)); + assertEquals(0, countSubstringOccurrences(log, IGNORE_EXT_MSG)); + } else if (clientSideEnabled) { + assertEquals(0, countSubstringOccurrences(log, + PRODUCED_COMP_CERT_MSG)); + assertEquals(0, countSubstringOccurrences(log, + CONSUMING_COMP_CERT_MSG)); + assertEquals(2, countSubstringOccurrences(log, CH_EXT)); + assertEquals(0, countSubstringOccurrences(log, CR_EXT)); + assertEquals(1, countSubstringOccurrences(log, IGNORE_EXT_MSG)); + } else if (serverSideEnabled) { + assertEquals(0, countSubstringOccurrences(log, + PRODUCED_COMP_CERT_MSG)); + assertEquals(0, countSubstringOccurrences(log, + CONSUMING_COMP_CERT_MSG)); + assertEquals(0, countSubstringOccurrences(log, CH_EXT)); + assertEquals(2, countSubstringOccurrences(log, CR_EXT)); + assertEquals(1, countSubstringOccurrences(log, IGNORE_EXT_MSG)); + } else { + assertEquals(0, countSubstringOccurrences(log, + PRODUCED_COMP_CERT_MSG)); + assertEquals(0, countSubstringOccurrences(log, + CONSUMING_COMP_CERT_MSG)); + assertEquals(0, countSubstringOccurrences(log, CH_EXT)); + assertEquals(0, countSubstringOccurrences(log, CR_EXT)); + assertEquals(0, countSubstringOccurrences(log, IGNORE_EXT_MSG)); + } + } +} diff --git a/test/jdk/sun/security/ssl/CertificateCompression/CompressedCertMsgCache.java b/test/jdk/sun/security/ssl/CertificateCompression/CompressedCertMsgCache.java new file mode 100644 index 00000000000..42e9701c6d0 --- /dev/null +++ b/test/jdk/sun/security/ssl/CertificateCompression/CompressedCertMsgCache.java @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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.test.lib.Asserts.assertEquals; +import static jdk.test.lib.security.SecurityUtils.countSubstringOccurrences; +import static jdk.test.lib.security.SecurityUtils.runAndGetLog; + +import java.io.IOException; +import java.math.BigInteger; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.KeyStore; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import java.util.Date; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManagerFactory; +import jdk.test.lib.security.CertificateBuilder; + +/* + * @test + * @bug 8372526 + * @summary Check CompressedCertificate message cache. + * @modules java.base/sun.security.x509 + * java.base/sun.security.util + * @library /javax/net/ssl/templates + * /test/lib + * @run main/othervm CompressedCertMsgCache + */ + +public class CompressedCertMsgCache extends SSLSocketTemplate { + + protected static String clientCertSubjectName = + "CN=localhost, OU=SSL-Client, ST=Some-State, C=US"; + protected static String serverCertSubjectName = + "O=Some-Org, L=Some-City, ST=Some-State, C=US"; + + protected static X509Certificate trustedCert; + protected static X509Certificate serverCert; + protected static X509Certificate clientCert; + protected static KeyPair serverKeys; + protected static KeyPair clientKeys; + protected static SSLContext serverSslContext; + protected static SSLContext clientSslContext; + + public static void main(String[] args) throws Exception { + + // Complete 3 handshakes with the same SSLContext. + String log = runAndGetLog(() -> { + try { + setupCertificates(); + serverSslContext = getSSLContext(trustedCert, serverCert, + serverKeys.getPrivate(), "TLSv1.3"); + clientSslContext = getSSLContext(trustedCert, clientCert, + clientKeys.getPrivate(), "TLSv1.3"); + + new CompressedCertMsgCache().run(); + new CompressedCertMsgCache().run(); + new CompressedCertMsgCache().run(); + } catch (Exception _) { + } + }); + + // The same CompressedCertificate message must be cached only once. + assertEquals(1, countSubstringOccurrences(log, + "Caching CompressedCertificate message")); + + // Make sure CompressedCertificate message is produced 3 times. + assertEquals(3, countSubstringOccurrences(log, + "Produced CompressedCertificate handshake message")); + + // Make sure CompressedCertificate message is consumed 3 times. + assertEquals(3, countSubstringOccurrences(log, + "Consuming CompressedCertificate handshake message")); + } + + @Override + public SSLContext createServerSSLContext() throws Exception { + return serverSslContext; + } + + @Override + public SSLContext createClientSSLContext() throws Exception { + return clientSslContext; + } + + protected static SSLContext getSSLContext( + X509Certificate trustedCertificate, X509Certificate keyCertificate, + PrivateKey privateKey, String protocol) + throws Exception { + + // create a key store + KeyStore ks = KeyStore.getInstance("PKCS12"); + ks.load(null, null); + + // import the trusted cert + ks.setCertificateEntry("TLS Signer", trustedCertificate); + + // generate certificate chain + Certificate[] chain = new Certificate[2]; + chain[0] = keyCertificate; + chain[1] = trustedCertificate; + + // import the key entry. + final char[] passphrase = "passphrase".toCharArray(); + ks.setKeyEntry("Whatever", privateKey, passphrase, chain); + + TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX"); + tmf.init(ks); + + // create SSL context + SSLContext ctx = SSLContext.getInstance(protocol); + + KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); + kmf.init(ks, passphrase); + + ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); + + return ctx; + } + + // Certificate-building helper methods. + + protected static void setupCertificates() throws Exception { + KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC"); + KeyPair caKeys = kpg.generateKeyPair(); + serverKeys = kpg.generateKeyPair(); + clientKeys = kpg.generateKeyPair(); + + trustedCert = createTrustedCert(caKeys); + + serverCert = customCertificateBuilder( + serverCertSubjectName, + serverKeys.getPublic(), caKeys.getPublic()) + .addBasicConstraintsExt(false, false, -1) + .build(trustedCert, caKeys.getPrivate(), "SHA256withECDSA"); + + clientCert = customCertificateBuilder( + clientCertSubjectName, + clientKeys.getPublic(), caKeys.getPublic()) + .addBasicConstraintsExt(false, false, -1) + .build(trustedCert, caKeys.getPrivate(), "SHA256withECDSA"); + } + + private static X509Certificate createTrustedCert(KeyPair caKeys) + throws Exception { + return customCertificateBuilder( + "O=CA-Org, L=Some-City, ST=Some-State, C=US", + caKeys.getPublic(), caKeys.getPublic()) + .addBasicConstraintsExt(true, true, 1) + .build(null, caKeys.getPrivate(), "SHA256withECDSA"); + } + + private static CertificateBuilder customCertificateBuilder( + String subjectName, PublicKey publicKey, PublicKey caKey) + throws CertificateException, IOException { + return new CertificateBuilder() + .setSubjectName(subjectName) + .setPublicKey(publicKey) + .setNotBefore( + Date.from(Instant.now().minus(1, ChronoUnit.HOURS))) + .setNotAfter(Date.from(Instant.now().plus(1, ChronoUnit.HOURS))) + .setSerialNumber(BigInteger.valueOf( + new SecureRandom().nextLong(1000000) + 1)) + .addSubjectKeyIdExt(publicKey) + .addAuthorityKeyIdExt(caKey) + .addKeyUsageExt(new boolean[]{ + true, true, true, true, true, true, true}); + } +} diff --git a/test/lib/jdk/test/lib/security/SecurityUtils.java b/test/lib/jdk/test/lib/security/SecurityUtils.java index be6ff1cc0e3..78dc2aa2729 100644 --- a/test/lib/jdk/test/lib/security/SecurityUtils.java +++ b/test/lib/jdk/test/lib/security/SecurityUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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,10 @@ package jdk.test.lib.security; +import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; +import java.io.PrintStream; import java.nio.ByteBuffer; import java.security.KeyStore; import java.security.Security; @@ -219,5 +221,40 @@ public final class SecurityUtils { return ((m.get() & 0xFF) << 8) | (m.get() & 0xFF); } + // Helper method to run and get log. + public static String runAndGetLog(Runnable runnable) { + System.setProperty("javax.net.debug", "ssl"); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + PrintStream err = new PrintStream(baos); + PrintStream origErr = System.err; + System.setErr(err); + + runnable.run(); + err.close(); + + // Save the log output and then print it as usual. + String log = baos.toString(); + System.setErr(origErr); + System.err.print(log); + return log; + } + + // Helper method to find log messages. + public static int countSubstringOccurrences(String str, String sub) { + if (str == null || sub == null || sub.isEmpty()) { + return 0; + } + + int count = 0; + int lastIndex = 0; + + while ((lastIndex = str.indexOf(sub, lastIndex)) != -1) { + count++; + lastIndex += sub.length(); + } + + return count; + } + private SecurityUtils() {} } From 5ddc36786a0797f346610819bb92353ff63abe7a Mon Sep 17 00:00:00 2001 From: Kelvin Nilsen Date: Fri, 17 Apr 2026 13:28:56 +0000 Subject: [PATCH 331/359] 8382095: GenShen: Do not clamp young reserve unnecessarily Reviewed-by: wkemper, shade --- .../share/gc/shenandoah/shenandoahFreeSet.cpp | 7 +++++-- .../gc/shenandoah/shenandoahGeneration.cpp | 9 +------- .../shenandoah/shenandoahGenerationalHeap.cpp | 21 +++++++++++++------ 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp index 592c5bffa5a..1807383123b 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp @@ -2678,8 +2678,11 @@ void ShenandoahFreeSet::reduce_young_reserve(size_t adjusted_young_reserve, size * 1. Memory currently available within old and young * 2. Trashed regions currently residing in young and old, which will become available momentarily * 3. The value of old_generation->get_region_balance() which represents the number of regions that we plan - * to transfer from old generation to young generation. Prior to each invocation of compute_young_and_old_reserves(), - * this value should computed by ShenandoahGenerationalHeap::compute_old_generation_balance(). + * to transfer from old generation to young generation. At the end of each GC cycle, we reset region_balance + * to zero. As we prepare to rebuild free set at the end of update-refs, we call + * ShenandoahGenerationalHeap::compute_old_generation_balance() to compute a new value of region_balance. + * This allows us to expand or shrink the size of the Old Collector reserves based on anticipated needs of + * the next GC cycle. */ void ShenandoahFreeSet::compute_young_and_old_reserves(size_t young_trashed_regions, size_t old_trashed_regions, size_t& young_reserve_result, size_t& old_reserve_result) const { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp index 7d082e4a8b0..5b26ee67653 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp @@ -310,16 +310,9 @@ void ShenandoahGeneration::prepare_regions_and_collection_set(bool concurrent) { ShenandoahGCPhase phase(concurrent ? ShenandoahPhaseTimings::final_rebuild_freeset : ShenandoahPhaseTimings::degen_gc_final_rebuild_freeset); ShenandoahHeapLocker locker(heap->lock()); - - // We are preparing for evacuation. + // At start of evacation, we do NOT compute_old_generation_balance() size_t young_trashed_regions, old_trashed_regions, first_old, last_old, num_old; _free_set->prepare_to_rebuild(young_trashed_regions, old_trashed_regions, first_old, last_old, num_old); - if (heap->mode()->is_generational()) { - ShenandoahGenerationalHeap* gen_heap = ShenandoahGenerationalHeap::heap(); - size_t allocation_runway = - gen_heap->young_generation()->heuristics()->bytes_of_allocation_runway_before_gc_trigger(young_trashed_regions); - gen_heap->compute_old_generation_balance(allocation_runway, old_trashed_regions, young_trashed_regions); - } _free_set->finish_rebuild(young_trashed_regions, old_trashed_regions, num_old); } } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp index a51449e91f4..1694121b955 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp @@ -406,11 +406,14 @@ template oop ShenandoahGenerationalHeap::try_evacuate_object(oop p, Thread* thread, uint from_region_age); template oop ShenandoahGenerationalHeap::try_evacuate_object(oop p, Thread* thread, uint from_region_age); +// Call this function at the end of a GC cycle in order to establish proper sizes of young and old reserves, +// setting the old-generation balance so that GC can perform the anticipated evacuations. +// // Make sure old-generation is large enough, but no larger than is necessary, to hold mixed evacuations // and promotions, if we anticipate either. Any deficit is provided by the young generation, subject to // mutator_xfer_limit, and any surplus is transferred to the young generation. mutator_xfer_limit is -// the maximum we're able to transfer from young to old. This is called at the end of GC, as we prepare -// for the idle span that precedes the next GC. +// the maximum we're able to transfer from young to old. The mutator_xfer_limit constrains the transfer +// of memory from young to old. It does not limit young reserves. void ShenandoahGenerationalHeap::compute_old_generation_balance(size_t mutator_xfer_limit, size_t old_trashed_regions, size_t young_trashed_regions) { shenandoah_assert_heaplocked(); @@ -462,11 +465,17 @@ void ShenandoahGenerationalHeap::compute_old_generation_balance(size_t mutator_x bound_on_old_reserve)); assert(mutator_xfer_limit <= young_available, "Cannot transfer (%zu) memory that is not available (%zu)", mutator_xfer_limit, young_available); - // Young reserves are to be taken out of the mutator_xfer_limit. - if (young_reserve > mutator_xfer_limit) { - young_reserve = mutator_xfer_limit; + + if (young_reserve > young_available) { + young_reserve = young_available; + } + // We allow young_reserve to exceed mutator_xfer_limit. Essentially, this means the GC is already behind the pace + // of mutator allocations, and we'll need to trigger the next GC as soon as possible. + if (mutator_xfer_limit > young_reserve) { + mutator_xfer_limit -= young_reserve; + } else { + mutator_xfer_limit = 0; } - mutator_xfer_limit -= young_reserve; // Decide how much old space we should reserve for a mixed collection size_t proposed_reserve_for_mixed = 0; From b418cbcdd4b8b200f5fe801469da1e3970eed634 Mon Sep 17 00:00:00 2001 From: Viktor Klang Date: Fri, 17 Apr 2026 14:03:47 +0000 Subject: [PATCH 332/359] 8381418: Clarifying the identity Parameter in the Java Stream.reduce() Method Documentation Reviewed-by: liach, alanb --- src/java.base/share/classes/java/util/stream/Stream.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/java.base/share/classes/java/util/stream/Stream.java b/src/java.base/share/classes/java/util/stream/Stream.java index 1dd13133fe1..645f4f033b7 100644 --- a/src/java.base/share/classes/java/util/stream/Stream.java +++ b/src/java.base/share/classes/java/util/stream/Stream.java @@ -1002,8 +1002,8 @@ public interface Stream extends BaseStream> { /** * Performs a reduction on the - * elements of this stream, using the provided identity, accumulation and - * combining functions. This is equivalent to: + * elements of this stream using the provided identity value, accumulation + * function, and combining function. This is equivalent to: *
    {@code
          *     U result = identity;
          *     for (T element : this stream)
    
    From c3c59413be1a05e5b2362bb84d5fd50a8cbceff0 Mon Sep 17 00:00:00 2001
    From: Quan Anh Mai 
    Date: Fri, 17 Apr 2026 14:09:07 +0000
    Subject: [PATCH 333/359] 8378966: C2: PhaseIdealLoop::pin_nodes_dependent_on
     must not be called with nullptr
    
    Reviewed-by: chagedorn, aseoane
    ---
     src/hotspot/share/opto/loopopts.cpp | 14 ++++++++++++--
     src/hotspot/share/opto/split_if.cpp |  3 +++
     2 files changed, 15 insertions(+), 2 deletions(-)
    
    diff --git a/src/hotspot/share/opto/loopopts.cpp b/src/hotspot/share/opto/loopopts.cpp
    index 11b23d7c365..ccd53129a87 100644
    --- a/src/hotspot/share/opto/loopopts.cpp
    +++ b/src/hotspot/share/opto/loopopts.cpp
    @@ -1307,7 +1307,14 @@ Node* PhaseIdealLoop::place_outside_loop(Node* useblock, IdealLoopTree* loop) co
     
     
     bool PhaseIdealLoop::identical_backtoback_ifs(Node *n) {
    -  if (!n->is_If() || n->is_BaseCountedLoopEnd()) {
    +  if (!n->is_If()) {
    +    return false;
    +  }
    +  if (n->outcnt() != n->as_If()->required_outcnt()) {
    +    assert(false, "malformed IfNode with %d outputs", n->outcnt());
    +    return false;
    +  }
    +  if (n->is_BaseCountedLoopEnd()) {
         return false;
       }
       if (!n->in(0)->is_Region()) {
    @@ -1433,7 +1440,10 @@ void PhaseIdealLoop::split_if_with_blocks_post(Node *n) {
     
         // Check some safety conditions
         if (iff->is_If()) {        // Classic split-if?
    -      if (iff->in(0) != n_ctrl) {
    +      if (iff->outcnt() != iff->as_If()->required_outcnt()) {
    +        assert(false, "malformed IfNode with %d outputs", iff->outcnt());
    +        return;
    +      } else if (iff->in(0) != n_ctrl) {
             return; // Compare must be in same blk as if
           }
         } else if (iff->is_CMove()) { // Trying to split-up a CMOVE
    diff --git a/src/hotspot/share/opto/split_if.cpp b/src/hotspot/share/opto/split_if.cpp
    index c1303f0d0db..e5f8043ae19 100644
    --- a/src/hotspot/share/opto/split_if.cpp
    +++ b/src/hotspot/share/opto/split_if.cpp
    @@ -704,6 +704,9 @@ void PhaseIdealLoop::do_split_if(Node* iff, RegionNode** new_false_region, Regio
           new_true = ifpx;
         }
       }
    +  assert(new_false != nullptr, "iff is malformed");
    +  assert(new_true != nullptr, "iff is malformed");
    +
       _igvn.remove_dead_node(new_iff, PhaseIterGVN::NodeOrigin::Speculative);
       // Lazy replace IDOM info with the region's dominator
       replace_node_and_forward_ctrl(iff, region_dom);
    
    From 26ccc2eaa491531faaecc6214196f3ca082a7e06 Mon Sep 17 00:00:00 2001
    From: Kelvin Nilsen 
    Date: Fri, 17 Apr 2026 15:30:34 +0000
    Subject: [PATCH 334/359] 8380651: [ubsan] gc/logging/TestGCId.java triggers
     runtime error: division by zero in shenandoahAdaptiveHeuristics
    
    Reviewed-by: wkemper, shade, xpeng
    ---
     .../shenandoahAdaptiveHeuristics.cpp          | 34 ++++++++++++-------
     .../gc/shenandoah/shenandoahControlThread.cpp |  3 +-
     .../shenandoahGenerationalControlThread.cpp   |  5 ++-
     .../share/gc/shenandoah/shenandoahHeap.cpp    |  9 +++--
     .../share/gc/shenandoah/shenandoahHeap.hpp    |  2 +-
     .../share/gc/shenandoah/shenandoahUtils.cpp   |  7 ++--
     .../share/gc/shenandoah/shenandoahUtils.hpp   |  3 +-
     7 files changed, 38 insertions(+), 25 deletions(-)
    
    diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp
    index 6b327d7e4af..c595d1fd9cd 100644
    --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp
    +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp
    @@ -209,14 +209,14 @@ void ShenandoahAdaptiveHeuristics::choose_collection_set_from_regiondata(Shenand
       }
     }
     
    -void ShenandoahAdaptiveHeuristics::add_degenerated_gc_time(double timestamp, double gc_time) {
    +void ShenandoahAdaptiveHeuristics::add_degenerated_gc_time(double time_at_start, double gc_time) {
       // Conservatively add sample into linear model If this time is above the predicted concurrent gc time
    -  if (predict_gc_time(timestamp) < gc_time) {
    -    add_gc_time(timestamp, gc_time);
    +  if (predict_gc_time(time_at_start) < gc_time) {
    +    add_gc_time(time_at_start, gc_time);
       }
     }
     
    -void ShenandoahAdaptiveHeuristics::add_gc_time(double timestamp, double gc_time) {
    +void ShenandoahAdaptiveHeuristics::add_gc_time(double time_at_start, double gc_time) {
       // Update best-fit linear predictor of GC time
       uint index = (_gc_time_first_sample_index + _gc_time_num_samples) % GC_TIME_SAMPLE_SIZE;
       if (_gc_time_num_samples == GC_TIME_SAMPLE_SIZE) {
    @@ -225,10 +225,10 @@ void ShenandoahAdaptiveHeuristics::add_gc_time(double timestamp, double gc_time)
         _gc_time_sum_of_xy -= _gc_time_xy[index];
         _gc_time_sum_of_xx -= _gc_time_xx[index];
       }
    -  _gc_time_timestamps[index] = timestamp;
    +  _gc_time_timestamps[index] = time_at_start;
       _gc_time_samples[index] = gc_time;
    -  _gc_time_xy[index] = timestamp * gc_time;
    -  _gc_time_xx[index] = timestamp * timestamp;
    +  _gc_time_xy[index] = time_at_start * gc_time;
    +  _gc_time_xx[index] = time_at_start * time_at_start;
     
       _gc_time_sum_of_timestamps += _gc_time_timestamps[index];
       _gc_time_sum_of_samples += _gc_time_samples[index];
    @@ -247,18 +247,26 @@ void ShenandoahAdaptiveHeuristics::add_gc_time(double timestamp, double gc_time)
         _gc_time_b = gc_time;
         _gc_time_sd = 0.0;
       } else if (_gc_time_num_samples == 2) {
    -    // Two points define a line
    -    double delta_y = gc_time - _gc_time_samples[_gc_time_first_sample_index];
    -    double delta_x = timestamp - _gc_time_timestamps[_gc_time_first_sample_index];
    -    _gc_time_m = delta_y / delta_x;
     
    +    assert(time_at_start > _gc_time_timestamps[_gc_time_first_sample_index],
    +           "Two GC cycles cannot finish at same time: %.6f vs %.6f, with GC times %.6f and %.6f", time_at_start,
    +           _gc_time_timestamps[_gc_time_first_sample_index], gc_time, _gc_time_samples[_gc_time_first_sample_index]);
    +
    +    // Two points define a line
    +    double delta_x = time_at_start - _gc_time_timestamps[_gc_time_first_sample_index];
    +    double delta_y = gc_time - _gc_time_samples[_gc_time_first_sample_index];
    +    _gc_time_m = delta_y / delta_x;
         // y = mx + b
         // so b = y0 - mx0
    -    _gc_time_b = gc_time - _gc_time_m * timestamp;
    +    _gc_time_b = gc_time - _gc_time_m * time_at_start;
         _gc_time_sd = 0.0;
       } else {
    +    // Since timestamps are monotonically increasing, denominator does not equal zero.
    +    double denominator = _gc_time_num_samples * _gc_time_sum_of_xx - _gc_time_sum_of_timestamps * _gc_time_sum_of_timestamps;
    +    assert(denominator != 0.0, "Invariant: samples: %u, sum_of_xx: %.6f, sum_of_timestamps: %.6f",
    +           _gc_time_num_samples, _gc_time_sum_of_xx, _gc_time_sum_of_timestamps);
         _gc_time_m = ((_gc_time_num_samples * _gc_time_sum_of_xy - _gc_time_sum_of_timestamps * _gc_time_sum_of_samples) /
    -                  (_gc_time_num_samples * _gc_time_sum_of_xx - _gc_time_sum_of_timestamps * _gc_time_sum_of_timestamps));
    +                  denominator);
         _gc_time_b = (_gc_time_sum_of_samples - _gc_time_m * _gc_time_sum_of_timestamps) / _gc_time_num_samples;
         double sum_of_squared_deviations = 0.0;
         for (size_t i = 0; i < _gc_time_num_samples; i++) {
    diff --git a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp
    index 4c6e82c86a5..6175f15676c 100644
    --- a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp
    +++ b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp
    @@ -346,7 +346,8 @@ void ShenandoahControlThread::service_stw_full_cycle(GCCause::Cause cause) {
     void ShenandoahControlThread::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();
    -  ShenandoahGCSession session(cause, heap->global_generation());
    +  ShenandoahGCSession session(cause, heap->global_generation(), true,
    +                              point == ShenandoahGC::ShenandoahDegenPoint::_degenerated_outside_cycle);
     
       heap->increment_total_collections(false);
     
    diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp
    index aa6a4a9bab2..bbad82de1dc 100644
    --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp
    +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp
    @@ -628,11 +628,10 @@ void ShenandoahGenerationalControlThread::service_stw_full_cycle(GCCause::Cause
     
     void ShenandoahGenerationalControlThread::service_stw_degenerated_cycle(const ShenandoahGCRequest& request) {
       assert(_degen_point != ShenandoahGC::_degenerated_unset, "Degenerated point should be set");
    -  request.generation->heuristics()->record_degenerated_cycle_start(ShenandoahGC::ShenandoahDegenPoint::_degenerated_outside_cycle
    -                                                                  == _degen_point);
       _heap->increment_total_collections(false);
     
    -  ShenandoahGCSession session(request.cause, request.generation);
    +  ShenandoahGCSession session(request.cause, request.generation, true,
    +                              _degen_point == ShenandoahGC::ShenandoahDegenPoint::_degenerated_outside_cycle);
       ShenandoahDegenGC gc(_degen_point, request.generation);
       gc.collect(request.cause);
       _degen_point = ShenandoahGC::_degenerated_unset;
    diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp
    index 75d3ade4e49..4b01ea1cd52 100644
    --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp
    +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp
    @@ -1650,7 +1650,8 @@ void ShenandoahHeap::set_active_generation(ShenandoahGeneration* generation) {
       _active_generation = generation;
     }
     
    -void ShenandoahHeap::on_cycle_start(GCCause::Cause cause, ShenandoahGeneration* generation) {
    +void ShenandoahHeap::on_cycle_start(GCCause::Cause cause, ShenandoahGeneration* generation,
    +                                    bool is_degenerated, bool is_out_of_cycle) {
       shenandoah_policy()->record_collection_cause(cause);
     
       const GCCause::Cause current = gc_cause();
    @@ -1659,7 +1660,11 @@ void ShenandoahHeap::on_cycle_start(GCCause::Cause cause, ShenandoahGeneration*
     
       set_gc_cause(cause);
     
    -  generation->heuristics()->record_cycle_start();
    +  if (is_degenerated) {
    +    generation->heuristics()->record_degenerated_cycle_start(is_out_of_cycle);
    +  } else {
    +    generation->heuristics()->record_cycle_start();
    +  }
     }
     
     void ShenandoahHeap::on_cycle_end(ShenandoahGeneration* generation) {
    diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp
    index ab7dd00b774..bed26a093d0 100644
    --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp
    +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp
    @@ -564,7 +564,7 @@ public:
         return _evac_tracker;
       }
     
    -  void on_cycle_start(GCCause::Cause cause, ShenandoahGeneration* generation);
    +  void on_cycle_start(GCCause::Cause cause, ShenandoahGeneration* generation, bool is_degenerated, bool is_out_of_cycle);
       void on_cycle_end(ShenandoahGeneration* generation);
     
       ShenandoahVerifier*        verifier();
    diff --git a/src/hotspot/share/gc/shenandoah/shenandoahUtils.cpp b/src/hotspot/share/gc/shenandoah/shenandoahUtils.cpp
    index dea47fcbf4f..5af2e274833 100644
    --- a/src/hotspot/share/gc/shenandoah/shenandoahUtils.cpp
    +++ b/src/hotspot/share/gc/shenandoah/shenandoahUtils.cpp
    @@ -56,15 +56,14 @@ const char* ShenandoahGCSession::cycle_end_message(ShenandoahGenerationType type
       }
     }
     
    -ShenandoahGCSession::ShenandoahGCSession(GCCause::Cause cause, ShenandoahGeneration* generation) :
    +ShenandoahGCSession::ShenandoahGCSession(GCCause::Cause cause, ShenandoahGeneration* generation,
    +                                         bool is_degenerated, bool is_out_of_cycle) :
       _heap(ShenandoahHeap::heap()),
       _generation(generation),
       _timer(_heap->gc_timer()),
       _tracer(_heap->tracer()) {
       assert(!ShenandoahGCPhase::is_current_phase_valid(), "No current GC phase");
    -
    -  _heap->on_cycle_start(cause, _generation);
    -
    +  _heap->on_cycle_start(cause, _generation, is_degenerated, is_out_of_cycle);
       _timer->register_gc_start();
       _tracer->report_gc_start(cause, _timer->gc_start());
       _heap->trace_heap_before_gc(_tracer);
    diff --git a/src/hotspot/share/gc/shenandoah/shenandoahUtils.hpp b/src/hotspot/share/gc/shenandoah/shenandoahUtils.hpp
    index 0169941c3d9..1ed6e43e3e1 100644
    --- a/src/hotspot/share/gc/shenandoah/shenandoahUtils.hpp
    +++ b/src/hotspot/share/gc/shenandoah/shenandoahUtils.hpp
    @@ -70,7 +70,8 @@ private:
     
       static const char* cycle_end_message(ShenandoahGenerationType type);
     public:
    -  ShenandoahGCSession(GCCause::Cause cause, ShenandoahGeneration* generation);
    +  ShenandoahGCSession(GCCause::Cause cause, ShenandoahGeneration* generation,
    +                      bool is_degenerated = false, bool is_out_of_cycle = false);
       ~ShenandoahGCSession();
     };
     
    
    From 7f90efd7d4d97c9d556c0089c27ad3a3c0dfca6d Mon Sep 17 00:00:00 2001
    From: Coleen Phillimore 
    Date: Fri, 17 Apr 2026 16:12:21 +0000
    Subject: [PATCH 335/359] 8381145: Missing ResourceMark in Mutex::print_on()
    
    Reviewed-by: stefank, pchilanomate, dholmes
    ---
     src/hotspot/share/runtime/mutex.cpp       | 28 +++++++++++++++--------
     src/hotspot/share/runtime/mutex.hpp       |  6 +++--
     test/hotspot/gtest/runtime/test_mutex.cpp |  5 ++--
     3 files changed, 26 insertions(+), 13 deletions(-)
    
    diff --git a/src/hotspot/share/runtime/mutex.cpp b/src/hotspot/share/runtime/mutex.cpp
    index c455b5f36a2..8e0c1d10e5c 100644
    --- a/src/hotspot/share/runtime/mutex.cpp
    +++ b/src/hotspot/share/runtime/mutex.cpp
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 1998, 2026, Oracle and/or its affiliates. All rights reserved.
      * 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,7 +293,8 @@ Mutex::Mutex(Rank rank, const char * name, bool allow_vm_block) : _owner(nullptr
       _rank            = rank;
       _skip_rank_check = false;
     
    -  assert(_rank >= static_cast(0) && _rank <= safepoint, "Bad lock rank %s: %s", rank_name(), name);
    +  assert(_rank >= static_cast(0) && _rank <= safepoint, "Bad lock rank %d outside [0, %d]: %s",
    +         static_cast(rank), static_cast(safepoint), name);
     
       // The allow_vm_block also includes allowing other non-Java threads to block or
       // allowing Java threads to block in native.
    @@ -324,25 +325,33 @@ static const char* _rank_names[] = { "event", "service", "stackwatermark", "tty"
     
     static const int _num_ranks = 7;
     
    -static const char* rank_name_internal(Mutex::Rank r) {
    +static void print_rank_name_internal(outputStream* st, Mutex::Rank r) {
       // Find closest rank and print out the name
    -  stringStream st;
       for (int i = 0; i < _num_ranks; i++) {
         if (r == _ranks[i]) {
    -      return _rank_names[i];
    +      st->print("%s", _rank_names[i]);
         } else if (r  > _ranks[i] && (i < _num_ranks-1 && r < _ranks[i+1])) {
           int delta = static_cast(_ranks[i+1]) - static_cast(r);
    -      st.print("%s-%d", _rank_names[i+1], delta);
    -      return st.as_string();
    +      st->print("%s-%d", _rank_names[i+1], delta);
         }
       }
    -  return "fail";
    +}
    +
    +// Requires caller to have ResourceMark.
    +static const char* rank_name_internal(Mutex::Rank r) {
    +  stringStream st;
    +  print_rank_name_internal(&st, r);
    +  return st.as_string();
     }
     
     const char* Mutex::rank_name() const {
       return rank_name_internal(_rank);
     }
     
    +// Does not require caller to have ResourceMark.
    +void Mutex::print_rank_name(outputStream* st) const {
    +  print_rank_name_internal(st, _rank);
    +}
     
     void Mutex::assert_no_overlap(Rank orig, Rank adjusted, int adjust) {
       int i = 0;
    @@ -364,7 +373,8 @@ void Mutex::print_on(outputStream* st) const {
       if (_allow_vm_block) {
         st->print("%s", " allow_vm_block");
       }
    -  DEBUG_ONLY(st->print(" %s", rank_name()));
    +  st->print(" ");
    +  DEBUG_ONLY(print_rank_name(st));
       st->cr();
     }
     
    diff --git a/src/hotspot/share/runtime/mutex.hpp b/src/hotspot/share/runtime/mutex.hpp
    index cf2b222d2da..4d30a320cbf 100644
    --- a/src/hotspot/share/runtime/mutex.hpp
    +++ b/src/hotspot/share/runtime/mutex.hpp
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 1998, 2026, Oracle and/or its affiliates. All rights reserved.
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      *
      * This code is free software; you can redistribute it and/or modify it
    @@ -130,9 +130,11 @@ class Mutex : public CHeapObj {
         return _skip_rank_check;
       }
     
    +  const char* rank_name() const;
    +  void print_rank_name(outputStream* st) const;
    +
      public:
       Rank   rank() const          { return _rank; }
    -  const char*  rank_name() const;
       Mutex* next()  const         { return _next; }
     #endif // ASSERT
     
    diff --git a/test/hotspot/gtest/runtime/test_mutex.cpp b/test/hotspot/gtest/runtime/test_mutex.cpp
    index 2ed7b1b3a34..64b7a5207d7 100644
    --- a/test/hotspot/gtest/runtime/test_mutex.cpp
    +++ b/test/hotspot/gtest/runtime/test_mutex.cpp
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved.
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      *
      * This code is free software; you can redistribute it and/or modify it
    @@ -323,11 +323,12 @@ TEST_VM_ASSERT_MSG(MutexSafepoint, possible_safepoint_lock,
         ".* Possible safepoint reached by thread that does not allow it") {
       JavaThread* thread = JavaThread::current();
       ThreadInVMfromNative in_native(thread);
    -  MutexLocker ml(new Mutex(Mutex::nosafepoint, "SpecialTest_lock"),
    +  MutexLocker ml(new Mutex(Mutex::nosafepoint-2, "SpecialTest_lock"),
                        Mutex::_no_safepoint_check_flag);
       thread->print_thread_state_on(tty);
       // If the lock above succeeds, try to safepoint to test the NSV implied with this nosafepoint lock.
       ThreadBlockInVM tbivm(thread);
       thread->print_thread_state_on(tty);
     }
    +
     #endif // ASSERT
    
    From 0a8dbed7ef4d12b09f223e81a9a658ddaeca931c Mon Sep 17 00:00:00 2001
    From: Artur Barashev 
    Date: Fri, 17 Apr 2026 17:02:59 +0000
    Subject: [PATCH 336/359] 8370656: Re-examine use of InterruptedIOException in
     sun.security.ssl code
    
    Reviewed-by: weijun, alanb
    ---
     .../sun/security/ssl/SSLSocketImpl.java       | 67 +++++++------------
     .../security/ssl/SSLSocketInputRecord.java    |  6 +-
     .../sun/security/ssl/SSLTransport.java        |  6 +-
     .../ssl/SSLSession/TestEnabledProtocols.java  | 10 ++-
     4 files changed, 35 insertions(+), 54 deletions(-)
    
    diff --git a/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java b/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java
    index f603cc22949..cef2f43526a 100644
    --- a/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java
    +++ b/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 1996, 2026, Oracle and/or its affiliates. All rights reserved.
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      *
      * This code is free software; you can redistribute it and/or modify it
    @@ -28,13 +28,13 @@ package sun.security.ssl;
     import java.io.EOFException;
     import java.io.IOException;
     import java.io.InputStream;
    -import java.io.InterruptedIOException;
     import java.io.OutputStream;
     import java.net.InetAddress;
     import java.net.InetSocketAddress;
     import java.net.Socket;
     import java.net.SocketAddress;
     import java.net.SocketException;
    +import java.net.SocketTimeoutException;
     import java.nio.ByteBuffer;
     import java.util.List;
     import java.util.concurrent.TimeUnit;
    @@ -77,10 +77,10 @@ public final class SSLSocketImpl
         /**
          * ERROR HANDLING GUIDELINES
          * (which exceptions to throw and catch and which not to throw and catch)
    -     *
    +     * 

    * - if there is an IOException (SocketException) when accessing the * underlying Socket, pass it through - * + *

    * - do not throw IOExceptions, throw SSLExceptions (or a subclass) */ @@ -454,12 +454,12 @@ public final class SSLSocketImpl if (!conContext.isNegotiated) { readHandshakeRecord(); } - } catch (InterruptedIOException iioe) { + } catch (SocketTimeoutException e) { if(resumable){ - handleException(iioe); + handleException(e); } else{ throw conContext.fatal(Alert.HANDSHAKE_FAILURE, - "Couldn't kickstart handshaking", iioe); + "Couldn't kickstart handshaking", e); } } catch (SocketException se) { handleException(se); @@ -1427,7 +1427,7 @@ public final class SSLSocketImpl return 0; } } catch (SSLException | - InterruptedIOException | SocketException se) { + SocketTimeoutException | SocketException se) { // Don't change exception in case of timeouts or interrupts // or SocketException. throw se; @@ -1486,7 +1486,7 @@ public final class SSLSocketImpl return buffer; } } catch (SSLException | - InterruptedIOException | SocketException se) { + SocketTimeoutException | SocketException se) { // Don't change exception in case of timeouts or interrupts // or SocketException. throw se; @@ -1677,40 +1677,23 @@ public final class SSLSocketImpl SSLLogger.warning("handling exception", cause); } - // Don't close the Socket in case of timeouts or interrupts. - if (cause instanceof InterruptedIOException) { - throw (IOException)cause; - } - - // need to perform error shutdown - boolean isSSLException = (cause instanceof SSLException); - Alert alert; - if (isSSLException) { - if (cause instanceof SSLHandshakeException) { - alert = Alert.HANDSHAKE_FAILURE; - } else { - alert = Alert.UNEXPECTED_MESSAGE; + throw switch (cause) { + // Don't close the Socket in case of timeouts. + case SocketTimeoutException ste -> ste; + // Send TLS alert with "fatal", then throw the socket exception. + case SocketException se -> { + try { + throw conContext.fatal(Alert.UNEXPECTED_MESSAGE, se); + } catch (Exception _) { + } + yield se; } - } else { - if (cause instanceof IOException) { - alert = Alert.UNEXPECTED_MESSAGE; - } else { - // RuntimeException - alert = Alert.INTERNAL_ERROR; - } - } - - if (cause instanceof SocketException) { - try { - throw conContext.fatal(alert, cause); - } catch (Exception e) { - // Just delivering the fatal alert, re-throw the socket exception instead. - } - - throw (SocketException)cause; - } - - throw conContext.fatal(alert, cause); + case SSLHandshakeException sslhe -> + conContext.fatal(Alert.HANDSHAKE_FAILURE, sslhe); + case IOException ioe -> + conContext.fatal(Alert.UNEXPECTED_MESSAGE, ioe); + default -> conContext.fatal(Alert.INTERNAL_ERROR, cause); + }; } private Plaintext handleEOF(EOFException eofe) throws IOException { diff --git a/src/java.base/share/classes/sun/security/ssl/SSLSocketInputRecord.java b/src/java.base/share/classes/sun/security/ssl/SSLSocketInputRecord.java index fd9c4b171e7..fc3d9733150 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLSocketInputRecord.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLSocketInputRecord.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2020, Azul Systems, Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -27,10 +27,10 @@ package sun.security.ssl; import java.io.EOFException; -import java.io.InterruptedIOException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.net.SocketTimeoutException; import java.nio.ByteBuffer; import java.security.GeneralSecurityException; import java.util.ArrayList; @@ -180,7 +180,7 @@ final class SSLSocketInputRecord extends InputRecord implements SSLRecord { if (plaintext == null) { plaintext = decodeInputRecord(); } - } catch(InterruptedIOException e) { + } catch (SocketTimeoutException e) { // do not clean header and recordBody in case of Socket Timeout cleanInBuffer = false; throw e; diff --git a/src/java.base/share/classes/sun/security/ssl/SSLTransport.java b/src/java.base/share/classes/sun/security/ssl/SSLTransport.java index 50bff1e6d21..02551b4a8c1 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLTransport.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLTransport.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * 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 sun.security.ssl; import java.io.EOFException; import java.io.IOException; -import java.io.InterruptedIOException; import java.net.SocketException; +import java.net.SocketTimeoutException; import java.nio.ByteBuffer; import javax.crypto.AEADBadTagException; import javax.crypto.BadPaddingException; @@ -138,7 +138,7 @@ interface SSLTransport { } catch (EOFException eofe) { // rethrow EOFException, the call will handle it if needed. throw eofe; - } catch (InterruptedIOException | SocketException se) { + } catch (SocketTimeoutException | SocketException se) { // don't close the Socket in case of timeouts or interrupts or SocketException. throw se; } catch (IOException ioe) { diff --git a/test/jdk/javax/net/ssl/SSLSession/TestEnabledProtocols.java b/test/jdk/javax/net/ssl/SSLSession/TestEnabledProtocols.java index 4e56a9a655b..070991586f3 100644 --- a/test/jdk/javax/net/ssl/SSLSession/TestEnabledProtocols.java +++ b/test/jdk/javax/net/ssl/SSLSession/TestEnabledProtocols.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * 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,10 @@ import java.io.IOException; import java.io.InputStream; -import java.io.InterruptedIOException; import java.io.OutputStream; import java.net.InetAddress; import java.net.SocketException; +import java.net.SocketTimeoutException; import java.security.Security; import java.util.Arrays; @@ -88,11 +88,9 @@ public class TestEnabledProtocols extends SSLSocketTemplate { // log it for debugging System.out.println("Server SSLHandshakeException:"); se.printStackTrace(System.out); - } catch (InterruptedIOException ioe) { - // must have been interrupted, no harm - } catch (SSLException | SocketException se) { + } catch (SocketTimeoutException | SSLException | SocketException se) { // The client side may have closed the socket. - System.out.println("Server SSLException:"); + System.out.println("Server exception:"); se.printStackTrace(System.out); } catch (Exception e) { System.out.println("Server exception:"); From 2ce2d5886bdccabe4f51d79dd92751933def905a Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Fri, 17 Apr 2026 18:17:52 +0000 Subject: [PATCH 337/359] 8074292: nsk/jdb/kill/kill001: generateOopMap.cpp assert(bb->is_reachable()) failed Co-authored-by: Tom Rodriguez Reviewed-by: sspitsyn, pchilanomate, dlong, never --- .../share/interpreter/interpreterRuntime.cpp | 14 +++ .../share/interpreter/interpreterRuntime.hpp | 4 +- src/hotspot/share/interpreter/oopMapCache.cpp | 15 ++- src/hotspot/share/oops/generateOopMap.cpp | 80 ++++++------- src/hotspot/share/oops/generateOopMap.hpp | 7 +- src/hotspot/share/runtime/globals.hpp | 3 + .../share/runtime/interfaceSupport.cpp | 7 +- .../exceptions/TestAccessErrorInCatch.java | 3 +- .../nsk/jdb/kill/kill003/kill003.java | 106 ++++++++++++++++++ .../nsk/jdb/kill/kill003/kill003a.java | 38 +++++++ 10 files changed, 228 insertions(+), 49 deletions(-) create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/jdb/kill/kill003/kill003.java create mode 100644 test/hotspot/jtreg/vmTestbase/nsk/jdb/kill/kill003/kill003a.java diff --git a/src/hotspot/share/interpreter/interpreterRuntime.cpp b/src/hotspot/share/interpreter/interpreterRuntime.cpp index e7b35b121a2..cd0a062ebc8 100644 --- a/src/hotspot/share/interpreter/interpreterRuntime.cpp +++ b/src/hotspot/share/interpreter/interpreterRuntime.cpp @@ -36,6 +36,7 @@ #include "interpreter/interpreter.hpp" #include "interpreter/interpreterRuntime.hpp" #include "interpreter/linkResolver.hpp" +#include "interpreter/oopMapCache.hpp" #include "interpreter/templateTable.hpp" #include "jvm_io.h" #include "logging/log.hpp" @@ -1527,4 +1528,17 @@ bool InterpreterRuntime::is_preemptable_call(address entry_point) { entry_point == CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_from_cache) || entry_point == CAST_FROM_FN_PTR(address, InterpreterRuntime::_new); } + +void InterpreterRuntime::generate_oop_map_alot() { + JavaThread* current = JavaThread::current(); + LastFrameAccessor last_frame(current); + if (last_frame.is_interpreted_frame()) { + ResourceMark rm(current); + InterpreterOopMap mask; + methodHandle mh(current, last_frame.method()); + int bci = last_frame.bci(); + log_info(generateoopmap)("Generating oopmap for method %s at bci %d", mh->name_and_sig_as_C_string(), bci); + OopMapCache::compute_one_oop_map(mh, bci, &mask); + } +} #endif // ASSERT diff --git a/src/hotspot/share/interpreter/interpreterRuntime.hpp b/src/hotspot/share/interpreter/interpreterRuntime.hpp index 70ceeb0b2af..3228027fa93 100644 --- a/src/hotspot/share/interpreter/interpreterRuntime.hpp +++ b/src/hotspot/share/interpreter/interpreterRuntime.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -173,6 +173,8 @@ private: // Virtual Thread Preemption DEBUG_ONLY(static bool is_preemptable_call(address entry_point);) + + DEBUG_ONLY(static void generate_oop_map_alot();) }; diff --git a/src/hotspot/share/interpreter/oopMapCache.cpp b/src/hotspot/share/interpreter/oopMapCache.cpp index 5a1ad7b7883..af45f7f9bed 100644 --- a/src/hotspot/share/interpreter/oopMapCache.cpp +++ b/src/hotspot/share/interpreter/oopMapCache.cpp @@ -92,11 +92,8 @@ class OopMapForCacheEntry: public GenerateOopMap { }; -OopMapForCacheEntry::OopMapForCacheEntry(const methodHandle& method, int bci, OopMapCacheEntry* entry) : GenerateOopMap(method) { - _bci = bci; - _entry = entry; - _stack_top = -1; -} +OopMapForCacheEntry::OopMapForCacheEntry(const methodHandle& method, int bci, OopMapCacheEntry* entry) : + GenerateOopMap(method, /*all_exception_edges*/ true), _entry(entry), _bci(bci), _stack_top(-1) { } bool OopMapForCacheEntry::compute_map(Thread* current) { @@ -107,6 +104,11 @@ bool OopMapForCacheEntry::compute_map(Thread* current) { } else { ResourceMark rm; if (!GenerateOopMap::compute_map(current)) { + // If compute_map fails, print the exception message, which is generated if + // this is a JavaThread, otherwise compute_map calls fatal so we don't get here. + if (exception() != nullptr) { + exception()->print(); + } fatal("Unrecoverable verification or out-of-memory error"); return false; } @@ -315,6 +317,9 @@ void OopMapCacheEntry::fill(const methodHandle& method, int bci) { } else { OopMapForCacheEntry gen(method, bci, this); if (!gen.compute_map(Thread::current())) { + if (gen.exception() != nullptr) { + gen.exception()->print(); + } fatal("Unrecoverable verification or out-of-memory error"); } } diff --git a/src/hotspot/share/oops/generateOopMap.cpp b/src/hotspot/share/oops/generateOopMap.cpp index 09912aeaf63..56f3e7e0325 100644 --- a/src/hotspot/share/oops/generateOopMap.cpp +++ b/src/hotspot/share/oops/generateOopMap.cpp @@ -1168,42 +1168,46 @@ void GenerateOopMap::interp_bb(BasicBlock *bb) { } void GenerateOopMap::do_exception_edge(BytecodeStream* itr) { - // Only check exception edge, if bytecode can trap - if (!Bytecodes::can_trap(itr->code())) return; - switch (itr->code()) { - case Bytecodes::_aload_0: - // These bytecodes can trap for rewriting. We need to assume that - // they do not throw exceptions to make the monitor analysis work. - return; - case Bytecodes::_ireturn: - case Bytecodes::_lreturn: - case Bytecodes::_freturn: - case Bytecodes::_dreturn: - case Bytecodes::_areturn: - case Bytecodes::_return: - // If the monitor stack height is not zero when we leave the method, - // then we are either exiting with a non-empty stack or we have - // found monitor trouble earlier in our analysis. In either case, - // assume an exception could be taken here. - if (_monitor_top == 0) { + // Only check exception edge, if bytecode can trap or if async exceptions can be thrown + // from any bytecode in the interpreter when single stepping. + if (!_all_exception_edges) { + if (!Bytecodes::can_trap(itr->code())) return; + switch (itr->code()) { + case Bytecodes::_aload_0: + // These bytecodes can trap for rewriting. We need to assume that + // they do not throw exceptions to make the monitor analysis work. return; - } - break; - case Bytecodes::_monitorexit: - // If the monitor stack height is bad_monitors, then we have detected a - // monitor matching problem earlier in the analysis. If the - // monitor stack height is 0, we are about to pop a monitor - // off of an empty stack. In either case, the bytecode - // could throw an exception. - if (_monitor_top != bad_monitors && _monitor_top != 0) { - return; - } - break; + case Bytecodes::_ireturn: + case Bytecodes::_lreturn: + case Bytecodes::_freturn: + case Bytecodes::_dreturn: + case Bytecodes::_areturn: + case Bytecodes::_return: + // If the monitor stack height is not zero when we leave the method, + // then we are either exiting with a non-empty stack or we have + // found monitor trouble earlier in our analysis. In either case, + // assume an exception could be taken here. + if (_monitor_top == 0) { + return; + } + break; - default: - break; + case Bytecodes::_monitorexit: + // If the monitor stack height is bad_monitors, then we have detected a + // monitor matching problem earlier in the analysis. If the + // monitor stack height is 0, we are about to pop a monitor + // off of an empty stack. In either case, the bytecode + // could throw an exception. + if (_monitor_top != bad_monitors && _monitor_top != 0) { + return; + } + break; + + default: + break; + } } if (_has_exceptions) { @@ -2055,12 +2059,12 @@ void GenerateOopMap::print_time() { // // ============ Main Entry Point =========== // -GenerateOopMap::GenerateOopMap(const methodHandle& method) { +GenerateOopMap::GenerateOopMap(const methodHandle& method, bool all_exception_edges) : // We have to initialize all variables here, that can be queried directly - _method = method; - _max_locals=0; - _init_vars = nullptr; -} + _method(method), + _max_locals(0), + _all_exception_edges(all_exception_edges), + _init_vars(nullptr) {} bool GenerateOopMap::compute_map(Thread* current) { #ifndef PRODUCT @@ -2187,7 +2191,7 @@ void GenerateOopMap::result_for_basicblock(int bci) { // Find basicblock and report results BasicBlock* bb = get_basic_block_containing(bci); guarantee(bb != nullptr, "no basic block for bci"); - assert(bb->is_reachable(), "getting result from unreachable basicblock %d", bci); + assert(bb->is_reachable(), "getting result from unreachable basicblock at bci %d", bci); bb->set_changed(true); interp_bb(bb); } diff --git a/src/hotspot/share/oops/generateOopMap.hpp b/src/hotspot/share/oops/generateOopMap.hpp index 783e295f08a..f0fdfeda57f 100644 --- a/src/hotspot/share/oops/generateOopMap.hpp +++ b/src/hotspot/share/oops/generateOopMap.hpp @@ -307,6 +307,7 @@ class GenerateOopMap { bool _did_relocation; // was relocation necessary bool _monitor_safe; // The monitors in this method have been determined // to be safe. + bool _all_exception_edges; // All bytecodes can reach containing exception handler. // Working Cell type state int _state_len; // Size of states @@ -455,7 +456,7 @@ class GenerateOopMap { friend class RelocCallback; public: - GenerateOopMap(const methodHandle& method); + GenerateOopMap(const methodHandle& method, bool all_exception_edges); // Compute the map - returns true on success and false on error. bool compute_map(Thread* current); @@ -516,7 +517,7 @@ class ResolveOopMapConflicts: public GenerateOopMap { #endif public: - ResolveOopMapConflicts(const methodHandle& method) : GenerateOopMap(method) { } + ResolveOopMapConflicts(const methodHandle& method) : GenerateOopMap(method, true) { } methodHandle do_potential_rewrite(TRAPS); }; @@ -535,7 +536,7 @@ class GeneratePairingInfo: public GenerateOopMap { CellTypeState* stack, int stack_top) {} public: - GeneratePairingInfo(const methodHandle& method) : GenerateOopMap(method) {}; + GeneratePairingInfo(const methodHandle& method) : GenerateOopMap(method, false) {}; // Call compute_map() to generate info. }; diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp index ac1ddec7cbc..9d38a44cbd5 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -871,6 +871,9 @@ const int ObjectAlignmentInBytes = 8; develop(bool, TimeOopMap, false, \ "Time calls to GenerateOopMap::compute_map() in sum") \ \ + develop(bool, GenerateOopMapALot, false, \ + "Generate interpreter oopmaps at all safepoints") \ + \ develop(bool, TraceFinalizerRegistration, false, \ "Trace registration of final references") \ \ diff --git a/src/hotspot/share/runtime/interfaceSupport.cpp b/src/hotspot/share/runtime/interfaceSupport.cpp index 11a7d9fd41f..6ccf63b4c5e 100644 --- a/src/hotspot/share/runtime/interfaceSupport.cpp +++ b/src/hotspot/share/runtime/interfaceSupport.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ */ #include "gc/shared/collectedHeap.inline.hpp" +#include "interpreter/interpreterRuntime.hpp" #include "logging/log.hpp" #include "memory/resourceArea.hpp" #include "memory/universe.hpp" @@ -65,6 +66,10 @@ VMEntryWrapper::~VMEntryWrapper() { if (VerifyStack) { InterfaceSupport::verify_stack(); } + // Verify interpreter oopmap generation + if (GenerateOopMapALot) { + InterpreterRuntime::generate_oop_map_alot(); + } } VMNativeEntryWrapper::VMNativeEntryWrapper() { diff --git a/test/hotspot/jtreg/compiler/exceptions/TestAccessErrorInCatch.java b/test/hotspot/jtreg/compiler/exceptions/TestAccessErrorInCatch.java index fa81fa93f11..89dfae5c4da 100644 --- a/test/hotspot/jtreg/compiler/exceptions/TestAccessErrorInCatch.java +++ b/test/hotspot/jtreg/compiler/exceptions/TestAccessErrorInCatch.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ * -XX:+IgnoreUnrecognizedVMOptions -XX:+VerifyStack * -XX:TieredStopAtLevel=3 * TestAccessErrorInCatch + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+GenerateOopMapALot TestAccessErrorInCatch */ import java.lang.invoke.MethodHandle; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/kill/kill003/kill003.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/kill/kill003/kill003.java new file mode 100644 index 00000000000..840e8def8bc --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/kill/kill003/kill003.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8074292 + * @summary Reproduce the bb->is_reachable() assert with GetSetLocals call after async exception. + * @library /vmTestbase + * /test/lib + * @compile -g kill003a.java + * @run driver + * nsk.jdb.kill.kill003.kill003 + * -arch=${os.family}-${os.simpleArch} + * -waittime=5 + * -verbose + * -debugee.vmkind=java + * -transport.address=dynamic + * -jdb=${test.jdk}/bin/jdb + * -java.options="${test.vm.opts} ${test.java.opts}" + * -workdir=. + * -debugee.vmkeys="${test.vm.opts} ${test.java.opts}" + */ + +package nsk.jdb.kill.kill003; + +import nsk.share.*; +import nsk.share.jdb.*; + +import java.io.*; +import java.util.*; + +public class kill003 extends JdbTest { + + public static void main (String argv[]) { + debuggeeClass = DEBUGGEE_CLASS; + firstBreak = FIRST_BREAK; + new kill003().runTest(argv); + } + + static final String PACKAGE_NAME = "nsk.jdb.kill.kill003"; + static final String TEST_CLASS = PACKAGE_NAME + ".kill003"; + static final String DEBUGGEE_CLASS = TEST_CLASS + "a"; + static final String FIRST_BREAK = DEBUGGEE_CLASS + ".main"; + static final String MYTHREAD = "MyThread"; + static final String DEBUGGEE_THREAD = PACKAGE_NAME + "." + MYTHREAD; + static final String DEBUGGEE_EXCEPTION = DEBUGGEE_CLASS + ".exception"; + + protected void runCases() { + String[] reply; + String[] threads; + + // At this point we are at the breakpoint triggered by the firstBreak in main + // after creating all the threads. Get the list of debuggee threads. + threads = jdb.getThreadIdsByName("main"); + + // Stopped at kill.main, so step into synchronized block + reply = jdb.receiveReplyFor(JdbCommand.next); + + if (threads.length != 1) { + log.complain("jdb should report " + 1 + " instance of " + DEBUGGEE_THREAD); + log.complain("Found: " + threads.length); + success = false; + } + + // Execution is at a bytecode that is not expected to handle an async exception. Throw one here + // to make sure it gets handled without crashing. The exception will be delivered at the next + // bytecode that can handle the async exception. + reply = jdb.receiveReplyForWithMessageWait(JdbCommand.kill + threads[0] + " " + DEBUGGEE_EXCEPTION, + "killed"); + + // Continue the debuggee - the async exception will be delivered to the debuggee. + reply = jdb.receiveReplyFor(JdbCommand.cont); + + // Ask the debuggee for its local variables at the bytecode where the async exception was delivered, which + // should be reachable. + reply = jdb.receiveReplyForWithMessageWait(JdbCommand.locals, "Local variables"); + + if (jdb.terminated()) { + throw new Failure("Debuggee exited"); + } + + // The lack of exception handler in the debuggee should cause it to exit when continued. + jdb.contToExit(1); + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/kill/kill003/kill003a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/kill/kill003/kill003a.java new file mode 100644 index 00000000000..1e72e02a560 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/kill/kill003/kill003a.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 nsk.jdb.kill.kill003; + +import nsk.share.jdb.*; + +/* This is debuggee application */ +public class kill003a { + static NullPointerException exception = new NullPointerException(); + + public static void main(String args[]) { + synchronized (args) { + } + System.out.println("done"); + System.exit(JdbTest.JCK_STATUS_BASE); + } +} From e95beacb4c2655865f8e8b081ba5137ce9878b82 Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Fri, 17 Apr 2026 18:30:56 +0000 Subject: [PATCH 338/359] 8382146: jdk/jfr/event/compiler/TestCodeCacheFull.java fails when C2 is disabled Reviewed-by: chagedorn --- .../jfr/event/compiler/TestCodeCacheFull.java | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/test/jdk/jdk/jfr/event/compiler/TestCodeCacheFull.java b/test/jdk/jdk/jfr/event/compiler/TestCodeCacheFull.java index 12c9d6c40fa..266eb73a656 100644 --- a/test/jdk/jdk/jfr/event/compiler/TestCodeCacheFull.java +++ b/test/jdk/jdk/jfr/event/compiler/TestCodeCacheFull.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,7 @@ import jdk.test.whitebox.WhiteBox; import jdk.test.whitebox.code.BlobType; /** - * @test TestCodeCacheFull + * @test id=Default * @requires vm.hasJFR * @requires vm.opt.UseCodeCacheFlushing == null | vm.opt.UseCodeCacheFlushing == true * @@ -50,6 +50,20 @@ import jdk.test.whitebox.code.BlobType; * @run main/othervm -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:-SegmentedCodeCache jdk.jfr.event.compiler.TestCodeCacheFull + */ + +/** + * @test id=HotCode + * @requires vm.hasJFR + * @requires vm.opt.UseCodeCacheFlushing == null | vm.opt.UseCodeCacheFlushing == true + * @requires vm.compiler2.enabled + * + * @library /test/lib + * @modules jdk.jfr + * jdk.management.jfr + * @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 * -XX:+TieredCompilation -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=8M jdk.jfr.event.compiler.TestCodeCacheFull From 2325c3649dd360043f8434d96dd2892c13ba0141 Mon Sep 17 00:00:00 2001 From: Saint Wesonga Date: Fri, 17 Apr 2026 19:55:20 +0000 Subject: [PATCH 339/359] 8378891: Problemlist TestStaticCallStub on Windows AArch64 Reviewed-by: mchevalier, chagedorn --- test/hotspot/jtreg/ProblemList.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index b4f9efff830..202570d6486 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -79,7 +79,7 @@ compiler/codecache/CodeCacheFullCountTest.java 8332954 generic-all compiler/interpreter/Test6833129.java 8335266 generic-i586 compiler/intrinsics/TestReturnOopSetForJFRWriteCheckpoint.java 8286300 linux-s390x -compiler/c2/aarch64/TestStaticCallStub.java 8359963 linux-aarch64,macosx-aarch64 +compiler/c2/aarch64/TestStaticCallStub.java 8359963 generic-aarch64 compiler/unsafe/AlignmentGapAccess.java 8373487 generic-all From 804ecc14dcc0465f9cbbfe38608bd989a0df84fd Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Fri, 17 Apr 2026 20:01:09 +0000 Subject: [PATCH 340/359] 8382436: Build failures after JDK-8326205 Reviewed-by: kvn --- src/hotspot/share/runtime/hotCodeCollector.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hotspot/share/runtime/hotCodeCollector.cpp b/src/hotspot/share/runtime/hotCodeCollector.cpp index 643cf3a8bbb..6bdeee011ce 100644 --- a/src/hotspot/share/runtime/hotCodeCollector.cpp +++ b/src/hotspot/share/runtime/hotCodeCollector.cpp @@ -29,6 +29,7 @@ #include "compiler/compilerDefinitions.inline.hpp" #include "logging/log.hpp" #include "memory/resourceArea.hpp" +#include "oops/method.inline.hpp" #include "runtime/hotCodeCollector.hpp" #include "runtime/hotCodeSampler.hpp" #include "runtime/java.hpp" From 0dd0108c1a7b3658df536adbc2bd68fa5167539d Mon Sep 17 00:00:00 2001 From: Jeremy Wood Date: Fri, 17 Apr 2026 20:53:42 +0000 Subject: [PATCH 341/359] 8377936: VoiceOver Reads Button Incorrectly Reviewed-by: prr, kizune --- .../classes/sun/lwawt/macosx/CAccessible.java | 22 +--- .../8377936/VoiceOverNamesAndStates.java | 107 ++++++++++++++++++ 2 files changed, 112 insertions(+), 17 deletions(-) create mode 100644 test/jdk/javax/accessibility/8377936/VoiceOverNamesAndStates.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 5be7f70b981..4315abe6197 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, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2026, Oracle and/or its affiliates. All rights reserved. * 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,10 +188,6 @@ final class CAccessible extends CFRetainedResource implements Accessible { // Do send check box state changes to native side if (thisRole == AccessibleRole.CHECK_BOX) { - if (!Objects.equals(newValue, oldValue)) { - valueChanged(ptr); - } - // Notify native side to handle check box style menuitem if (parentRole == AccessibleRole.POPUP_MENU && newValue != null && ((AccessibleState)newValue) == AccessibleState.FOCUSED) { @@ -201,23 +197,12 @@ final class CAccessible extends CFRetainedResource implements Accessible { // Do send radio button state changes to native side if (thisRole == AccessibleRole.RADIO_BUTTON) { - if (newValue != null && !newValue.equals(oldValue)) { - valueChanged(ptr); - } - // Notify native side to handle radio button style menuitem if (parentRole == AccessibleRole.POPUP_MENU && newValue != null && ((AccessibleState)newValue) == AccessibleState.FOCUSED) { menuItemSelected(ptr); } } - - // Do send toggle button state changes to native side - if (thisRole == AccessibleRole.TOGGLE_BUTTON) { - if (!Objects.equals(newValue, oldValue)) { - valueChanged(ptr); - } - } } else if (name.equals(ACCESSIBLE_NAME_PROPERTY)) { //for now trigger only for JTabbedPane. if (e.getSource() instanceof JTabbedPane) { @@ -227,7 +212,10 @@ final class CAccessible extends CFRetainedResource implements Accessible { AccessibleRole thisRole = accessible.getAccessibleContext() .getAccessibleRole(); if (thisRole == AccessibleRole.SLIDER || - thisRole == AccessibleRole.PROGRESS_BAR) { + thisRole == AccessibleRole.PROGRESS_BAR || + thisRole == AccessibleRole.CHECK_BOX || + thisRole == AccessibleRole.RADIO_BUTTON || + thisRole == AccessibleRole.TOGGLE_BUTTON ) { valueChanged(ptr); } } diff --git a/test/jdk/javax/accessibility/8377936/VoiceOverNamesAndStates.java b/test/jdk/javax/accessibility/8377936/VoiceOverNamesAndStates.java new file mode 100644 index 00000000000..9df68cf0ca0 --- /dev/null +++ b/test/jdk/javax/accessibility/8377936/VoiceOverNamesAndStates.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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.FlowLayout; +import javax.swing.AbstractButton; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JFrame; + +/* + * @test + * @key headful + * @bug 8377936 + * @summary manual test for VoiceOver reading button names and states + * @requires os.family == "mac" + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual VoiceOverNamesAndStates + */ + +public class VoiceOverNamesAndStates { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + INSTRUCTIONS: + + Part A: + 1. Open VoiceOver + 2. Move the VoiceOver cursor to the leftmost button. + 3. Press CTRL + ALT + RIGHT to move to the rightmost button. + + Expected behavior: VoiceOver should announce rightmost button. + (It should NOT announce the leftmost button.) + + Part B (Regression for 8061359, 8348936, 8309733): + 1. Open VoiceOver + 2. Move the VoiceOver cursor to the leftmost button. + 3. Press SPACE to trigger Swing's default KeyListeners. + 4. Repeat step 3 to untoggle button. + 5. Press CTRL + ALT + SPACE to trigger VO's listeners. + 6. Repeat step 5 to untoggle button + + Expected behavior: VoiceOver should announce the change in the + button state in steps 3-6. (When you use VoiceOver to toggle + the button you should hear a small chirp as the button + toggles.) + + Part C (Regression for 8345728, 8283400): + 1. Turn on Screen Magnifier + (See System Settings -> Accessibility -> Hover Text) + 2. Press CMD key and hover mouse over leftmost button + 3. Click the button + 4. Release the CMD key + + Expected behavior: both the button and the "hover text" window + repaint to show a selected button. + + 5. Repeat steps 2-4 to untoggle the button + + Expected behavior: both the button and the "hover text" window + repaint to show a deselected button. + + """; + + PassFailJFrame.builder() + .title("VoiceOverNamesAndStates Instruction") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(VoiceOverNamesAndStates::createUI) + .build() + .awaitAndCheck(); + } + + private static JFrame createUI() { + JFrame f = new JFrame(); + + f.getContentPane().setLayout(new FlowLayout()); + + AbstractButton button1 = new JCheckBox("chess"); + AbstractButton button2 = new JButton("backgammon"); + + f.getContentPane().add(button1); + f.getContentPane().add(button2); + f.pack(); + f.setVisible(true); + return f; + } +} From d71f070ce66081013eff2fb91d9e98403312903e Mon Sep 17 00:00:00 2001 From: Archie Cobbs Date: Sun, 19 Apr 2026 02:08:28 +0000 Subject: [PATCH 342/359] 8382368: Warning that @Deprecated "has no effect" is suppressed by @Deprecated Reviewed-by: liach --- .../com/sun/tools/javac/code/Lint.java | 90 +++++++++++-------- .../tools/javac/resources/compiler.properties | 2 +- .../sun/tools/javac/util/JCDiagnostic.java | 6 +- .../classes/com/sun/tools/javac/util/Log.java | 14 +-- .../javac/warnings/DeprecatedNoEffect.java | 14 +++ .../javac/warnings/DeprecatedNoEffect.out | 3 + 6 files changed, 81 insertions(+), 48 deletions(-) create mode 100644 test/langtools/tools/javac/warnings/DeprecatedNoEffect.java create mode 100644 test/langtools/tools/javac/warnings/DeprecatedNoEffect.out diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java index 773c573c201..776fd544bfb 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2026, Oracle and/or its affiliates. All rights reserved. * 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,11 +37,16 @@ import java.util.Set; import java.util.stream.Stream; import com.sun.tools.javac.main.Option; +import com.sun.tools.javac.util.Assert; import com.sun.tools.javac.util.Context; +import com.sun.tools.javac.util.JCDiagnostic; import com.sun.tools.javac.util.Log; import com.sun.tools.javac.util.Names; import com.sun.tools.javac.util.Options; +import static com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag.DEFAULT_ENABLED; +import static com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag.DEPRECATION_SENSITIVE; + /** * A class for handling -Xlint suboptions and @SuppressWarnings. * @@ -76,35 +81,20 @@ public class Lint { */ public Lint augment(Symbol sym) { EnumSet suppressions = suppressionsFrom(sym); - if (!suppressions.isEmpty()) { + boolean symWithinDeprecated = withinDeprecated || isDeprecatedDeclaration(sym); + if (!suppressions.isEmpty() || symWithinDeprecated != withinDeprecated) { Lint lint = new Lint(this); lint.values.removeAll(suppressions); lint.suppressedValues.addAll(suppressions); + lint.withinDeprecated = symWithinDeprecated; return lint; } return this; } - /** - * Returns a new Lint that has the given LintCategorys enabled. - * @param lc one or more categories to be enabled - */ - public Lint enable(LintCategory... lc) { - Lint l = new Lint(this); - l.values.addAll(Arrays.asList(lc)); - l.suppressedValues.removeAll(Arrays.asList(lc)); - return l; - } - - /** - * Returns a new Lint that has the given LintCategorys suppressed. - * @param lc one or more categories to be suppressed - */ - public Lint suppress(LintCategory... lc) { - Lint l = new Lint(this); - l.values.removeAll(Arrays.asList(lc)); - l.suppressedValues.addAll(Arrays.asList(lc)); - return l; + // Does sym's declaration have a (non-useless) @Deprecated annotation? + public static boolean isDeprecatedDeclaration(Symbol sym) { + return sym.isDeprecated() && sym.isDeprecatableViaAnnotation(); } private final Context context; @@ -115,9 +105,12 @@ public class Lint { private Symtab syms; private Names names; - // Invariant: it's never the case that a category is in both "values" and "suppressedValues" + // Invariants: + // - It's never the case that a category is in both "values" and "suppressedValues" + // - All categories in "suppressedValues" have annotationSuppression = true private EnumSet values; private EnumSet suppressedValues; + private boolean withinDeprecated; private static final Map map = new LinkedHashMap<>(40); @@ -129,7 +122,7 @@ public class Lint { log = Log.instance(context); } - // Instantiate a non-root ("symbol scoped") instance + // Copy constructor - used to instantiate a non-root ("symbol scoped") instances protected Lint(Lint other) { other.initializeRootIfNeeded(); this.context = other.context; @@ -139,6 +132,7 @@ public class Lint { this.names = other.names; this.values = other.values.clone(); this.suppressedValues = other.suppressedValues.clone(); + this.withinDeprecated = other.withinDeprecated; } // Process command line options on demand to allow use of root Lint early during startup @@ -169,7 +163,7 @@ public class Lint { @Override public String toString() { initializeRootIfNeeded(); - return "Lint:[enable" + values + ",suppress" + suppressedValues + "]"; + return "Lint:[enable" + values + ",suppress" + suppressedValues + ",deprecated=" + withinDeprecated + "]"; } /** @@ -443,6 +437,34 @@ public class Lint { public final boolean enabledByDefault; } + /** + * Determine if the given diagnostic should be emitted given the state of this instance. + */ + public boolean shouldEmit(JCDiagnostic diag) { + + // Check category + LintCategory category = diag.getLintCategory(); + if (category == null) + return true; + + // Certain warnings within @Deprecated declarations are automatically suppressed (JLS 9.6.4.6) + if (withinDeprecated && diag.isFlagSet(DEPRECATION_SENSITIVE)) { + Assert.check(diag.isFlagSet(DEFAULT_ENABLED) && category.annotationSuppression); + return false; + } + + // If the warning is not enabled by default, then emit only when its lint category is explicitly enabled + if (!diag.isFlagSet(DEFAULT_ENABLED)) + return isEnabled(category); + + // If the lint category doesn't support @SuppressWarnings, then we just check the -Xlint:category flag + if (!category.annotationSuppression) + return !options.isDisabled(Option.XLINT, category); + + // Check whether the lint category is currently suppressed + return !isSuppressed(category); + } + /** * Checks if a warning category is enabled. A warning category may be enabled * on the command line, or by default, and can be temporarily disabled with @@ -454,10 +476,11 @@ public class Lint { } /** - * Checks is a warning category has been specifically suppressed, by means - * of the SuppressWarnings annotation, or, in the case of the deprecated - * category, whether it has been implicitly suppressed by virtue of the - * current entity being itself deprecated. + * Check if a warning category has been specifically suppressed by means of @SuppressWarnings. + * + *

    + * Always returns false for categories that are not suppressible by the annotation, even + * if they (uselessly) happen to appear in one. */ public boolean isSuppressed(LintCategory lc) { initializeRootIfNeeded(); @@ -468,17 +491,14 @@ public class Lint { * Obtain the set of recognized lint warning categories suppressed at the given symbol's declaration. * *

    - * This set can be non-empty only if the symbol is annotated with either - * @SuppressWarnings or @Deprecated. + * This set can be non-empty only if the symbol is annotated with @SuppressWarnings, and only categories + * for which {@code annotationSuppression} is true are included. * * @param symbol symbol corresponding to a possibly-annotated declaration * @return new warning suppressions applied to sym */ public EnumSet suppressionsFrom(Symbol symbol) { - EnumSet suppressions = suppressionsFrom(symbol.getDeclarationAttributes().stream()); - if (symbol.isDeprecated() && symbol.isDeprecatableViaAnnotation()) - suppressions.add(LintCategory.DEPRECATION); - return suppressions; + return suppressionsFrom(symbol.getDeclarationAttributes().stream()); } // Find the @SuppressWarnings annotation in the given stream and extract the recognized suppressions diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties index 58a5333ce4c..a2bfb9c7201 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties @@ -1960,7 +1960,7 @@ compiler.warn.incubating.modules=\ # 0: symbol, 1: symbol # lint: deprecation -# flags: aggregate, mandatory, default-enabled +# flags: aggregate, mandatory, default-enabled, deprecation-sensitive compiler.warn.has.been.deprecated=\ {0} in {1} has been deprecated diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/JCDiagnostic.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/JCDiagnostic.java index 328183c0cb3..aed42f7b2b2 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/JCDiagnostic.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/JCDiagnostic.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +436,10 @@ public class JCDiagnostic implements Diagnostic { * is not explicitly enabled, as long as it is not explicitly suppressed. */ DEFAULT_ENABLED, + /** Flag for warnings that are automatically suppressed when they occur inside + * a declaration that is itself annotated as @Deprecated. See JLS 9.6.4.6. + */ + DEPRECATION_SENSITIVE, /** Flags mandatory warnings that should pass through a mandatory warning aggregator. */ AGGREGATE, diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Log.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Log.java index b061d2283a0..99f71e87df1 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Log.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Log.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -174,16 +174,8 @@ public class Log extends AbstractLog { } // Apply the lint configuration (if any) and discard the warning if it gets filtered out - if (lint != null) { - LintCategory category = diag.getLintCategory(); - boolean emit = !diag.isFlagSet(DEFAULT_ENABLED) ? // is the warning not enabled by default? - lint.isEnabled(category) : // then emit if the category is enabled - category.annotationSuppression ? // else emit if the category is not suppressed, where - !lint.isSuppressed(category) : // ...suppression happens via @SuppressWarnings - !options.isDisabled(Option.XLINT, category); // ...suppression happens via -Xlint:-category - if (!emit) - return; - } + if (lint != null && !lint.shouldEmit(diag)) + return; // Proceed reportReady(diag); diff --git a/test/langtools/tools/javac/warnings/DeprecatedNoEffect.java b/test/langtools/tools/javac/warnings/DeprecatedNoEffect.java new file mode 100644 index 00000000000..b2c8a10c0ac --- /dev/null +++ b/test/langtools/tools/javac/warnings/DeprecatedNoEffect.java @@ -0,0 +1,14 @@ +/* + * @test /nodynamiccopyright/ + * @bug 8382368 + * @compile/ref=DeprecatedNoEffect.out -Xlint:deprecation -XDrawDiagnostics DeprecatedNoEffect.java + */ +public class DeprecatedNoEffect { + void m1() { + @Deprecated int i1; // there should be a "has no effect" warning here + } + @Deprecated + void m2() { + @Deprecated int i2; // there should be a "has no effect" warning here also + } +} diff --git a/test/langtools/tools/javac/warnings/DeprecatedNoEffect.out b/test/langtools/tools/javac/warnings/DeprecatedNoEffect.out new file mode 100644 index 00000000000..55003e62fb8 --- /dev/null +++ b/test/langtools/tools/javac/warnings/DeprecatedNoEffect.out @@ -0,0 +1,3 @@ +DeprecatedNoEffect.java:8:21: compiler.warn.deprecated.annotation.has.no.effect: kindname.variable +DeprecatedNoEffect.java:12:21: compiler.warn.deprecated.annotation.has.no.effect: kindname.variable +2 warnings From 35b0de3d4d4e8212227af5462fafbd464103f058 Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Sun, 19 Apr 2026 03:10:04 +0000 Subject: [PATCH 343/359] 8382043: Add missing @Override annotations in "javax.print.attribute" package Reviewed-by: dmarkov, azvegint, prr --- .../javax/print/attribute/AttributeSet.java | 4 ++- .../attribute/AttributeSetUtilities.java | 28 ++++++++++++++++++- .../javax/print/attribute/DateTimeSyntax.java | 5 +++- .../print/attribute/DocAttributeSet.java | 4 ++- .../javax/print/attribute/EnumSyntax.java | 5 +++- .../print/attribute/HashAttributeSet.java | 15 +++++++++- .../javax/print/attribute/IntegerSyntax.java | 5 +++- .../print/attribute/PrintJobAttributeSet.java | 4 ++- .../attribute/PrintRequestAttributeSet.java | 4 ++- .../attribute/PrintServiceAttributeSet.java | 4 ++- .../print/attribute/ResolutionSyntax.java | 5 +++- .../print/attribute/SetOfIntegerSyntax.java | 5 +++- .../javax/print/attribute/Size2DSyntax.java | 5 +++- .../javax/print/attribute/TextSyntax.java | 5 +++- .../javax/print/attribute/URISyntax.java | 5 +++- 15 files changed, 88 insertions(+), 15 deletions(-) diff --git a/src/java.desktop/share/classes/javax/print/attribute/AttributeSet.java b/src/java.desktop/share/classes/javax/print/attribute/AttributeSet.java index 58b23569a92..0fd2da05d60 100644 --- a/src/java.desktop/share/classes/javax/print/attribute/AttributeSet.java +++ b/src/java.desktop/share/classes/javax/print/attribute/AttributeSet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +249,7 @@ public interface AttributeSet { * @return {@code true} if the specified object is equal to this attribute * set */ + @Override public boolean equals(Object object); /** @@ -261,5 +262,6 @@ public interface AttributeSet { * * @return the hash code value for this attribute set */ + @Override public int hashCode(); } diff --git a/src/java.desktop/share/classes/javax/print/attribute/AttributeSetUtilities.java b/src/java.desktop/share/classes/javax/print/attribute/AttributeSetUtilities.java index f762eb89925..ea4dcf54f32 100644 --- a/src/java.desktop/share/classes/javax/print/attribute/AttributeSetUtilities.java +++ b/src/java.desktop/share/classes/javax/print/attribute/AttributeSetUtilities.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * 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,54 +101,67 @@ public final class AttributeSetUtilities { attrset = attributeSet; } + @Override public Attribute get(Class key) { return attrset.get(key); } + @Override public boolean add(Attribute attribute) { throw new UnmodifiableSetException(); } + @Override public synchronized boolean remove(Class category) { throw new UnmodifiableSetException(); } + @Override public boolean remove(Attribute attribute) { throw new UnmodifiableSetException(); } + @Override public boolean containsKey(Class category) { return attrset.containsKey(category); } + @Override public boolean containsValue(Attribute attribute) { return attrset.containsValue(attribute); } + @Override public boolean addAll(AttributeSet attributes) { throw new UnmodifiableSetException(); } + @Override public int size() { return attrset.size(); } + @Override public Attribute[] toArray() { return attrset.toArray(); } + @Override public void clear() { throw new UnmodifiableSetException(); } + @Override public boolean isEmpty() { return attrset.isEmpty(); } + @Override public boolean equals(Object o) { return attrset.equals (o); } + @Override public int hashCode() { return attrset.hashCode(); } @@ -366,54 +379,67 @@ public final class AttributeSetUtilities { attrset = attributeSet; } + @Override public synchronized Attribute get(Class category) { return attrset.get(category); } + @Override public synchronized boolean add(Attribute attribute) { return attrset.add(attribute); } + @Override public synchronized boolean remove(Class category) { return attrset.remove(category); } + @Override public synchronized boolean remove(Attribute attribute) { return attrset.remove(attribute); } + @Override public synchronized boolean containsKey(Class category) { return attrset.containsKey(category); } + @Override public synchronized boolean containsValue(Attribute attribute) { return attrset.containsValue(attribute); } + @Override public synchronized boolean addAll(AttributeSet attributes) { return attrset.addAll(attributes); } + @Override public synchronized int size() { return attrset.size(); } + @Override public synchronized Attribute[] toArray() { return attrset.toArray(); } + @Override public synchronized void clear() { attrset.clear(); } + @Override public synchronized boolean isEmpty() { return attrset.isEmpty(); } + @Override public synchronized boolean equals(Object o) { return attrset.equals (o); } + @Override public synchronized int hashCode() { return attrset.hashCode(); } diff --git a/src/java.desktop/share/classes/javax/print/attribute/DateTimeSyntax.java b/src/java.desktop/share/classes/javax/print/attribute/DateTimeSyntax.java index 2f0eafb9f79..154b492de84 100644 --- a/src/java.desktop/share/classes/javax/print/attribute/DateTimeSyntax.java +++ b/src/java.desktop/share/classes/javax/print/attribute/DateTimeSyntax.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -114,6 +114,7 @@ public abstract class DateTimeSyntax implements Serializable, Cloneable { * @return {@code true} if {@code object} is equivalent to this date-time * attribute, {@code false} otherwise */ + @Override public boolean equals(Object object) { return object instanceof DateTimeSyntax other && value.equals(other.value); @@ -123,6 +124,7 @@ public abstract class DateTimeSyntax implements Serializable, Cloneable { * Returns a hash code value for this date-time attribute. The hashcode is * that of this attribute's {@code java.util.Date} value. */ + @Override public int hashCode() { return value.hashCode(); } @@ -132,6 +134,7 @@ public abstract class DateTimeSyntax implements Serializable, Cloneable { * string value is just this attribute's {@code java.util.Date} value * converted to a string. */ + @Override public String toString() { return "" + value; } diff --git a/src/java.desktop/share/classes/javax/print/attribute/DocAttributeSet.java b/src/java.desktop/share/classes/javax/print/attribute/DocAttributeSet.java index 102786da27b..2abd6e6322a 100644 --- a/src/java.desktop/share/classes/javax/print/attribute/DocAttributeSet.java +++ b/src/java.desktop/share/classes/javax/print/attribute/DocAttributeSet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -59,6 +59,7 @@ public interface DocAttributeSet extends AttributeSet { * interface {@link DocAttribute DocAttribute} * @throws NullPointerException if the {@code attribute} is {@code null} */ + @Override public boolean add(Attribute attribute); /** @@ -88,5 +89,6 @@ public interface DocAttributeSet extends AttributeSet { * @throws NullPointerException if the specified set is {@code null} * @see #add(Attribute) */ + @Override public boolean addAll(AttributeSet attributes); } diff --git a/src/java.desktop/share/classes/javax/print/attribute/EnumSyntax.java b/src/java.desktop/share/classes/javax/print/attribute/EnumSyntax.java index fd48a600ee3..4c291999e02 100644 --- a/src/java.desktop/share/classes/javax/print/attribute/EnumSyntax.java +++ b/src/java.desktop/share/classes/javax/print/attribute/EnumSyntax.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -145,6 +145,7 @@ public abstract class EnumSyntax implements Serializable, Cloneable { * semantics of enumeration values is the same object as this enumeration * value. */ + @Override public Object clone() { return this; } @@ -153,6 +154,7 @@ public abstract class EnumSyntax implements Serializable, Cloneable { * Returns a hash code value for this enumeration value. The hash code is * just this enumeration value's integer value. */ + @Override public int hashCode() { return value; } @@ -160,6 +162,7 @@ public abstract class EnumSyntax implements Serializable, Cloneable { /** * Returns a string value corresponding to this enumeration value. */ + @Override public String toString() { String[] theTable = getStringTable(); diff --git a/src/java.desktop/share/classes/javax/print/attribute/HashAttributeSet.java b/src/java.desktop/share/classes/javax/print/attribute/HashAttributeSet.java index 4ad4c8634aa..6800b45a349 100644 --- a/src/java.desktop/share/classes/javax/print/attribute/HashAttributeSet.java +++ b/src/java.desktop/share/classes/javax/print/attribute/HashAttributeSet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +255,7 @@ public class HashAttributeSet implements AttributeSet, Serializable { * {@link Class Class} that implements interface * {@link Attribute Attribute} */ + @Override public Attribute get(Class category) { return attrMap.get(AttributeSetUtilities. verifyAttributeCategory(category, @@ -274,6 +275,7 @@ public class HashAttributeSet implements AttributeSet, Serializable { * @throws UnmodifiableSetException if this attribute set does not support * the {@code add()} operation */ + @Override public boolean add(Attribute attribute) { Object oldAttribute = attrMap.put(attribute.getCategory(), @@ -294,6 +296,7 @@ public class HashAttributeSet implements AttributeSet, Serializable { * @throws UnmodifiableSetException if this attribute set does not support * the {@code remove()} operation */ + @Override public boolean remove(Class category) { return category != null && @@ -314,6 +317,7 @@ public class HashAttributeSet implements AttributeSet, Serializable { * @throws UnmodifiableSetException if this attribute set does not support * the {@code remove()} operation */ + @Override public boolean remove(Attribute attribute) { return attribute != null && @@ -328,6 +332,7 @@ public class HashAttributeSet implements AttributeSet, Serializable { * @return {@code true} if this attribute set contains an attribute value * for the specified category */ + @Override public boolean containsKey(Class category) { return category != null && @@ -344,6 +349,7 @@ public class HashAttributeSet implements AttributeSet, Serializable { * @return {@code true} if this attribute set contains the given attribute * value */ + @Override public boolean containsValue(Attribute attribute) { return attribute != null && attribute.equals(attrMap.get(attribute.getCategory())); @@ -371,6 +377,7 @@ public class HashAttributeSet implements AttributeSet, Serializable { * {@code null}, or the set is {@code null} * @see #add(Attribute) */ + @Override public boolean addAll(AttributeSet attributes) { Attribute []attrs = attributes.toArray(); @@ -392,6 +399,7 @@ public class HashAttributeSet implements AttributeSet, Serializable { * * @return the number of attributes in this attribute set */ + @Override public int size() { return attrMap.size(); } @@ -402,6 +410,7 @@ public class HashAttributeSet implements AttributeSet, Serializable { * @return the attributes contained in this set as an array, zero length if * the {@code AttributeSet} is empty */ + @Override public Attribute[] toArray() { Attribute []attrs = new Attribute[size()]; attrMap.values().toArray(attrs); @@ -414,6 +423,7 @@ public class HashAttributeSet implements AttributeSet, Serializable { * @throws UnmodifiableSetException if this attribute set does not support * the {@code clear()} operation */ + @Override public void clear() { attrMap.clear(); } @@ -423,6 +433,7 @@ public class HashAttributeSet implements AttributeSet, Serializable { * * @return {@code true} if this attribute set contains no attributes */ + @Override public boolean isEmpty() { return attrMap.isEmpty(); } @@ -438,6 +449,7 @@ public class HashAttributeSet implements AttributeSet, Serializable { * @return {@code true} if the specified object is equal to this attribute * set */ + @Override public boolean equals(Object object) { if (!(object instanceof AttributeSet aset)) { return false; @@ -466,6 +478,7 @@ public class HashAttributeSet implements AttributeSet, Serializable { * * @return the hash code value for this attribute set */ + @Override public int hashCode() { int hcode = 0; Attribute[] attrs = toArray(); diff --git a/src/java.desktop/share/classes/javax/print/attribute/IntegerSyntax.java b/src/java.desktop/share/classes/javax/print/attribute/IntegerSyntax.java index f6dbee3aa5a..b6846ff7271 100644 --- a/src/java.desktop/share/classes/javax/print/attribute/IntegerSyntax.java +++ b/src/java.desktop/share/classes/javax/print/attribute/IntegerSyntax.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -107,6 +107,7 @@ public abstract class IntegerSyntax implements Serializable, Cloneable { * @return {@code true} if {@code object} is equivalent to this integer * attribute, {@code false} otherwise */ + @Override public boolean equals(Object object) { return object instanceof IntegerSyntax other && value == other.value; @@ -116,6 +117,7 @@ public abstract class IntegerSyntax implements Serializable, Cloneable { * Returns a hash code value for this integer attribute. The hash code is * just this integer attribute's integer value. */ + @Override public int hashCode() { return value; } @@ -125,6 +127,7 @@ public abstract class IntegerSyntax implements Serializable, Cloneable { * string value is just this integer attribute's integer value converted to * a string. */ + @Override public String toString() { return "" + value; } diff --git a/src/java.desktop/share/classes/javax/print/attribute/PrintJobAttributeSet.java b/src/java.desktop/share/classes/javax/print/attribute/PrintJobAttributeSet.java index 63535fba93e..ce22602f4d5 100644 --- a/src/java.desktop/share/classes/javax/print/attribute/PrintJobAttributeSet.java +++ b/src/java.desktop/share/classes/javax/print/attribute/PrintJobAttributeSet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -59,6 +59,7 @@ public interface PrintJobAttributeSet extends AttributeSet { * interface {@link PrintJobAttribute PrintJobAttribute} * @throws NullPointerException if the {@code attribute} is {@code null} */ + @Override public boolean add(Attribute attribute); /** @@ -88,5 +89,6 @@ public interface PrintJobAttributeSet extends AttributeSet { * @throws NullPointerException if the specified set is {@code null} * @see #add(Attribute) */ + @Override public boolean addAll(AttributeSet attributes); } diff --git a/src/java.desktop/share/classes/javax/print/attribute/PrintRequestAttributeSet.java b/src/java.desktop/share/classes/javax/print/attribute/PrintRequestAttributeSet.java index 95a07655f03..958d255b296 100644 --- a/src/java.desktop/share/classes/javax/print/attribute/PrintRequestAttributeSet.java +++ b/src/java.desktop/share/classes/javax/print/attribute/PrintRequestAttributeSet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * 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,7 @@ public interface PrintRequestAttributeSet extends AttributeSet { * interface {@link PrintRequestAttribute PrintRequestAttribute} * @throws NullPointerException if the {@code attribute} is {@code null} */ + @Override public boolean add(Attribute attribute); /** @@ -90,5 +91,6 @@ public interface PrintRequestAttributeSet extends AttributeSet { * @throws NullPointerException if the specified set is {@code null} * @see #add(Attribute) */ + @Override public boolean addAll(AttributeSet attributes); } diff --git a/src/java.desktop/share/classes/javax/print/attribute/PrintServiceAttributeSet.java b/src/java.desktop/share/classes/javax/print/attribute/PrintServiceAttributeSet.java index fd2d4dc4694..a456eac07b6 100644 --- a/src/java.desktop/share/classes/javax/print/attribute/PrintServiceAttributeSet.java +++ b/src/java.desktop/share/classes/javax/print/attribute/PrintServiceAttributeSet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * 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,7 @@ public interface PrintServiceAttributeSet extends AttributeSet { * interface {@link PrintServiceAttribute PrintServiceAttribute} * @throws NullPointerException if the {@code attribute} is {@code null} */ + @Override public boolean add(Attribute attribute); /** @@ -90,5 +91,6 @@ public interface PrintServiceAttributeSet extends AttributeSet { * @throws NullPointerException if the specified set is {@code null} * @see #add(Attribute) */ + @Override public boolean addAll(AttributeSet attributes); } diff --git a/src/java.desktop/share/classes/javax/print/attribute/ResolutionSyntax.java b/src/java.desktop/share/classes/javax/print/attribute/ResolutionSyntax.java index 8ffae65a0d2..ffb1fab3619 100644 --- a/src/java.desktop/share/classes/javax/print/attribute/ResolutionSyntax.java +++ b/src/java.desktop/share/classes/javax/print/attribute/ResolutionSyntax.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -266,6 +266,7 @@ public abstract class ResolutionSyntax implements Serializable, Cloneable { * @return {@code true} if {@code object} is equivalent to this resolution * attribute, {@code false} otherwise */ + @Override public boolean equals(Object object) { return object instanceof ResolutionSyntax other && this.crossFeedResolution == other.crossFeedResolution && @@ -275,6 +276,7 @@ public abstract class ResolutionSyntax implements Serializable, Cloneable { /** * Returns a hash code value for this resolution attribute. */ + @Override public int hashCode() { return(((crossFeedResolution & 0x0000FFFF)) | ((feedResolution & 0x0000FFFF) << 16)); @@ -286,6 +288,7 @@ public abstract class ResolutionSyntax implements Serializable, Cloneable { * cross feed direction resolution and F is the feed direction * resolution. The values are reported in the internal units of dphi. */ + @Override public String toString() { StringBuilder result = new StringBuilder(); result.append(crossFeedResolution); diff --git a/src/java.desktop/share/classes/javax/print/attribute/SetOfIntegerSyntax.java b/src/java.desktop/share/classes/javax/print/attribute/SetOfIntegerSyntax.java index 6df67ef90ca..8088cfcd743 100644 --- a/src/java.desktop/share/classes/javax/print/attribute/SetOfIntegerSyntax.java +++ b/src/java.desktop/share/classes/javax/print/attribute/SetOfIntegerSyntax.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -482,6 +482,7 @@ public abstract class SetOfIntegerSyntax implements Serializable, Cloneable { * @return {@code true} if {@code object} is equivalent to this * set-of-integer attribute, {@code false} otherwise */ + @Override public boolean equals(Object object) { if (object instanceof SetOfIntegerSyntax other) { int[][] myMembers = this.members; @@ -509,6 +510,7 @@ public abstract class SetOfIntegerSyntax implements Serializable, Cloneable { * code is the sum of the lower and upper bounds of the ranges in the * canonical array form, or 0 for an empty set. */ + @Override public int hashCode() { int result = 0; int n = members.length; @@ -526,6 +528,7 @@ public abstract class SetOfIntegerSyntax implements Serializable, Cloneable { * the lower bound equals the upper bound or * "i-j" otherwise. */ + @Override public String toString() { StringBuilder result = new StringBuilder(); int n = members.length; diff --git a/src/java.desktop/share/classes/javax/print/attribute/Size2DSyntax.java b/src/java.desktop/share/classes/javax/print/attribute/Size2DSyntax.java index 9ff772bc30d..056031b52f2 100644 --- a/src/java.desktop/share/classes/javax/print/attribute/Size2DSyntax.java +++ b/src/java.desktop/share/classes/javax/print/attribute/Size2DSyntax.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * 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,6 +263,7 @@ public abstract class Size2DSyntax implements Serializable, Cloneable { * @return {@code true} if {@code object} is equivalent to this * two-dimensional size attribute, {@code false} otherwise */ + @Override public boolean equals(Object object) { return object instanceof Size2DSyntax size2DSyntax && this.x == size2DSyntax.x && @@ -272,6 +273,7 @@ public abstract class Size2DSyntax implements Serializable, Cloneable { /** * Returns a hash code value for this two-dimensional size attribute. */ + @Override public int hashCode() { return (((x & 0x0000FFFF) ) | ((y & 0x0000FFFF) << 16)); @@ -283,6 +285,7 @@ public abstract class Size2DSyntax implements Serializable, Cloneable { * is the {@code X} dimension and Y is the {@code Y} dimension. The * values are reported in the internal units of micrometers. */ + @Override public String toString() { StringBuilder result = new StringBuilder(); result.append(x); diff --git a/src/java.desktop/share/classes/javax/print/attribute/TextSyntax.java b/src/java.desktop/share/classes/javax/print/attribute/TextSyntax.java index 9a343bc8af2..2c49a11b250 100644 --- a/src/java.desktop/share/classes/javax/print/attribute/TextSyntax.java +++ b/src/java.desktop/share/classes/javax/print/attribute/TextSyntax.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * 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,7 @@ public abstract class TextSyntax implements Serializable, Cloneable { * * @return a hashcode value for this object */ + @Override public int hashCode() { return value.hashCode() ^ locale.hashCode(); } @@ -131,6 +132,7 @@ public abstract class TextSyntax implements Serializable, Cloneable { * @return {@code true} if {@code object} is equivalent to this text * attribute, {@code false} otherwise */ + @Override public boolean equals(Object object) { return object instanceof TextSyntax other && this.value.equals(other.value) && @@ -143,6 +145,7 @@ public abstract class TextSyntax implements Serializable, Cloneable { * * @return a {@code String} identifying this object */ + @Override public String toString(){ return value; } diff --git a/src/java.desktop/share/classes/javax/print/attribute/URISyntax.java b/src/java.desktop/share/classes/javax/print/attribute/URISyntax.java index 10545df71fd..b3e604283f7 100644 --- a/src/java.desktop/share/classes/javax/print/attribute/URISyntax.java +++ b/src/java.desktop/share/classes/javax/print/attribute/URISyntax.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -82,6 +82,7 @@ public abstract class URISyntax implements Serializable, Cloneable { * * @return a hashcode value for this object */ + @Override public int hashCode() { return uri.hashCode(); } @@ -100,6 +101,7 @@ public abstract class URISyntax implements Serializable, Cloneable { * @return {@code true} if {@code object} is equivalent to this {@code URI} * attribute, {@code false} otherwise */ + @Override public boolean equals(Object object) { return object instanceof URISyntax other && this.uri.equals(other.uri); @@ -112,6 +114,7 @@ public abstract class URISyntax implements Serializable, Cloneable { * * @return a {@code String} identifying this object */ + @Override public String toString() { return uri.toString(); } From 8d79d4794eef196a17e8f993dbca8856f65f936c Mon Sep 17 00:00:00 2001 From: David Holmes Date: Sun, 19 Apr 2026 21:20:49 +0000 Subject: [PATCH 344/359] 8382391: Cleanup unnecessary storestore() in stringStream::as_string Reviewed-by: stefank, dlong, shade --- src/hotspot/share/utilities/ostream.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/hotspot/share/utilities/ostream.cpp b/src/hotspot/share/utilities/ostream.cpp index ded233d48bf..1ac34e3d9cb 100644 --- a/src/hotspot/share/utilities/ostream.cpp +++ b/src/hotspot/share/utilities/ostream.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -425,11 +425,6 @@ char* stringStream::as_string(bool c_heap) const { NEW_C_HEAP_ARRAY(char, _written + 1, mtInternal) : NEW_RESOURCE_ARRAY(char, _written + 1); ::memcpy(copy, _buffer, _written); copy[_written] = '\0'; // terminating null - if (c_heap) { - // Need to ensure our content is written to memory before we return - // the pointer to it. - OrderAccess::storestore(); - } return copy; } From 35f623b61279a448e2ddcbb6e1ba9eebe4dee8e2 Mon Sep 17 00:00:00 2001 From: Ivan Bereziuk Date: Mon, 20 Apr 2026 04:01:32 +0000 Subject: [PATCH 345/359] 8382090: Remove .rej and .orig from .gitignore Reviewed-by: aivanov, erikj, syan, liach --- .gitignore | 2 -- 1 file changed, 2 deletions(-) diff --git a/.gitignore b/.gitignore index b6b4a1a559a..a45e2113756 100644 --- a/.gitignore +++ b/.gitignore @@ -24,8 +24,6 @@ NashornProfile.txt /.gdbinit /.lldbinit **/core.[0-9]* -*.rej -*.orig test/benchmarks/**/target /src/hotspot/CMakeLists.txt /src/hotspot/compile_commands.json From 444e6f6366853b0eb842cb28283eed4dd00851d0 Mon Sep 17 00:00:00 2001 From: jonghoonpark Date: Mon, 20 Apr 2026 05:32:15 +0000 Subject: [PATCH 346/359] 8382312: Cleanup instanceKlass dead code Reviewed-by: dholmes --- src/hotspot/share/oops/instanceKlass.hpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/hotspot/share/oops/instanceKlass.hpp b/src/hotspot/share/oops/instanceKlass.hpp index dd563ad3492..6c880811024 100644 --- a/src/hotspot/share/oops/instanceKlass.hpp +++ b/src/hotspot/share/oops/instanceKlass.hpp @@ -330,9 +330,6 @@ class InstanceKlass: public Klass { bool defined_by_other_loaders() const { return _misc_flags.defined_by_other_loaders(); } void set_class_loader_type() { _misc_flags.set_class_loader_type(_class_loader_data); } - // Check if the class can be shared in CDS - bool is_shareable() const; - bool shared_loading_failed() const { return _misc_flags.shared_loading_failed(); } void set_shared_loading_failed() { _misc_flags.set_shared_loading_failed(true); } @@ -1136,8 +1133,6 @@ private: void link_previous_versions(InstanceKlass* pv) { _previous_versions = pv; } void mark_newly_obsolete_methods(Array* old_methods, int emcp_method_count); #endif - // log class name to classlist - void log_to_classlist() const; public: #if INCLUDE_CDS From da0a7b1eec974c983f8ca25a695dce5bebfa8616 Mon Sep 17 00:00:00 2001 From: Dingli Zhang Date: Mon, 20 Apr 2026 06:33:17 +0000 Subject: [PATCH 347/359] 8382315: RISC-V: TestMultiplyReductionByte.java fails with guarantee(is_uimm5(imm)) failed: uimm is invalid Reviewed-by: fyang, gcao --- .../cpu/riscv/c2_MacroAssembler_riscv.cpp | 42 ++++++++++--------- .../cpu/riscv/c2_MacroAssembler_riscv.hpp | 12 ++++-- .../vectorapi/TestMultiplyReductionByte.java | 8 ++-- 3 files changed, 36 insertions(+), 26 deletions(-) diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp index 0d06fd469de..c9cd8220551 100644 --- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp @@ -3069,12 +3069,12 @@ void C2_MacroAssembler::reduce_mul_integral_v(Register dst, Register src1, Vecto // 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); + slidedown_v(vtmp1, vtmp2, vector_length); vsetvli_helper(bt, vector_length); vmul_vv(vtmp1, vtmp1, vtmp2); } else { - vslidedown_vi(vtmp1, src2, vector_length); + slidedown_v(vtmp1, src2, vector_length); vsetvli_helper(bt, vector_length); vmul_vv(vtmp1, vtmp1, src2); @@ -3082,7 +3082,7 @@ void C2_MacroAssembler::reduce_mul_integral_v(Register dst, Register src1, Vecto while (vector_length > 1) { vector_length /= 2; - vslidedown_vi(vtmp2, vtmp1, vector_length); + slidedown_v(vtmp2, vtmp1, vector_length); vsetvli_helper(bt, vector_length); vmul_vv(vtmp1, vtmp1, vtmp2); } @@ -3281,40 +3281,44 @@ VFCVT_SAFE(vfcvt_rtz_x_f_v); // Extract a scalar element from an vector at position 'idx'. // The input elements in src are expected to be of integral type. -void C2_MacroAssembler::extract_v(Register dst, VectorRegister src, BasicType bt, - int idx, VectorRegister tmp) { +void C2_MacroAssembler::extract_v(Register dst, VectorRegister src, + BasicType bt, int idx, VectorRegister vtmp) { assert(is_integral_type(bt), "unsupported element type"); assert(idx >= 0, "idx cannot be negative"); // Only need the first element after vector slidedown vsetvli_helper(bt, 1); if (idx == 0) { vmv_x_s(dst, src); - } else if (idx <= 31) { - vslidedown_vi(tmp, src, idx); - vmv_x_s(dst, tmp); } else { - mv(t0, idx); - vslidedown_vx(tmp, src, t0); - vmv_x_s(dst, tmp); + slidedown_v(vtmp, src, idx); + vmv_x_s(dst, vtmp); } } // Extract a scalar element from an vector at position 'idx'. // The input elements in src are expected to be of floating point type. -void C2_MacroAssembler::extract_fp_v(FloatRegister dst, VectorRegister src, BasicType bt, - int idx, VectorRegister tmp) { +void C2_MacroAssembler::extract_fp_v(FloatRegister dst, VectorRegister src, + BasicType bt, int idx, VectorRegister vtmp) { assert(is_floating_point_type(bt), "unsupported element type"); assert(idx >= 0, "idx cannot be negative"); // Only need the first element after vector slidedown vsetvli_helper(bt, 1); if (idx == 0) { vfmv_f_s(dst, src); - } else if (idx <= 31) { - vslidedown_vi(tmp, src, idx); - vfmv_f_s(dst, tmp); } else { - mv(t0, idx); - vslidedown_vx(tmp, src, t0); - vfmv_f_s(dst, tmp); + slidedown_v(vtmp, src, idx); + vfmv_f_s(dst, vtmp); + } +} + +// Move elements down a vector register group. +// Offset is the start index (offset) for the source. +void C2_MacroAssembler::slidedown_v(VectorRegister dst, VectorRegister src, + uint32_t offset, Register tmp) { + if (is_uimm5(offset)) { + vslidedown_vi(dst, src, offset); + } else { + mv(tmp, offset); + vslidedown_vx(dst, src, tmp); } } diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp index fa87ceba295..468d53b1a54 100644 --- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -296,7 +296,13 @@ void vfcvt_rtz_x_f_v_safe(VectorRegister dst, VectorRegister src); - void extract_v(Register dst, VectorRegister src, BasicType bt, int idx, VectorRegister tmp); - void extract_fp_v(FloatRegister dst, VectorRegister src, BasicType bt, int idx, VectorRegister tmp); + void extract_v(Register dst, VectorRegister src, + BasicType bt, int idx, VectorRegister vtmp); + + void extract_fp_v(FloatRegister dst, VectorRegister src, + BasicType bt, int idx, VectorRegister vtmp); + + void slidedown_v(VectorRegister dst, VectorRegister src, + uint32_t offset, Register tmp = t0); #endif // CPU_RISCV_C2_MACROASSEMBLER_RISCV_HPP diff --git a/test/hotspot/jtreg/compiler/vectorapi/TestMultiplyReductionByte.java b/test/hotspot/jtreg/compiler/vectorapi/TestMultiplyReductionByte.java index 13eafd8dc26..e9bf906a1be 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/TestMultiplyReductionByte.java +++ b/test/hotspot/jtreg/compiler/vectorapi/TestMultiplyReductionByte.java @@ -57,7 +57,7 @@ public class TestMultiplyReductionByte { @Test @IR(counts = {IRNode.MUL_REDUCTION_VI, ">=1"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, applyIf = {"MaxVectorSize", ">=8"}) static byte testMulReduce64() { return ByteVector.fromArray(ByteVector.SPECIES_64, input, 0) @@ -75,7 +75,7 @@ public class TestMultiplyReductionByte { @Test @IR(counts = {IRNode.MUL_REDUCTION_VI, ">=1"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, applyIf = {"MaxVectorSize", ">=16"}) static byte testMulReduce128() { return ByteVector.fromArray(ByteVector.SPECIES_128, input, 0) @@ -93,7 +93,7 @@ public class TestMultiplyReductionByte { @Test @IR(counts = {IRNode.MUL_REDUCTION_VI, ">=1"}, - applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true", "rvv", "true"}, applyIf = {"MaxVectorSize", ">=32"}) static byte testMulReduce256() { return ByteVector.fromArray(ByteVector.SPECIES_256, input, 0) @@ -111,7 +111,7 @@ public class TestMultiplyReductionByte { @Test @IR(counts = {IRNode.MUL_REDUCTION_VI, ">=1"}, - applyIfCPUFeatureOr = {"avx512f", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx512f", "true", "asimd", "true", "rvv", "true"}, applyIf = {"MaxVectorSize", ">=64"}) static byte testMulReduce512() { return ByteVector.fromArray(ByteVector.SPECIES_512, input, 0) From e4076b09dff90701a3f192d3eefba27d35c260d6 Mon Sep 17 00:00:00 2001 From: Daniel Skantz Date: Mon, 20 Apr 2026 06:38:10 +0000 Subject: [PATCH 348/359] 8375905: Add a missing bailout check in PhaseCFG::schedule_late and a test to exercise more bailout code paths Reviewed-by: dfenacci, chagedorn, rcastanedalo --- src/hotspot/share/opto/gcm.cpp | 3 ++ .../compiler/debug/TestStressBailout.java | 28 +++++++++++++------ 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/src/hotspot/share/opto/gcm.cpp b/src/hotspot/share/opto/gcm.cpp index e3d3108a22e..ce1ea8a59e2 100644 --- a/src/hotspot/share/opto/gcm.cpp +++ b/src/hotspot/share/opto/gcm.cpp @@ -1743,6 +1743,9 @@ void PhaseCFG::schedule_late(VectorSet &visited, Node_Stack &stack) { // are needed make sure that after placement in a block we don't // need any new precedence edges. verify_anti_dependences(late, self); + if (C->failing()) { + return; + } } #endif } // Loop until all nodes have been visited diff --git a/test/hotspot/jtreg/compiler/debug/TestStressBailout.java b/test/hotspot/jtreg/compiler/debug/TestStressBailout.java index 68610576a39..f79cb679c41 100644 --- a/test/hotspot/jtreg/compiler/debug/TestStressBailout.java +++ b/test/hotspot/jtreg/compiler/debug/TestStressBailout.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. * 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 @@ package compiler.debug; import java.util.Random; +import java.util.stream.Stream; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; @@ -36,24 +37,33 @@ import jdk.test.lib.Utils; * @requires vm.debug == true & vm.compiler2.enabled & (vm.opt.AbortVMOnCompilationFailure == "null" | !vm.opt.AbortVMOnCompilationFailure) * @summary Basic tests for bailout stress flag. * @library /test/lib / - * @run driver compiler.debug.TestStressBailout + * @run main compiler.debug.TestStressBailout + */ + +/* + * @test + * @key stress randomness + * @bug 8375905 + * @requires vm.debug == true & vm.compiler2.enabled & (vm.opt.AbortVMOnCompilationFailure == "null" | !vm.opt.AbortVMOnCompilationFailure) + * @summary Additional crashes revealed by diagnostic code run during VerifyIterativeGVN + * @library /test/lib / + * @run main compiler.debug.TestStressBailout -XX:VerifyIterativeGVN=1111 */ public class TestStressBailout { - static void runTest(int invprob) throws Exception { - String[] procArgs = {"-Xcomp", "-XX:-TieredCompilation", "-XX:+StressBailout", - "-XX:StressBailoutMean=" + invprob, "-version"}; - ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder(procArgs); + static void runTest(int invprob, Stream vmArgs) throws Exception { + Stream procArgs = Stream.of("-Xcomp", "-XX:-TieredCompilation", "-XX:+StressBailout", "-XX:StressBailoutMean=" + invprob, "-version"); + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder(Stream.concat(vmArgs, procArgs).toArray(x -> new String[x])); OutputAnalyzer out = new OutputAnalyzer(pb.start()); out.shouldHaveExitValue(0); } - public static void main(String[] args) throws Exception { + public static void main(String[] vmArgs) throws Exception { Random r = Utils.getRandomInstance(); // Likely bail out on -version, for some low Mean value. - runTest(r.nextInt(1, 10)); + runTest(r.nextInt(1, 10), Stream.of(vmArgs)); // Higher value - runTest(r.nextInt(10, 1_000_000)); + runTest(r.nextInt(10, 1_000_000), Stream.of(vmArgs)); } } From f1eac215ffd86e5a4694b6a6bf99832bc8a236d8 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Mon, 20 Apr 2026 06:40:25 +0000 Subject: [PATCH 349/359] 8378462: Build fails with --enable-linktime-gc set when using some devkits/toolchains Reviewed-by: erikj, prr, clanger --- make/modules/java.desktop/lib/ClientLibraries.gmk | 2 ++ 1 file changed, 2 insertions(+) diff --git a/make/modules/java.desktop/lib/ClientLibraries.gmk b/make/modules/java.desktop/lib/ClientLibraries.gmk index 3e37fe79643..2326505d11c 100644 --- a/make/modules/java.desktop/lib/ClientLibraries.gmk +++ b/make/modules/java.desktop/lib/ClientLibraries.gmk @@ -395,6 +395,8 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBFONTMANAGER, \ AccelGlyphCache.c, \ CFLAGS := $(LIBFONTMANAGER_CFLAGS), \ CXXFLAGS := $(LIBFONTMANAGER_CFLAGS), \ + CXXFLAGS_gcc := -fno-rtti -fno-exceptions, \ + CXXFLAGS_clang := -fno-rtti -fno-exceptions, \ OPTIMIZATION := HIGHEST, \ CFLAGS_windows = -DCC_NOEX, \ EXTRA_HEADER_DIRS := $(LIBFONTMANAGER_EXTRA_HEADER_DIRS), \ From 5b8ac195dcca3c8f74879c8b5ca8c628db490afb Mon Sep 17 00:00:00 2001 From: Alexander Zvegintsev Date: Mon, 20 Apr 2026 07:08:15 +0000 Subject: [PATCH 350/359] 8382420: [macos] remove java/awt/Modal/ToBack/ tests from problemlist Reviewed-by: dmarkov, aivanov, prr --- test/jdk/ProblemList.txt | 54 +++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 29 deletions(-) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index f1bd91d86aa..52d02750434 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -386,36 +386,32 @@ java/awt/Mouse/EnterExitEvents/FullscreenEnterEventTest.java 8051455 macosx-all java/awt/Mouse/MouseModifiersUnitTest/MouseModifiersUnitTest_Standard.java 7124407,8302787 macosx-all,windows-all java/awt/Mouse/RemovedComponentMouseListener/RemovedComponentMouseListener.java 8157170 macosx-all java/awt/Modal/ToFront/DialogToFrontNonModalTest.java 8221899 linux-all -java/awt/Modal/ToBack/ToBackAppModal1Test.java 8196441 linux-all,macosx-all -java/awt/Modal/ToBack/ToBackAppModal2Test.java 8196441 linux-all,macosx-all -java/awt/Modal/ToBack/ToBackAppModal3Test.java 8196441 linux-all,macosx-all -java/awt/Modal/ToBack/ToBackAppModal4Test.java 8196441 linux-all,macosx-all -java/awt/Modal/ToBack/ToBackAppModal5Test.java 8196441 macosx-all +java/awt/Modal/ToBack/ToBackAppModal1Test.java 8196441 linux-all +java/awt/Modal/ToBack/ToBackAppModal2Test.java 8196441 linux-all +java/awt/Modal/ToBack/ToBackAppModal3Test.java 8196441 linux-all +java/awt/Modal/ToBack/ToBackAppModal4Test.java 8196441 linux-all java/awt/Modal/ToBack/ToBackAppModal6Test.java 8196441 linux-all -java/awt/Modal/ToBack/ToBackModal1Test.java 8196441 linux-all,macosx-all -java/awt/Modal/ToBack/ToBackModal2Test.java 8196441 linux-all,macosx-all -java/awt/Modal/ToBack/ToBackModal3Test.java 8196441 linux-all,macosx-all -java/awt/Modal/ToBack/ToBackModal4Test.java 8196441 linux-all,macosx-all -java/awt/Modal/ToBack/ToBackTKModal1Test.java 8196441 linux-all,macosx-all -java/awt/Modal/ToBack/ToBackTKModal2Test.java 8196441 linux-all,macosx-all -java/awt/Modal/ToBack/ToBackTKModal3Test.java 8196441 linux-all,macosx-all -java/awt/Modal/ToBack/ToBackTKModal4Test.java 8196441 linux-all,macosx-all -java/awt/Modal/ToBack/ToBackTKModal5Test.java 8196441 macosx-all -java/awt/Modal/ToBack/ToBackDocModal1Test.java 8196441 linux-all,macosx-all -java/awt/Modal/ToBack/ToBackDocModal2Test.java 8196441 linux-all,macosx-all -java/awt/Modal/ToBack/ToBackDocModal3Test.java 8196441 linux-all,macosx-all -java/awt/Modal/ToBack/ToBackDocModal4Test.java 8196441 linux-all,macosx-all -java/awt/Modal/ToBack/ToBackDocModal5Test.java 8196441 linux-all,macosx-all -java/awt/Modal/ToBack/ToBackModeless1Test.java 8196441 macosx-all,linux-all -java/awt/Modal/ToBack/ToBackModeless2Test.java 8196441 macosx-all,linux-all -java/awt/Modal/ToBack/ToBackModeless3Test.java 8196441 macosx-all,linux-all -java/awt/Modal/ToBack/ToBackModeless4Test.java 8196441 macosx-all,linux-all -java/awt/Modal/ToBack/ToBackModeless5Test.java 8196441 macosx-all -java/awt/Modal/ToBack/ToBackNonModal1Test.java 8196441 macosx-all,linux-all -java/awt/Modal/ToBack/ToBackNonModal2Test.java 8196441 macosx-all,linux-all -java/awt/Modal/ToBack/ToBackNonModal3Test.java 8196441 macosx-all,linux-all -java/awt/Modal/ToBack/ToBackNonModal4Test.java 8196441 macosx-all,linux-all -java/awt/Modal/ToBack/ToBackNonModal5Test.java 8196441 macosx-all +java/awt/Modal/ToBack/ToBackModal1Test.java 8196441 linux-all +java/awt/Modal/ToBack/ToBackModal2Test.java 8196441 linux-all +java/awt/Modal/ToBack/ToBackModal3Test.java 8196441 linux-all +java/awt/Modal/ToBack/ToBackModal4Test.java 8196441 linux-all +java/awt/Modal/ToBack/ToBackTKModal1Test.java 8196441 linux-all +java/awt/Modal/ToBack/ToBackTKModal2Test.java 8196441 linux-all +java/awt/Modal/ToBack/ToBackTKModal3Test.java 8196441 linux-all +java/awt/Modal/ToBack/ToBackTKModal4Test.java 8196441 linux-all +java/awt/Modal/ToBack/ToBackDocModal1Test.java 8196441 linux-all +java/awt/Modal/ToBack/ToBackDocModal2Test.java 8196441 linux-all +java/awt/Modal/ToBack/ToBackDocModal3Test.java 8196441 linux-all +java/awt/Modal/ToBack/ToBackDocModal4Test.java 8196441 linux-all +java/awt/Modal/ToBack/ToBackDocModal5Test.java 8196441 linux-all +java/awt/Modal/ToBack/ToBackModeless1Test.java 8196441 linux-all +java/awt/Modal/ToBack/ToBackModeless2Test.java 8196441 linux-all +java/awt/Modal/ToBack/ToBackModeless3Test.java 8196441 linux-all +java/awt/Modal/ToBack/ToBackModeless4Test.java 8196441 linux-all +java/awt/Modal/ToBack/ToBackNonModal1Test.java 8196441 linux-all +java/awt/Modal/ToBack/ToBackNonModal2Test.java 8196441 linux-all +java/awt/Modal/ToBack/ToBackNonModal3Test.java 8196441 linux-all +java/awt/Modal/ToBack/ToBackNonModal4Test.java 8196441 linux-all javax/print/PrintSEUmlauts/PrintSEUmlauts.java 8135174 generic-all java/awt/font/Rotate/RotatedTextTest.java 8219641 linux-all java/awt/font/TextLayout/LigatureCaretTest.java 8266312 generic-all From 48b6da7cf685fd3d2326b89455799818a0de48d9 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Mon, 20 Apr 2026 07:40:12 +0000 Subject: [PATCH 351/359] 8382422: G1: G1GCPhaseTimes::record_merge_heap_roots() uses += instead of direct assignment Reviewed-by: iwalulya, ayang --- src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp b/src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp index b57bf0d617e..6df98ba9c73 100644 --- a/src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp +++ b/src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp @@ -298,7 +298,7 @@ class G1GCPhaseTimes : public CHeapObj { } void record_merge_heap_roots_time(double ms) { - _cur_merge_heap_roots_time_ms += ms; + _cur_merge_heap_roots_time_ms = ms; } void record_merge_refinement_table_time(double ms) { From 62bd83a0d8c12f68474cf6c1d99df124c4a66a0d Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Mon, 20 Apr 2026 07:42:34 +0000 Subject: [PATCH 352/359] 8382423: G1: Remove unused G1GCPhaseTimes::_external_accounted_time_ms Reviewed-by: ayang, iwalulya --- src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp | 1 - src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp | 6 ------ 2 files changed, 7 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp b/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp index 023790a2422..f3f4f4147c7 100644 --- a/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp +++ b/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp @@ -181,7 +181,6 @@ void G1GCPhaseTimes::reset() { _cur_resize_heap_time_ms = 0.0; _cur_ref_proc_time_ms = 0.0; _root_region_scan_time_ms = 0.0; - _external_accounted_time_ms = 0.0; _recorded_prepare_heap_roots_time_ms = 0.0; _recorded_young_cset_choice_time_ms = 0.0; _recorded_non_young_cset_choice_time_ms = 0.0; diff --git a/src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp b/src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp index 6df98ba9c73..614db0379e6 100644 --- a/src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp +++ b/src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp @@ -193,8 +193,6 @@ class G1GCPhaseTimes : public CHeapObj { // Not included in _gc_pause_time_ms double _root_region_scan_time_ms; - double _external_accounted_time_ms; - double _recorded_prepare_heap_roots_time_ms; double _recorded_young_cset_choice_time_ms; @@ -373,10 +371,6 @@ class G1GCPhaseTimes : public CHeapObj { _cur_verify_after_time_ms = time_ms; } - void inc_external_accounted_time_ms(double time_ms) { - _external_accounted_time_ms += time_ms; - } - void record_prepare_heap_roots_time_ms(double recorded_prepare_heap_roots_time_ms) { _recorded_prepare_heap_roots_time_ms = recorded_prepare_heap_roots_time_ms; } From 952f9aa0695871a98c53326b18ae66af82531840 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Mon, 20 Apr 2026 07:52:17 +0000 Subject: [PATCH 353/359] 8382418: G1: Remove some stale comments about time accounting Reviewed-by: iwalulya --- src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp | 5 +---- src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp | 3 --- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp b/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp index f3f4f4147c7..e13b9d91bc5 100644 --- a/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp +++ b/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp @@ -415,8 +415,6 @@ double G1GCPhaseTimes::print_pre_evacuate_collection_set() const { info_time("Pre Evacuate Collection Set", sum_ms); - // Concurrent tasks of ResetMarkingState and NoteStartOfMark are triggered during - // young collection. However, their execution time are not included in _gc_pause_time_ms. if (_cur_prepare_concurrent_task_time_ms > 0.0) { debug_time("Prepare Concurrent Start", _cur_prepare_concurrent_task_time_ms); debug_phase(_gc_par_phases[ResetMarkingState], 1); @@ -542,10 +540,9 @@ void G1GCPhaseTimes::print_other(double accounted_ms) const { info_time("Other", _gc_pause_time_ms - accounted_ms); } -// Root-region-scan-wait, verify-before and verify-after are part of young GC, +// Root region scan, verify before and verify after are part of young GC, // but these are not measured by G1Policy. i.e. these are not included in // G1Policy::record_young_collection_start() and record_young_collection_end(). -// In addition, these are not included in G1GCPhaseTimes::_gc_pause_time_ms. // See G1YoungCollector::collect(). void G1GCPhaseTimes::print(bool evacuation_failed) { if (_root_region_scan_time_ms > 0.0) { diff --git a/src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp b/src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp index 614db0379e6..eb51b340da3 100644 --- a/src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp +++ b/src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp @@ -175,7 +175,6 @@ class G1GCPhaseTimes : public CHeapObj { double _cur_collection_nmethod_list_cleanup_time_ms; double _cur_merge_heap_roots_time_ms; - // Merge refinement table time. Note that this time is included in _cur_merge_heap_roots_time_ms. double _cur_merge_refinement_table_time_ms; double _cur_optional_merge_heap_roots_time_ms; @@ -190,7 +189,6 @@ class G1GCPhaseTimes : public CHeapObj { double _cur_resize_heap_time_ms; double _cur_ref_proc_time_ms; - // Not included in _gc_pause_time_ms double _root_region_scan_time_ms; double _recorded_prepare_heap_roots_time_ms; @@ -208,7 +206,6 @@ class G1GCPhaseTimes : public CHeapObj { double _cur_region_register_time; - // Not included in _gc_pause_time_ms double _cur_verify_before_time_ms; double _cur_verify_after_time_ms; From 61849f47add0d96d4723858f10fe67de411c4166 Mon Sep 17 00:00:00 2001 From: Per Minborg Date: Mon, 20 Apr 2026 08:08:49 +0000 Subject: [PATCH 354/359] 8381935: Improve numChunks range in the PPC64 CallAranger Reviewed-by: mdoerr --- .../jdk/internal/foreign/abi/ppc64/CallArranger.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/ppc64/CallArranger.java b/src/java.base/share/classes/jdk/internal/foreign/abi/ppc64/CallArranger.java index 0fd90ef6f73..c9994ec2930 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/abi/ppc64/CallArranger.java +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/ppc64/CallArranger.java @@ -245,7 +245,12 @@ public abstract class CallArranger { // Regular struct, no HFA. VMStorage[] structAlloc(MemoryLayout layout) { // Allocate enough gp slots (regs and stack) such that the struct fits in them. - int numChunks = (int) Utils.alignUp(layout.byteSize(), MAX_COPY_SIZE) / MAX_COPY_SIZE; + final int numChunks; + try { + numChunks = Math.toIntExact(Utils.alignUp(layout.byteSize(), MAX_COPY_SIZE) / MAX_COPY_SIZE); + } catch (ArithmeticException ae) { + throw new IllegalArgumentException("Layout too large: " + layout, ae); + } VMStorage[] result = new VMStorage[numChunks]; for (int i = 0; i < numChunks; i++) { result[i] = nextStorage(StorageType.INTEGER, false); From eac396861824f74e9bb19098bf689957a6e19f06 Mon Sep 17 00:00:00 2001 From: Per Minborg Date: Mon, 20 Apr 2026 08:11:51 +0000 Subject: [PATCH 355/359] 8381012: Add warning for == for MemorySegment.NULL Reviewed-by: liach --- .../share/classes/java/lang/foreign/MemorySegment.java | 5 +++++ 1 file changed, 5 insertions(+) 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 78098e39a17..70b15bb0cd7 100644 --- a/src/java.base/share/classes/java/lang/foreign/MemorySegment.java +++ b/src/java.base/share/classes/java/lang/foreign/MemorySegment.java @@ -1552,6 +1552,11 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl { *

    * The {@linkplain MemorySegment#maxByteAlignment() maximum byte alignment} for * the {@code NULL} segment is of 262. + * + * @apiNote Clients should avoid using {@code ==} to compare a segment with + * {@code MemorySegment.NULL}. A segment with address {@code 0L} may be + * {@linkplain #ofAddress(long) created independently} and may therefore + * have a different identity. */ MemorySegment NULL = MemorySegment.ofAddress(0L); From 9a689b017149019207284709bcf39535a232a4e8 Mon Sep 17 00:00:00 2001 From: Dingli Zhang Date: Mon, 20 Apr 2026 08:39:48 +0000 Subject: [PATCH 356/359] 8382393: Enable VectorStoreMaskIdentityTest.java IR tests for RISC-V Reviewed-by: fyang, epeter --- .../VectorStoreMaskIdentityTest.java | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/test/hotspot/jtreg/compiler/vectorapi/VectorStoreMaskIdentityTest.java b/test/hotspot/jtreg/compiler/vectorapi/VectorStoreMaskIdentityTest.java index c019f116373..527041b58a6 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/VectorStoreMaskIdentityTest.java +++ b/test/hotspot/jtreg/compiler/vectorapi/VectorStoreMaskIdentityTest.java @@ -73,7 +73,7 @@ public class VectorStoreMaskIdentityTest { IRNode.VECTOR_LOAD_MASK, "= 0", IRNode.VECTOR_STORE_MASK, "= 0", IRNode.VECTOR_MASK_CAST, "= 0" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx", "true" }, + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }, applyIf = { "MaxVectorSize", ">= 16" }) public static void testVectorMaskStoreIdentityByte() { VectorMask mask_byte_64 = VectorMask.fromArray(B64, mask_in, 0); @@ -93,7 +93,7 @@ public class VectorStoreMaskIdentityTest { IRNode.VECTOR_LOAD_MASK, "= 0", IRNode.VECTOR_STORE_MASK, "= 0", IRNode.VECTOR_MASK_CAST, "= 0" }, - applyIfCPUFeatureOr = { "sve", "true", "avx2", "true" }, + applyIfCPUFeatureOr = { "sve", "true", "avx2", "true", "rvv", "true" }, applyIf = { "MaxVectorSize", "> 16" }) public static void testVectorMaskStoreIdentityByte256() { VectorMask mask_byte_64 = VectorMask.fromArray(B64, mask_in, 0); @@ -113,7 +113,7 @@ public class VectorStoreMaskIdentityTest { IRNode.VECTOR_LOAD_MASK, "= 0", IRNode.VECTOR_STORE_MASK, "= 0", IRNode.VECTOR_MASK_CAST, "= 0" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx", "true" }, + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }, applyIf = { "MaxVectorSize", ">= 16" }) public static void testVectorMaskStoreIdentityShort() { VectorMask mask_short_128 = VectorMask.fromArray(S128, mask_in, 0); @@ -133,7 +133,7 @@ public class VectorStoreMaskIdentityTest { IRNode.VECTOR_LOAD_MASK, "= 0", IRNode.VECTOR_STORE_MASK, "= 0", IRNode.VECTOR_MASK_CAST, "= 0" }, - applyIfCPUFeatureOr = { "sve", "true", "avx2", "true" }, + applyIfCPUFeatureOr = { "sve", "true", "avx2", "true", "rvv", "true" }, applyIf = { "MaxVectorSize", "> 16" }) public static void testVectorMaskStoreIdentityShort256() { VectorMask mask_short_128 = VectorMask.fromArray(S128, mask_in, 0); @@ -153,7 +153,7 @@ public class VectorStoreMaskIdentityTest { IRNode.VECTOR_LOAD_MASK, "= 0", IRNode.VECTOR_STORE_MASK, "= 0", IRNode.VECTOR_MASK_CAST, "= 0" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx", "true" }, + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }, applyIf = { "MaxVectorSize", ">= 16" }) public static void testVectorMaskStoreIdentityInt() { VectorMask mask_int_128 = VectorMask.fromArray(I128, mask_in, 0); @@ -173,7 +173,7 @@ public class VectorStoreMaskIdentityTest { IRNode.VECTOR_LOAD_MASK, "= 0", IRNode.VECTOR_STORE_MASK, "= 0", IRNode.VECTOR_MASK_CAST, "= 0" }, - applyIfCPUFeatureOr = { "sve", "true", "avx2", "true" }, + applyIfCPUFeatureOr = { "sve", "true", "avx2", "true", "rvv", "true" }, applyIf = { "MaxVectorSize", "> 16" }) public static void testVectorMaskStoreIdentityInt256() { VectorMask mask_int_128 = VectorMask.fromArray(I128, mask_in, 0); @@ -193,7 +193,7 @@ public class VectorStoreMaskIdentityTest { IRNode.VECTOR_LOAD_MASK, "= 0", IRNode.VECTOR_STORE_MASK, "= 0", IRNode.VECTOR_MASK_CAST, "= 0" }, - applyIfCPUFeatureOr = { "asimd", "true" }, + applyIfCPUFeatureOr = { "asimd", "true", "rvv", "true" }, applyIf = { "MaxVectorSize", ">= 16" }) public static void testVectorMaskStoreIdentityLong() { VectorMask mask_long_128 = VectorMask.fromArray(L128, mask_in, 0); @@ -213,7 +213,7 @@ public class VectorStoreMaskIdentityTest { IRNode.VECTOR_LOAD_MASK, "= 0", IRNode.VECTOR_STORE_MASK, "= 0", IRNode.VECTOR_MASK_CAST, "= 0" }, - applyIfCPUFeatureOr = { "sve", "true", "avx2", "true" }, + applyIfCPUFeatureOr = { "sve", "true", "avx2", "true", "rvv", "true" }, applyIf = { "MaxVectorSize", "> 16" }) public static void testVectorMaskStoreIdentityLong256() { VectorMask mask_long_256 = VectorMask.fromArray(L256, mask_in, 0); @@ -233,7 +233,7 @@ public class VectorStoreMaskIdentityTest { IRNode.VECTOR_LOAD_MASK, "= 0", IRNode.VECTOR_STORE_MASK, "= 0", IRNode.VECTOR_MASK_CAST, "= 0" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx", "true" }, + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }, applyIf = { "MaxVectorSize", ">= 16" }) public static void testVectorMaskStoreIdentityFloat() { VectorMask mask_float_128 = VectorMask.fromArray(F128, mask_in, 0); @@ -253,7 +253,7 @@ public class VectorStoreMaskIdentityTest { IRNode.VECTOR_LOAD_MASK, "= 0", IRNode.VECTOR_STORE_MASK, "= 0", IRNode.VECTOR_MASK_CAST, "= 0" }, - applyIfCPUFeatureOr = { "sve", "true", "avx2", "true" }, + applyIfCPUFeatureOr = { "sve", "true", "avx2", "true", "rvv", "true" }, applyIf = { "MaxVectorSize", "> 16" }) public static void testVectorMaskStoreIdentityFloat256() { VectorMask mask_float_128 = VectorMask.fromArray(F128, mask_in, 0); @@ -273,7 +273,7 @@ public class VectorStoreMaskIdentityTest { IRNode.VECTOR_LOAD_MASK, "= 0", IRNode.VECTOR_STORE_MASK, "= 0", IRNode.VECTOR_MASK_CAST, "= 0" }, - applyIfCPUFeatureOr = { "asimd", "true" }, + applyIfCPUFeatureOr = { "asimd", "true", "rvv", "true" }, applyIf = { "MaxVectorSize", ">= 16" }) public static void testVectorMaskStoreIdentityDouble() { VectorMask mask_double_128 = VectorMask.fromArray(D128, mask_in, 0); @@ -293,7 +293,7 @@ public class VectorStoreMaskIdentityTest { IRNode.VECTOR_LOAD_MASK, "= 0", IRNode.VECTOR_STORE_MASK, "= 0", IRNode.VECTOR_MASK_CAST, "= 0" }, - applyIfCPUFeatureOr = { "sve", "true", "avx2", "true" }, + applyIfCPUFeatureOr = { "sve", "true", "avx2", "true", "rvv", "true" }, applyIf = { "MaxVectorSize", "> 16" }) public static void testVectorMaskStoreIdentityDouble256() { VectorMask mask_double_256 = VectorMask.fromArray(D256, mask_in, 0); @@ -314,4 +314,4 @@ public class VectorStoreMaskIdentityTest { .addFlags("--add-modules=jdk.incubator.vector") .start(); } -} \ No newline at end of file +} From abd3d4620423c322d18e7d8a4f3476de97402054 Mon Sep 17 00:00:00 2001 From: Stefan Karlsson Date: Mon, 20 Apr 2026 08:42:08 +0000 Subject: [PATCH 357/359] 8382401: Remove return type parameters from FREE_ and REALLOC_ macros Reviewed-by: tschatzl, dholmes --- src/hotspot/cpu/x86/vm_version_x86.cpp | 2 +- src/hotspot/os/aix/os_aix.cpp | 4 +- src/hotspot/os/aix/os_perf_aix.cpp | 12 ++-- src/hotspot/os/bsd/os_bsd.cpp | 8 +-- src/hotspot/os/bsd/os_perf_bsd.cpp | 6 +- src/hotspot/os/linux/os_linux.cpp | 6 +- src/hotspot/os/linux/os_perf_linux.cpp | 8 +-- src/hotspot/os/linux/procMapsParser.cpp | 2 +- src/hotspot/os/posix/perfMemory_posix.cpp | 40 +++++------ src/hotspot/os/windows/os_perf_windows.cpp | 22 +++--- src/hotspot/os/windows/os_windows.cpp | 20 +++--- src/hotspot/os/windows/perfMemory_windows.cpp | 72 +++++++++---------- src/hotspot/share/asm/codeBuffer.cpp | 2 +- .../share/cds/aotStreamedHeapLoader.cpp | 2 +- src/hotspot/share/cds/archiveBuilder.cpp | 2 +- src/hotspot/share/cds/cdsConfig.cpp | 2 +- src/hotspot/share/cds/classListWriter.cpp | 2 +- src/hotspot/share/cds/filemap.cpp | 2 +- src/hotspot/share/ci/ciReplay.cpp | 2 +- .../share/classfile/classFileParser.cpp | 8 +-- src/hotspot/share/classfile/classLoader.cpp | 10 +-- .../share/classfile/compactHashtable.cpp | 2 +- .../share/classfile/resolutionErrors.cpp | 6 +- src/hotspot/share/code/aotCodeCache.cpp | 6 +- src/hotspot/share/code/aotCodeCache.hpp | 2 +- src/hotspot/share/code/codeCache.cpp | 2 +- .../share/code/exceptionHandlerTable.cpp | 4 +- .../share/compiler/cHeapStringHolder.cpp | 2 +- .../compiler/compilationMemoryStatistic.cpp | 2 +- src/hotspot/share/compiler/compileLog.cpp | 6 +- .../share/compiler/compilerDirectives.cpp | 2 +- .../share/compiler/compilerDirectives.hpp | 2 +- .../share/compiler/directivesParser.cpp | 9 ++- src/hotspot/share/compiler/oopMap.cpp | 2 +- .../gc/epsilon/epsilonMonitoringSupport.cpp | 2 +- src/hotspot/share/gc/g1/g1Allocator.cpp | 6 +- src/hotspot/share/gc/g1/g1Arguments.cpp | 2 +- src/hotspot/share/gc/g1/g1CardSet.cpp | 2 +- src/hotspot/share/gc/g1/g1CardSetMemory.cpp | 2 +- .../share/gc/g1/g1CardTableClaimTable.cpp | 2 +- src/hotspot/share/gc/g1/g1CollectionSet.cpp | 4 +- .../share/gc/g1/g1CollectionSetCandidates.cpp | 4 +- src/hotspot/share/gc/g1/g1ConcurrentMark.cpp | 8 +-- .../share/gc/g1/g1EvacFailureRegions.cpp | 2 +- src/hotspot/share/gc/g1/g1FullCollector.cpp | 8 +-- .../share/gc/g1/g1HeapRegionManager.cpp | 4 +- src/hotspot/share/gc/g1/g1HeapRegionSet.cpp | 2 +- src/hotspot/share/gc/g1/g1HeapTransition.cpp | 4 +- src/hotspot/share/gc/g1/g1MonotonicArena.cpp | 2 +- .../share/gc/g1/g1MonotonicArenaFreePool.cpp | 2 +- src/hotspot/share/gc/g1/g1NUMA.cpp | 10 +-- src/hotspot/share/gc/g1/g1NUMAStats.cpp | 4 +- .../share/gc/g1/g1ParScanThreadState.cpp | 8 +-- .../share/gc/g1/g1RegionMarkStatsCache.cpp | 2 +- src/hotspot/share/gc/g1/g1RegionsOnNodes.cpp | 2 +- src/hotspot/share/gc/g1/g1RemSet.cpp | 6 +- src/hotspot/share/gc/g1/g1RemSetSummary.cpp | 2 +- src/hotspot/share/gc/g1/g1SurvRateGroup.cpp | 4 +- .../gc/g1/g1YoungGCPostEvacuateTasks.cpp | 2 +- .../share/gc/g1/g1YoungGCPreEvacuateTasks.cpp | 2 +- .../share/gc/parallel/mutableNUMASpace.cpp | 2 +- src/hotspot/share/gc/shared/bufferNode.cpp | 2 +- .../share/gc/shared/classUnloadingContext.cpp | 2 +- .../share/gc/shared/collectorCounters.cpp | 2 +- .../share/gc/shared/generationCounters.cpp | 2 +- .../share/gc/shared/hSpaceCounters.cpp | 2 +- src/hotspot/share/gc/shared/oopStorage.cpp | 4 +- .../share/gc/shared/partialArrayState.cpp | 2 +- .../share/gc/shared/preservedMarks.cpp | 2 +- .../gc/shared/stringdedup/stringDedup.cpp | 2 +- .../shared/stringdedup/stringDedupTable.cpp | 2 +- .../share/gc/shared/taskqueue.inline.hpp | 2 +- .../gc/shared/workerDataArray.inline.hpp | 2 +- src/hotspot/share/gc/shared/workerUtils.cpp | 2 +- .../shenandoahAdaptiveHeuristics.cpp | 12 ++-- .../heuristics/shenandoahHeuristics.cpp | 2 +- .../gc/shenandoah/shenandoahAgeCensus.cpp | 10 +-- .../share/gc/shenandoah/shenandoahFullGC.cpp | 4 +- .../shenandoahHeapRegionCounters.cpp | 4 +- .../gc/shenandoah/shenandoahHeapRegionSet.cpp | 2 +- .../share/gc/shenandoah/shenandoahNMethod.cpp | 6 +- .../gc/shenandoah/shenandoahNumberSeq.cpp | 6 +- .../shenandoah/shenandoahScanRemembered.hpp | 4 +- .../gc/shenandoah/shenandoahSimpleBitMap.cpp | 2 +- .../gc/shenandoah/shenandoahVerifier.cpp | 2 +- .../share/gc/z/zForwardingAllocator.cpp | 4 +- src/hotspot/share/interpreter/oopMapCache.cpp | 4 +- src/hotspot/share/jfr/jni/jfrJavaSupport.cpp | 2 +- .../sampling/samplePriorityQueue.cpp | 2 +- .../jfr/periodic/jfrNetworkUtilization.cpp | 2 +- .../jfr/recorder/service/jfrOptionSet.cpp | 2 +- .../recorder/stacktrace/jfrStackFilter.cpp | 4 +- .../stacktrace/jfrStackFilterRegistry.cpp | 4 +- .../jfr/support/methodtracer/jfrFilter.cpp | 8 +-- .../support/methodtracer/jfrFilterManager.cpp | 8 +-- .../jfrConcurrentHashtable.inline.hpp | 2 +- .../share/jfr/utilities/jfrHashtable.hpp | 2 +- src/hotspot/share/jfr/utilities/jfrSet.hpp | 4 +- src/hotspot/share/libadt/vectset.cpp | 2 +- src/hotspot/share/logging/logAsyncWriter.hpp | 2 +- .../share/logging/logConfiguration.cpp | 11 ++- src/hotspot/share/logging/logFileOutput.cpp | 4 +- .../share/logging/logMessageBuffer.cpp | 6 +- src/hotspot/share/logging/logOutput.cpp | 6 +- src/hotspot/share/logging/logTagSet.cpp | 2 +- src/hotspot/share/memory/allocation.hpp | 49 +++++++------ src/hotspot/share/memory/arena.hpp | 10 +-- src/hotspot/share/memory/heapInspection.cpp | 2 +- src/hotspot/share/memory/memRegion.cpp | 2 +- .../share/memory/metaspace/rootChunkArea.cpp | 2 +- src/hotspot/share/memory/resourceArea.cpp | 6 +- src/hotspot/share/memory/universe.cpp | 2 +- .../share/nmt/nmtNativeCallStackStorage.cpp | 2 +- src/hotspot/share/nmt/vmatree.cpp | 4 +- src/hotspot/share/nmt/vmatree.hpp | 2 +- src/hotspot/share/oops/instanceKlass.cpp | 4 +- src/hotspot/share/opto/block.cpp | 2 +- src/hotspot/share/opto/chaitin.cpp | 2 +- src/hotspot/share/opto/compile.cpp | 2 +- src/hotspot/share/opto/loopnode.cpp | 4 +- src/hotspot/share/opto/loopnode.hpp | 4 +- src/hotspot/share/opto/node.cpp | 3 +- src/hotspot/share/opto/phasetype.hpp | 2 +- src/hotspot/share/opto/regmask.hpp | 3 +- .../share/opto/traceAutoVectorizationTag.hpp | 2 +- .../share/opto/traceMergeStoresTag.hpp | 2 +- src/hotspot/share/prims/jni.cpp | 2 +- src/hotspot/share/prims/jvmtiAgent.cpp | 2 +- .../prims/jvmtiClassFileReconstituter.cpp | 2 +- src/hotspot/share/prims/jvmtiExport.cpp | 2 +- src/hotspot/share/prims/jvmtiTagMap.cpp | 2 +- src/hotspot/share/prims/unsafe.cpp | 4 +- src/hotspot/share/runtime/arguments.cpp | 26 +++---- src/hotspot/share/runtime/deoptimization.cpp | 6 +- src/hotspot/share/runtime/flags/jvmFlag.cpp | 2 +- .../share/runtime/flags/jvmFlagAccess.cpp | 2 +- src/hotspot/share/runtime/javaThread.cpp | 6 +- src/hotspot/share/runtime/nonJavaThread.cpp | 2 +- .../share/runtime/objectMonitorTable.cpp | 2 +- src/hotspot/share/runtime/os.cpp | 18 ++--- src/hotspot/share/runtime/os_perf.hpp | 6 +- src/hotspot/share/runtime/perfData.cpp | 4 +- src/hotspot/share/runtime/perfMemory.cpp | 2 +- src/hotspot/share/runtime/sharedRuntime.cpp | 4 +- src/hotspot/share/runtime/threadSMR.cpp | 2 +- src/hotspot/share/runtime/threads.cpp | 2 +- src/hotspot/share/runtime/vmStructs.cpp | 8 +-- .../share/services/diagnosticArgument.cpp | 8 +-- .../share/services/finalizerService.cpp | 2 +- src/hotspot/share/services/heapDumper.cpp | 2 +- src/hotspot/share/services/management.cpp | 2 +- src/hotspot/share/services/memoryManager.cpp | 4 +- .../utilities/concurrentHashTable.inline.hpp | 2 +- src/hotspot/share/utilities/elfFile.cpp | 2 +- src/hotspot/share/utilities/elfFile.hpp | 2 +- src/hotspot/share/utilities/istream.cpp | 2 +- src/hotspot/share/utilities/numberSeq.cpp | 2 +- src/hotspot/share/utilities/ostream.cpp | 12 ++-- .../share/utilities/resizableHashTable.hpp | 4 +- src/hotspot/share/utilities/stack.inline.hpp | 2 +- src/hotspot/share/utilities/stringUtils.cpp | 2 +- src/hotspot/share/utilities/xmlstream.cpp | 4 +- .../gtest/concurrentTestRunner.inline.hpp | 2 +- .../gtest/gc/g1/test_freeRegionList.cpp | 2 +- .../gtest/gc/g1/test_g1BatchedGangTask.cpp | 2 +- .../gtest/gc/g1/test_g1CardSetContainers.cpp | 6 +- .../gtest/gc/shared/test_oopStorage.cpp | 4 +- .../gc/shared/test_oopStorage_parperf.cpp | 2 +- .../shenandoah/test_shenandoahMarkBitMap.cpp | 2 +- test/hotspot/gtest/logging/logTestFixture.cpp | 2 +- .../gtest/logging/logTestUtils.inline.hpp | 2 +- test/hotspot/gtest/logging/test_asynclog.cpp | 2 +- .../gtest/logging/test_logMessageTest.cpp | 2 +- test/hotspot/gtest/memory/test_arena.cpp | 6 +- .../gtest/metaspace/metaspaceGtestCommon.hpp | 4 +- .../metaspace/metaspaceGtestSparseArray.hpp | 3 +- .../gtest/nmt/test_nmt_locationprinting.cpp | 4 +- test/hotspot/gtest/nmt/test_nmtpreinitmap.cpp | 2 +- test/hotspot/gtest/runtime/test_os.cpp | 2 +- test/hotspot/gtest/threadHelper.inline.hpp | 2 +- .../gtest/utilities/test_bitMap_popcnt.cpp | 2 +- .../utilities/test_concurrentHashtable.cpp | 2 +- .../gtest/utilities/test_lockFreeStack.cpp | 2 +- .../gtest/utilities/test_quicksort.cpp | 4 +- 184 files changed, 435 insertions(+), 439 deletions(-) diff --git a/src/hotspot/cpu/x86/vm_version_x86.cpp b/src/hotspot/cpu/x86/vm_version_x86.cpp index cf9de40a237..7d9ceb9d446 100644 --- a/src/hotspot/cpu/x86/vm_version_x86.cpp +++ b/src/hotspot/cpu/x86/vm_version_x86.cpp @@ -2527,7 +2527,7 @@ const char* VM_Version::cpu_brand_string(void) { } int ret_val = cpu_extended_brand_string(_cpu_brand_string, CPU_EBS_MAX_LENGTH); if (ret_val != OS_OK) { - FREE_C_HEAP_ARRAY(char, _cpu_brand_string); + FREE_C_HEAP_ARRAY(_cpu_brand_string); _cpu_brand_string = nullptr; } } diff --git a/src/hotspot/os/aix/os_aix.cpp b/src/hotspot/os/aix/os_aix.cpp index 3cad24d388c..32d845b2b6d 100644 --- a/src/hotspot/os/aix/os_aix.cpp +++ b/src/hotspot/os/aix/os_aix.cpp @@ -578,13 +578,13 @@ void os::init_system_properties_values() { char *ld_library_path = NEW_C_HEAP_ARRAY(char, pathsize, mtInternal); os::snprintf_checked(ld_library_path, pathsize, "%s%s" DEFAULT_LIBPATH, v, v_colon); Arguments::set_library_path(ld_library_path); - FREE_C_HEAP_ARRAY(char, ld_library_path); + FREE_C_HEAP_ARRAY(ld_library_path); // Extensions directories. os::snprintf_checked(buf, bufsize, "%s" EXTENSIONS_DIR, Arguments::get_java_home()); Arguments::set_ext_dirs(buf); - FREE_C_HEAP_ARRAY(char, buf); + FREE_C_HEAP_ARRAY(buf); #undef DEFAULT_LIBPATH #undef EXTENSIONS_DIR diff --git a/src/hotspot/os/aix/os_perf_aix.cpp b/src/hotspot/os/aix/os_perf_aix.cpp index cbf78083483..3668ac6ba3f 100644 --- a/src/hotspot/os/aix/os_perf_aix.cpp +++ b/src/hotspot/os/aix/os_perf_aix.cpp @@ -258,10 +258,10 @@ bool CPUPerformanceInterface::CPUPerformance::initialize() { CPUPerformanceInterface::CPUPerformance::~CPUPerformance() { if (_lcpu_names) { - FREE_C_HEAP_ARRAY(perfstat_id_t, _lcpu_names); + FREE_C_HEAP_ARRAY(_lcpu_names); } if (_prev_ticks) { - FREE_C_HEAP_ARRAY(cpu_tick_store_t, _prev_ticks); + FREE_C_HEAP_ARRAY(_prev_ticks); } } @@ -511,12 +511,12 @@ CPUInformationInterface::~CPUInformationInterface() { if (_cpu_info != nullptr) { if (_cpu_info->cpu_name() != nullptr) { const char* cpu_name = _cpu_info->cpu_name(); - FREE_C_HEAP_ARRAY(char, cpu_name); + FREE_C_HEAP_ARRAY(cpu_name); _cpu_info->set_cpu_name(nullptr); } if (_cpu_info->cpu_description() != nullptr) { const char* cpu_desc = _cpu_info->cpu_description(); - FREE_C_HEAP_ARRAY(char, cpu_desc); + FREE_C_HEAP_ARRAY(cpu_desc); _cpu_info->set_cpu_description(nullptr); } delete _cpu_info; @@ -576,7 +576,7 @@ int NetworkPerformanceInterface::NetworkPerformance::network_utilization(Network // check for error if (n_records < 0) { - FREE_C_HEAP_ARRAY(perfstat_netinterface_t, net_stats); + FREE_C_HEAP_ARRAY(net_stats); return OS_ERR; } @@ -593,7 +593,7 @@ int NetworkPerformanceInterface::NetworkPerformance::network_utilization(Network *network_interfaces = new_interface; } - FREE_C_HEAP_ARRAY(perfstat_netinterface_t, net_stats); + FREE_C_HEAP_ARRAY(net_stats); return OS_OK; } diff --git a/src/hotspot/os/bsd/os_bsd.cpp b/src/hotspot/os/bsd/os_bsd.cpp index a4d9a2197a5..4c77b619718 100644 --- a/src/hotspot/os/bsd/os_bsd.cpp +++ b/src/hotspot/os/bsd/os_bsd.cpp @@ -444,14 +444,14 @@ void os::init_system_properties_values() { char *ld_library_path = NEW_C_HEAP_ARRAY(char, ld_library_path_size, mtInternal); os::snprintf_checked(ld_library_path, ld_library_path_size, "%s%s" SYS_EXT_DIR "/lib/%s:" DEFAULT_LIBPATH, v, v_colon, cpu_arch); Arguments::set_library_path(ld_library_path); - FREE_C_HEAP_ARRAY(char, ld_library_path); + FREE_C_HEAP_ARRAY(ld_library_path); } // Extensions directories. os::snprintf_checked(buf, bufsize, "%s" EXTENSIONS_DIR ":" SYS_EXT_DIR EXTENSIONS_DIR, Arguments::get_java_home()); Arguments::set_ext_dirs(buf); - FREE_C_HEAP_ARRAY(char, buf); + FREE_C_HEAP_ARRAY(buf); #else // __APPLE__ @@ -538,7 +538,7 @@ void os::init_system_properties_values() { os::snprintf_checked(ld_library_path, ld_library_path_size, "%s%s%s%s%s" SYS_EXTENSIONS_DIR ":" SYS_EXTENSIONS_DIRS ":.", v, v_colon, l, l_colon, user_home_dir); Arguments::set_library_path(ld_library_path); - FREE_C_HEAP_ARRAY(char, ld_library_path); + FREE_C_HEAP_ARRAY(ld_library_path); } // Extensions directories. @@ -550,7 +550,7 @@ void os::init_system_properties_values() { user_home_dir, Arguments::get_java_home()); Arguments::set_ext_dirs(buf); - FREE_C_HEAP_ARRAY(char, buf); + FREE_C_HEAP_ARRAY(buf); #undef SYS_EXTENSIONS_DIR #undef SYS_EXTENSIONS_DIRS diff --git a/src/hotspot/os/bsd/os_perf_bsd.cpp b/src/hotspot/os/bsd/os_perf_bsd.cpp index 78d9519c3a7..47fe3a0d7e9 100644 --- a/src/hotspot/os/bsd/os_perf_bsd.cpp +++ b/src/hotspot/os/bsd/os_perf_bsd.cpp @@ -301,7 +301,7 @@ int SystemProcessInterface::SystemProcesses::system_processes(SystemProcess** sy pids_bytes = proc_listpids(PROC_ALL_PIDS, 0, pids, pids_bytes); if (pids_bytes <= 0) { // couldn't fit buffer, retry. - FREE_RESOURCE_ARRAY(pid_t, pids, pid_count); + FREE_RESOURCE_ARRAY(pids, pid_count); pids = nullptr; try_count++; if (try_count > 3) { @@ -381,12 +381,12 @@ CPUInformationInterface::~CPUInformationInterface() { if (_cpu_info != nullptr) { if (_cpu_info->cpu_name() != nullptr) { const char* cpu_name = _cpu_info->cpu_name(); - FREE_C_HEAP_ARRAY(char, cpu_name); + FREE_C_HEAP_ARRAY(cpu_name); _cpu_info->set_cpu_name(nullptr); } if (_cpu_info->cpu_description() != nullptr) { const char* cpu_desc = _cpu_info->cpu_description(); - FREE_C_HEAP_ARRAY(char, cpu_desc); + FREE_C_HEAP_ARRAY(cpu_desc); _cpu_info->set_cpu_description(nullptr); } delete _cpu_info; diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index a87c0ab33fa..6927f5108ac 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -710,14 +710,14 @@ void os::init_system_properties_values() { char *ld_library_path = NEW_C_HEAP_ARRAY(char, pathsize, mtInternal); os::snprintf_checked(ld_library_path, pathsize, "%s%s" SYS_EXT_DIR "/lib:" DEFAULT_LIBPATH, v, v_colon); Arguments::set_library_path(ld_library_path); - FREE_C_HEAP_ARRAY(char, ld_library_path); + FREE_C_HEAP_ARRAY(ld_library_path); } // Extensions directories. os::snprintf_checked(buf, bufsize, "%s" EXTENSIONS_DIR ":" SYS_EXT_DIR EXTENSIONS_DIR, Arguments::get_java_home()); Arguments::set_ext_dirs(buf); - FREE_C_HEAP_ARRAY(char, buf); + FREE_C_HEAP_ARRAY(buf); #undef DEFAULT_LIBPATH #undef SYS_EXT_DIR @@ -3435,7 +3435,7 @@ void os::Linux::rebuild_cpu_to_node_map() { } } } - FREE_C_HEAP_ARRAY(unsigned long, cpu_map); + FREE_C_HEAP_ARRAY(cpu_map); } int os::Linux::numa_node_to_cpus(int node, unsigned long *buffer, int bufferlen) { diff --git a/src/hotspot/os/linux/os_perf_linux.cpp b/src/hotspot/os/linux/os_perf_linux.cpp index 9f91f3b4c0d..c0e863ed2a2 100644 --- a/src/hotspot/os/linux/os_perf_linux.cpp +++ b/src/hotspot/os/linux/os_perf_linux.cpp @@ -545,7 +545,7 @@ bool CPUPerformanceInterface::CPUPerformance::initialize() { CPUPerformanceInterface::CPUPerformance::~CPUPerformance() { if (_counters.cpus != nullptr) { - FREE_C_HEAP_ARRAY(char, _counters.cpus); + FREE_C_HEAP_ARRAY(_counters.cpus); } } @@ -811,7 +811,7 @@ int SystemProcessInterface::SystemProcesses::ProcessIterator::current(SystemProc cmdline = get_cmdline(); if (cmdline != nullptr) { process_info->set_command_line(allocate_string(cmdline)); - FREE_C_HEAP_ARRAY(char, cmdline); + FREE_C_HEAP_ARRAY(cmdline); } return OS_OK; @@ -937,12 +937,12 @@ CPUInformationInterface::~CPUInformationInterface() { if (_cpu_info != nullptr) { if (_cpu_info->cpu_name() != nullptr) { const char* cpu_name = _cpu_info->cpu_name(); - FREE_C_HEAP_ARRAY(char, cpu_name); + FREE_C_HEAP_ARRAY(cpu_name); _cpu_info->set_cpu_name(nullptr); } if (_cpu_info->cpu_description() != nullptr) { const char* cpu_desc = _cpu_info->cpu_description(); - FREE_C_HEAP_ARRAY(char, cpu_desc); + FREE_C_HEAP_ARRAY(cpu_desc); _cpu_info->set_cpu_description(nullptr); } delete _cpu_info; diff --git a/src/hotspot/os/linux/procMapsParser.cpp b/src/hotspot/os/linux/procMapsParser.cpp index 0663cae61f3..00675683e34 100644 --- a/src/hotspot/os/linux/procMapsParser.cpp +++ b/src/hotspot/os/linux/procMapsParser.cpp @@ -45,7 +45,7 @@ ProcSmapsParser::ProcSmapsParser(FILE* f) : } ProcSmapsParser::~ProcSmapsParser() { - FREE_C_HEAP_ARRAY(char, _line); + FREE_C_HEAP_ARRAY(_line); } bool ProcSmapsParser::read_line() { diff --git a/src/hotspot/os/posix/perfMemory_posix.cpp b/src/hotspot/os/posix/perfMemory_posix.cpp index c5046797e02..300c86ffc47 100644 --- a/src/hotspot/os/posix/perfMemory_posix.cpp +++ b/src/hotspot/os/posix/perfMemory_posix.cpp @@ -118,7 +118,7 @@ static void save_memory_to_file(char* addr, size_t size) { } } } - FREE_C_HEAP_ARRAY(char, destfile); + FREE_C_HEAP_ARRAY(destfile); } @@ -483,14 +483,14 @@ static char* get_user_name(uid_t uid) { p->pw_name == nullptr ? "pw_name = null" : "pw_name zero length"); } } - FREE_C_HEAP_ARRAY(char, pwbuf); + FREE_C_HEAP_ARRAY(pwbuf); return nullptr; } char* user_name = NEW_C_HEAP_ARRAY(char, strlen(p->pw_name) + 1, mtInternal); strcpy(user_name, p->pw_name); - FREE_C_HEAP_ARRAY(char, pwbuf); + FREE_C_HEAP_ARRAY(pwbuf); return user_name; } @@ -572,7 +572,7 @@ static char* get_user_name_slow(int vmid, int nspid, TRAPS) { DIR* subdirp = open_directory_secure(usrdir_name); if (subdirp == nullptr) { - FREE_C_HEAP_ARRAY(char, usrdir_name); + FREE_C_HEAP_ARRAY(usrdir_name); continue; } @@ -583,7 +583,7 @@ static char* get_user_name_slow(int vmid, int nspid, TRAPS) { // symlink can be exploited. // if (!is_directory_secure(usrdir_name)) { - FREE_C_HEAP_ARRAY(char, usrdir_name); + FREE_C_HEAP_ARRAY(usrdir_name); os::closedir(subdirp); continue; } @@ -607,13 +607,13 @@ static char* get_user_name_slow(int vmid, int nspid, TRAPS) { // don't follow symbolic links for the file RESTARTABLE(::lstat(filename, &statbuf), result); if (result == OS_ERR) { - FREE_C_HEAP_ARRAY(char, filename); + FREE_C_HEAP_ARRAY(filename); continue; } // skip over files that are not regular files. if (!S_ISREG(statbuf.st_mode)) { - FREE_C_HEAP_ARRAY(char, filename); + FREE_C_HEAP_ARRAY(filename); continue; } @@ -623,7 +623,7 @@ static char* get_user_name_slow(int vmid, int nspid, TRAPS) { if (statbuf.st_ctime > oldest_ctime) { char* user = strchr(dentry->d_name, '_') + 1; - FREE_C_HEAP_ARRAY(char, oldest_user); + FREE_C_HEAP_ARRAY(oldest_user); oldest_user = NEW_C_HEAP_ARRAY(char, strlen(user)+1, mtInternal); strcpy(oldest_user, user); @@ -631,11 +631,11 @@ static char* get_user_name_slow(int vmid, int nspid, TRAPS) { } } - FREE_C_HEAP_ARRAY(char, filename); + FREE_C_HEAP_ARRAY(filename); } } os::closedir(subdirp); - FREE_C_HEAP_ARRAY(char, usrdir_name); + FREE_C_HEAP_ARRAY(usrdir_name); } os::closedir(tmpdirp); @@ -1105,11 +1105,11 @@ static char* mmap_create_shared(size_t size) { log_info(perf, memops)("Trying to open %s/%s", dirname, short_filename); fd = create_sharedmem_file(dirname, short_filename, size); - FREE_C_HEAP_ARRAY(char, user_name); - FREE_C_HEAP_ARRAY(char, dirname); + FREE_C_HEAP_ARRAY(user_name); + FREE_C_HEAP_ARRAY(dirname); if (fd == -1) { - FREE_C_HEAP_ARRAY(char, filename); + FREE_C_HEAP_ARRAY(filename); return nullptr; } @@ -1121,7 +1121,7 @@ static char* mmap_create_shared(size_t size) { if (mapAddress == MAP_FAILED) { log_debug(perf)("mmap failed - %s", os::strerror(errno)); remove_file(filename); - FREE_C_HEAP_ARRAY(char, filename); + FREE_C_HEAP_ARRAY(filename); return nullptr; } @@ -1171,7 +1171,7 @@ static void delete_shared_memory(char* addr, size_t size) { remove_file(backing_store_file_name); // Don't.. Free heap memory could deadlock os::abort() if it is called // from signal handler. OS will reclaim the heap memory. - // FREE_C_HEAP_ARRAY(char, backing_store_file_name); + // FREE_C_HEAP_ARRAY(backing_store_file_name); backing_store_file_name = nullptr; } } @@ -1223,8 +1223,8 @@ static void mmap_attach_shared(int vmid, char** addr, size_t* sizep, TRAPS) { // store file, we don't follow them when attaching either. // if (!is_directory_secure(dirname)) { - FREE_C_HEAP_ARRAY(char, dirname); - FREE_C_HEAP_ARRAY(char, luser); + FREE_C_HEAP_ARRAY(dirname); + FREE_C_HEAP_ARRAY(luser); THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "Process not found"); } @@ -1236,9 +1236,9 @@ static void mmap_attach_shared(int vmid, char** addr, size_t* sizep, TRAPS) { int fd = open_sharedmem_file(filename, file_flags, THREAD); // free the c heap resources that are no longer needed - FREE_C_HEAP_ARRAY(char, luser); - FREE_C_HEAP_ARRAY(char, dirname); - FREE_C_HEAP_ARRAY(char, filename); + FREE_C_HEAP_ARRAY(luser); + FREE_C_HEAP_ARRAY(dirname); + FREE_C_HEAP_ARRAY(filename); if (HAS_PENDING_EXCEPTION) { assert(fd == OS_ERR, "open_sharedmem_file always return OS_ERR on exceptions"); diff --git a/src/hotspot/os/windows/os_perf_windows.cpp b/src/hotspot/os/windows/os_perf_windows.cpp index 9d04ae65954..59ea83b9148 100644 --- a/src/hotspot/os/windows/os_perf_windows.cpp +++ b/src/hotspot/os/windows/os_perf_windows.cpp @@ -178,9 +178,9 @@ static void destroy(MultiCounterQueryP query) { for (int i = 0; i < query->noOfCounters; ++i) { close_query(nullptr, &query->counters[i]); } - FREE_C_HEAP_ARRAY(char, query->counters); + FREE_C_HEAP_ARRAY(query->counters); close_query(&query->query.pdh_query_handle, nullptr); - FREE_C_HEAP_ARRAY(MultiCounterQueryS, query); + FREE_C_HEAP_ARRAY(query); } } @@ -189,15 +189,15 @@ static void destroy_query_set(MultiCounterQuerySetP query_set) { for (int j = 0; j < query_set->queries[i].noOfCounters; ++j) { close_query(nullptr, &query_set->queries[i].counters[j]); } - FREE_C_HEAP_ARRAY(char, query_set->queries[i].counters); + FREE_C_HEAP_ARRAY(query_set->queries[i].counters); close_query(&query_set->queries[i].query.pdh_query_handle, nullptr); } - FREE_C_HEAP_ARRAY(MultiCounterQueryS, query_set->queries); + FREE_C_HEAP_ARRAY(query_set->queries); } static void destroy(MultiCounterQuerySetP query) { destroy_query_set(query); - FREE_C_HEAP_ARRAY(MultiCounterQuerySetS, query); + FREE_C_HEAP_ARRAY(query); } static void destroy(ProcessQueryP query) { @@ -229,7 +229,7 @@ static void allocate_counters(ProcessQueryP query, size_t nofCounters) { } static void deallocate_counters(MultiCounterQueryP query) { - FREE_C_HEAP_ARRAY(char, query->counters); + FREE_C_HEAP_ARRAY(query->counters); query->counters = nullptr; query->noOfCounters = 0; } @@ -710,11 +710,11 @@ static const char* pdh_process_image_name() { } static void deallocate_pdh_constants() { - FREE_C_HEAP_ARRAY(char, process_image_name); + FREE_C_HEAP_ARRAY(process_image_name); process_image_name = nullptr; - FREE_C_HEAP_ARRAY(char, pdh_process_instance_IDProcess_counter_fmt); + FREE_C_HEAP_ARRAY(pdh_process_instance_IDProcess_counter_fmt); pdh_process_instance_IDProcess_counter_fmt = nullptr; - FREE_C_HEAP_ARRAY(char, pdh_process_instance_wildcard_IDProcess_counter); + FREE_C_HEAP_ARRAY(pdh_process_instance_wildcard_IDProcess_counter); pdh_process_instance_wildcard_IDProcess_counter = nullptr; } @@ -1445,9 +1445,9 @@ bool CPUInformationInterface::initialize() { CPUInformationInterface::~CPUInformationInterface() { if (_cpu_info != nullptr) { - FREE_C_HEAP_ARRAY(char, _cpu_info->cpu_name()); + FREE_C_HEAP_ARRAY(_cpu_info->cpu_name()); _cpu_info->set_cpu_name(nullptr); - FREE_C_HEAP_ARRAY(char, _cpu_info->cpu_description()); + FREE_C_HEAP_ARRAY(_cpu_info->cpu_description()); _cpu_info->set_cpu_description(nullptr); delete _cpu_info; } diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index 9d8fb45f0d1..9a987bf3762 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -334,14 +334,14 @@ void os::init_system_properties_values() { home_path = NEW_C_HEAP_ARRAY(char, strlen(home_dir) + 1, mtInternal); strcpy(home_path, home_dir); Arguments::set_java_home(home_path); - FREE_C_HEAP_ARRAY(char, home_path); + FREE_C_HEAP_ARRAY(home_path); dll_path = NEW_C_HEAP_ARRAY(char, strlen(home_dir) + strlen(bin) + 1, mtInternal); strcpy(dll_path, home_dir); strcat(dll_path, bin); Arguments::set_dll_dir(dll_path); - FREE_C_HEAP_ARRAY(char, dll_path); + FREE_C_HEAP_ARRAY(dll_path); if (!set_boot_path('\\', ';')) { vm_exit_during_initialization("Failed setting boot class path.", nullptr); @@ -396,7 +396,7 @@ void os::init_system_properties_values() { strcat(library_path, ";."); Arguments::set_library_path(library_path); - FREE_C_HEAP_ARRAY(char, library_path); + FREE_C_HEAP_ARRAY(library_path); } // Default extensions directory @@ -1079,7 +1079,7 @@ void os::set_native_thread_name(const char *name) { HRESULT hr = _SetThreadDescription(current, unicode_name); if (FAILED(hr)) { log_debug(os, thread)("set_native_thread_name: SetThreadDescription failed - falling back to debugger method"); - FREE_C_HEAP_ARRAY(WCHAR, unicode_name); + FREE_C_HEAP_ARRAY(unicode_name); } else { log_trace(os, thread)("set_native_thread_name: SetThreadDescription succeeded - new name: %s", name); @@ -1102,7 +1102,7 @@ void os::set_native_thread_name(const char *name) { LocalFree(thread_name); } #endif - FREE_C_HEAP_ARRAY(WCHAR, unicode_name); + FREE_C_HEAP_ARRAY(unicode_name); return; } } else { @@ -2897,7 +2897,7 @@ class NUMANodeListHolder { int _numa_used_node_count; void free_node_list() { - FREE_C_HEAP_ARRAY(int, _numa_used_node_list); + FREE_C_HEAP_ARRAY(_numa_used_node_list); } public: @@ -4744,7 +4744,7 @@ static wchar_t* wide_abs_unc_path(char const* path, errno_t & err, int additiona LPWSTR unicode_path = nullptr; err = convert_to_unicode(buf, &unicode_path); - FREE_C_HEAP_ARRAY(char, buf); + FREE_C_HEAP_ARRAY(buf); if (err != ERROR_SUCCESS) { return nullptr; } @@ -4772,9 +4772,9 @@ static wchar_t* wide_abs_unc_path(char const* path, errno_t & err, int additiona } if (converted_path != unicode_path) { - FREE_C_HEAP_ARRAY(WCHAR, converted_path); + FREE_C_HEAP_ARRAY(converted_path); } - FREE_C_HEAP_ARRAY(WCHAR, unicode_path); + FREE_C_HEAP_ARRAY(unicode_path); return static_cast(result); // LPWSTR and wchat_t* are the same type on Windows. } @@ -5827,7 +5827,7 @@ int os::fork_and_exec(const char* cmd) { exit_code = -1; } - FREE_C_HEAP_ARRAY(char, cmd_string); + FREE_C_HEAP_ARRAY(cmd_string); return (int)exit_code; } diff --git a/src/hotspot/os/windows/perfMemory_windows.cpp b/src/hotspot/os/windows/perfMemory_windows.cpp index dad2804f18a..8e698c53d28 100644 --- a/src/hotspot/os/windows/perfMemory_windows.cpp +++ b/src/hotspot/os/windows/perfMemory_windows.cpp @@ -113,7 +113,7 @@ static void save_memory_to_file(char* addr, size_t size) { } } - FREE_C_HEAP_ARRAY(char, destfile); + FREE_C_HEAP_ARRAY(destfile); } // Shared Memory Implementation Details @@ -319,7 +319,7 @@ static char* get_user_name_slow(int vmid) { DIR* subdirp = os::opendir(usrdir_name); if (subdirp == nullptr) { - FREE_C_HEAP_ARRAY(char, usrdir_name); + FREE_C_HEAP_ARRAY(usrdir_name); continue; } @@ -330,7 +330,7 @@ static char* get_user_name_slow(int vmid) { // symlink can be exploited. // if (!is_directory_secure(usrdir_name)) { - FREE_C_HEAP_ARRAY(char, usrdir_name); + FREE_C_HEAP_ARRAY(usrdir_name); os::closedir(subdirp); continue; } @@ -350,13 +350,13 @@ static char* get_user_name_slow(int vmid) { strcat(filename, udentry->d_name); if (::stat(filename, &statbuf) == OS_ERR) { - FREE_C_HEAP_ARRAY(char, filename); + FREE_C_HEAP_ARRAY(filename); continue; } // skip over files that are not regular files. if ((statbuf.st_mode & S_IFMT) != S_IFREG) { - FREE_C_HEAP_ARRAY(char, filename); + FREE_C_HEAP_ARRAY(filename); continue; } @@ -378,18 +378,18 @@ static char* get_user_name_slow(int vmid) { if (statbuf.st_ctime > latest_ctime) { char* user = strchr(dentry->d_name, '_') + 1; - FREE_C_HEAP_ARRAY(char, latest_user); + FREE_C_HEAP_ARRAY(latest_user); latest_user = NEW_C_HEAP_ARRAY(char, strlen(user)+1, mtInternal); strcpy(latest_user, user); latest_ctime = statbuf.st_ctime; } - FREE_C_HEAP_ARRAY(char, filename); + FREE_C_HEAP_ARRAY(filename); } } os::closedir(subdirp); - FREE_C_HEAP_ARRAY(char, usrdir_name); + FREE_C_HEAP_ARRAY(usrdir_name); } os::closedir(tmpdirp); @@ -481,7 +481,7 @@ static void remove_file(const char* dirname, const char* filename) { } } - FREE_C_HEAP_ARRAY(char, path); + FREE_C_HEAP_ARRAY(path); } // returns true if the process represented by pid is alive, otherwise @@ -708,11 +708,11 @@ static void free_security_desc(PSECURITY_DESCRIPTOR pSD) { // be an ACL we enlisted. free the resources. // if (success && exists && pACL != nullptr && !isdefault) { - FREE_C_HEAP_ARRAY(char, pACL); + FREE_C_HEAP_ARRAY(pACL); } // free the security descriptor - FREE_C_HEAP_ARRAY(char, pSD); + FREE_C_HEAP_ARRAY(pSD); } } @@ -768,7 +768,7 @@ static PSID get_user_sid(HANDLE hProcess) { if (!GetTokenInformation(hAccessToken, TokenUser, token_buf, rsize, &rsize)) { log_debug(perf)("GetTokenInformation failure: lasterror = %d, rsize = %d", GetLastError(), rsize); - FREE_C_HEAP_ARRAY(char, token_buf); + FREE_C_HEAP_ARRAY(token_buf); CloseHandle(hAccessToken); return nullptr; } @@ -779,15 +779,15 @@ static PSID get_user_sid(HANDLE hProcess) { if (!CopySid(nbytes, pSID, token_buf->User.Sid)) { log_debug(perf)("GetTokenInformation failure: lasterror = %d, rsize = %d", GetLastError(), rsize); - FREE_C_HEAP_ARRAY(char, token_buf); - FREE_C_HEAP_ARRAY(char, pSID); + FREE_C_HEAP_ARRAY(token_buf); + FREE_C_HEAP_ARRAY(pSID); CloseHandle(hAccessToken); return nullptr; } // close the access token. CloseHandle(hAccessToken); - FREE_C_HEAP_ARRAY(char, token_buf); + FREE_C_HEAP_ARRAY(token_buf); return pSID; } @@ -865,7 +865,7 @@ static bool add_allow_aces(PSECURITY_DESCRIPTOR pSD, if (!InitializeAcl(newACL, newACLsize, ACL_REVISION)) { log_debug(perf)("InitializeAcl failure: lasterror = %d", GetLastError()); - FREE_C_HEAP_ARRAY(char, newACL); + FREE_C_HEAP_ARRAY(newACL); return false; } @@ -876,7 +876,7 @@ static bool add_allow_aces(PSECURITY_DESCRIPTOR pSD, LPVOID ace; if (!GetAce(oldACL, ace_index, &ace)) { log_debug(perf)("InitializeAcl failure: lasterror = %d", GetLastError()); - FREE_C_HEAP_ARRAY(char, newACL); + FREE_C_HEAP_ARRAY(newACL); return false; } if (((ACCESS_ALLOWED_ACE *)ace)->Header.AceFlags && INHERITED_ACE) { @@ -901,7 +901,7 @@ static bool add_allow_aces(PSECURITY_DESCRIPTOR pSD, if (!AddAce(newACL, ACL_REVISION, MAXDWORD, ace, ((PACE_HEADER)ace)->AceSize)) { log_debug(perf)("AddAce failure: lasterror = %d", GetLastError()); - FREE_C_HEAP_ARRAY(char, newACL); + FREE_C_HEAP_ARRAY(newACL); return false; } } @@ -915,7 +915,7 @@ static bool add_allow_aces(PSECURITY_DESCRIPTOR pSD, aces[i].mask, aces[i].pSid)) { log_debug(perf)("AddAccessAllowedAce failure: lasterror = %d", GetLastError()); - FREE_C_HEAP_ARRAY(char, newACL); + FREE_C_HEAP_ARRAY(newACL); return false; } } @@ -928,13 +928,13 @@ static bool add_allow_aces(PSECURITY_DESCRIPTOR pSD, LPVOID ace; if (!GetAce(oldACL, ace_index, &ace)) { log_debug(perf)("InitializeAcl failure: lasterror = %d", GetLastError()); - FREE_C_HEAP_ARRAY(char, newACL); + FREE_C_HEAP_ARRAY(newACL); return false; } if (!AddAce(newACL, ACL_REVISION, MAXDWORD, ace, ((PACE_HEADER)ace)->AceSize)) { log_debug(perf)("AddAce failure: lasterror = %d", GetLastError()); - FREE_C_HEAP_ARRAY(char, newACL); + FREE_C_HEAP_ARRAY(newACL); return false; } ace_index++; @@ -944,7 +944,7 @@ static bool add_allow_aces(PSECURITY_DESCRIPTOR pSD, // add the new ACL to the security descriptor. if (!SetSecurityDescriptorDacl(pSD, TRUE, newACL, FALSE)) { log_debug(perf)("SetSecurityDescriptorDacl failure: lasterror = %d", GetLastError()); - FREE_C_HEAP_ARRAY(char, newACL); + FREE_C_HEAP_ARRAY(newACL); return false; } @@ -952,7 +952,7 @@ static bool add_allow_aces(PSECURITY_DESCRIPTOR pSD, // protected prevents that. if (!SetSecurityDescriptorControl(pSD, SE_DACL_PROTECTED, SE_DACL_PROTECTED)) { log_debug(perf)("SetSecurityDescriptorControl failure: lasterror = %d", GetLastError()); - FREE_C_HEAP_ARRAY(char, newACL); + FREE_C_HEAP_ARRAY(newACL); return false; } @@ -1057,7 +1057,7 @@ static LPSECURITY_ATTRIBUTES make_user_everybody_admin_security_attr( // create a security attributes structure with access control // entries as initialized above. LPSECURITY_ATTRIBUTES lpSA = make_security_attr(aces, 3); - FREE_C_HEAP_ARRAY(char, aces[0].pSid); + FREE_C_HEAP_ARRAY(aces[0].pSid); FreeSid(everybodySid); FreeSid(administratorsSid); return(lpSA); @@ -1341,8 +1341,8 @@ static char* mapping_create_shared(size_t size) { // check that the file system is secure - i.e. it supports ACLs. if (!is_filesystem_secure(dirname)) { - FREE_C_HEAP_ARRAY(char, dirname); - FREE_C_HEAP_ARRAY(char, user); + FREE_C_HEAP_ARRAY(dirname); + FREE_C_HEAP_ARRAY(user); return nullptr; } @@ -1358,15 +1358,15 @@ static char* mapping_create_shared(size_t size) { assert(((size != 0) && (size % os::vm_page_size() == 0)), "unexpected PerfMemry region size"); - FREE_C_HEAP_ARRAY(char, user); + FREE_C_HEAP_ARRAY(user); // create the shared memory resources sharedmem_fileMapHandle = create_sharedmem_resources(dirname, filename, objectname, size); - FREE_C_HEAP_ARRAY(char, filename); - FREE_C_HEAP_ARRAY(char, objectname); - FREE_C_HEAP_ARRAY(char, dirname); + FREE_C_HEAP_ARRAY(filename); + FREE_C_HEAP_ARRAY(objectname); + FREE_C_HEAP_ARRAY(dirname); if (sharedmem_fileMapHandle == nullptr) { return nullptr; @@ -1480,8 +1480,8 @@ static void open_file_mapping(int vmid, char** addrp, size_t* sizep, TRAPS) { // store file, we also don't following them when attaching // if (!is_directory_secure(dirname)) { - FREE_C_HEAP_ARRAY(char, dirname); - FREE_C_HEAP_ARRAY(char, luser); + FREE_C_HEAP_ARRAY(dirname); + FREE_C_HEAP_ARRAY(luser); THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "Process not found"); } @@ -1498,10 +1498,10 @@ static void open_file_mapping(int vmid, char** addrp, size_t* sizep, TRAPS) { char* robjectname = ResourceArea::strdup(THREAD, objectname); // free the c heap resources that are no longer needed - FREE_C_HEAP_ARRAY(char, luser); - FREE_C_HEAP_ARRAY(char, dirname); - FREE_C_HEAP_ARRAY(char, filename); - FREE_C_HEAP_ARRAY(char, objectname); + FREE_C_HEAP_ARRAY(luser); + FREE_C_HEAP_ARRAY(dirname); + FREE_C_HEAP_ARRAY(filename); + FREE_C_HEAP_ARRAY(objectname); size_t size; if (*sizep == 0) { diff --git a/src/hotspot/share/asm/codeBuffer.cpp b/src/hotspot/share/asm/codeBuffer.cpp index 854cf73049b..c6475050592 100644 --- a/src/hotspot/share/asm/codeBuffer.cpp +++ b/src/hotspot/share/asm/codeBuffer.cpp @@ -417,7 +417,7 @@ void CodeSection::expand_locs(int new_capacity) { new_capacity = old_capacity * 2; relocInfo* locs_start; if (_locs_own) { - locs_start = REALLOC_RESOURCE_ARRAY(relocInfo, _locs_start, old_capacity, new_capacity); + locs_start = REALLOC_RESOURCE_ARRAY(_locs_start, old_capacity, new_capacity); } else { locs_start = NEW_RESOURCE_ARRAY(relocInfo, new_capacity); Copy::conjoint_jbytes(_locs_start, locs_start, old_capacity * sizeof(relocInfo)); diff --git a/src/hotspot/share/cds/aotStreamedHeapLoader.cpp b/src/hotspot/share/cds/aotStreamedHeapLoader.cpp index 39f735543cd..7f9f8cf0628 100644 --- a/src/hotspot/share/cds/aotStreamedHeapLoader.cpp +++ b/src/hotspot/share/cds/aotStreamedHeapLoader.cpp @@ -797,7 +797,7 @@ void AOTStreamedHeapLoader::cleanup() { Universe::vm_global()->release(&handles[num_null_handles], num_handles - num_null_handles); } - FREE_C_HEAP_ARRAY(void*, _object_index_to_heap_object_table); + FREE_C_HEAP_ARRAY(_object_index_to_heap_object_table); // Unmap regions FileMapInfo::current_info()->unmap_region(AOTMetaspace::hp); diff --git a/src/hotspot/share/cds/archiveBuilder.cpp b/src/hotspot/share/cds/archiveBuilder.cpp index 21eef3d7b0b..cf51897c2f1 100644 --- a/src/hotspot/share/cds/archiveBuilder.cpp +++ b/src/hotspot/share/cds/archiveBuilder.cpp @@ -1171,7 +1171,7 @@ void ArchiveBuilder::write_archive(FileMapInfo* mapinfo, AOTMappedHeapInfo* mapp AOTMapLogger::dumptime_log(this, mapinfo, mapped_heap_info, streamed_heap_info, bitmap, bitmap_size_in_bytes); } CDS_JAVA_HEAP_ONLY(HeapShared::destroy_archived_object_cache()); - FREE_C_HEAP_ARRAY(char, bitmap); + FREE_C_HEAP_ARRAY(bitmap); } void ArchiveBuilder::write_region(FileMapInfo* mapinfo, int region_idx, DumpRegion* dump_region, bool read_only, bool allow_exec) { diff --git a/src/hotspot/share/cds/cdsConfig.cpp b/src/hotspot/share/cds/cdsConfig.cpp index ecf3c6d2231..21066f76932 100644 --- a/src/hotspot/share/cds/cdsConfig.cpp +++ b/src/hotspot/share/cds/cdsConfig.cpp @@ -520,7 +520,7 @@ static void substitute_aot_filename(JVMFlagsEnum flag_enum) { JVMFlag::Error err = JVMFlagAccess::set_ccstr(flag, &new_filename, JVMFlagOrigin::ERGONOMIC); assert(err == JVMFlag::SUCCESS, "must never fail"); } - FREE_C_HEAP_ARRAY(char, new_filename); + FREE_C_HEAP_ARRAY(new_filename); } void CDSConfig::check_aotmode_record() { diff --git a/src/hotspot/share/cds/classListWriter.cpp b/src/hotspot/share/cds/classListWriter.cpp index 8e1f298e8e3..c90e233df73 100644 --- a/src/hotspot/share/cds/classListWriter.cpp +++ b/src/hotspot/share/cds/classListWriter.cpp @@ -49,7 +49,7 @@ void ClassListWriter::init() { _classlist_file->print_cr("# This file is generated via the -XX:DumpLoadedClassList= option"); _classlist_file->print_cr("# and is used at CDS archive dump time (see -Xshare:dump)."); _classlist_file->print_cr("#"); - FREE_C_HEAP_ARRAY(char, list_name); + FREE_C_HEAP_ARRAY(list_name); } } diff --git a/src/hotspot/share/cds/filemap.cpp b/src/hotspot/share/cds/filemap.cpp index 38502b2b2d8..186dca4fa13 100644 --- a/src/hotspot/share/cds/filemap.cpp +++ b/src/hotspot/share/cds/filemap.cpp @@ -402,7 +402,7 @@ public: ~FileHeaderHelper() { if (_header != nullptr) { - FREE_C_HEAP_ARRAY(char, _header); + FREE_C_HEAP_ARRAY(_header); } if (_fd != -1) { ::close(_fd); diff --git a/src/hotspot/share/ci/ciReplay.cpp b/src/hotspot/share/ci/ciReplay.cpp index 6266c024260..35522e75877 100644 --- a/src/hotspot/share/ci/ciReplay.cpp +++ b/src/hotspot/share/ci/ciReplay.cpp @@ -600,7 +600,7 @@ class CompileReplay : public StackObj { _nesting.check(); // Check if a reallocation in the resource arena is safe int new_length = _buffer_length * 2; // Next call will throw error in case of OOM. - _buffer = REALLOC_RESOURCE_ARRAY(char, _buffer, _buffer_length, new_length); + _buffer = REALLOC_RESOURCE_ARRAY(_buffer, _buffer_length, new_length); _buffer_length = new_length; } if (c == '\n') { diff --git a/src/hotspot/share/classfile/classFileParser.cpp b/src/hotspot/share/classfile/classFileParser.cpp index a9ea6fbea11..d5ee16fec32 100644 --- a/src/hotspot/share/classfile/classFileParser.cpp +++ b/src/hotspot/share/classfile/classFileParser.cpp @@ -2363,8 +2363,8 @@ Method* ClassFileParser::parse_method(const ClassFileStream* const cfs, } if (lvt_cnt == max_lvt_cnt) { max_lvt_cnt <<= 1; - localvariable_table_length = REALLOC_RESOURCE_ARRAY(u2, localvariable_table_length, lvt_cnt, max_lvt_cnt); - localvariable_table_start = REALLOC_RESOURCE_ARRAY(const unsafe_u2*, localvariable_table_start, lvt_cnt, max_lvt_cnt); + localvariable_table_length = REALLOC_RESOURCE_ARRAY(localvariable_table_length, lvt_cnt, max_lvt_cnt); + localvariable_table_start = REALLOC_RESOURCE_ARRAY(localvariable_table_start, lvt_cnt, max_lvt_cnt); } localvariable_table_start[lvt_cnt] = parse_localvariable_table(cfs, @@ -2393,8 +2393,8 @@ Method* ClassFileParser::parse_method(const ClassFileStream* const cfs, // Parse local variable type table if (lvtt_cnt == max_lvtt_cnt) { max_lvtt_cnt <<= 1; - localvariable_type_table_length = REALLOC_RESOURCE_ARRAY(u2, localvariable_type_table_length, lvtt_cnt, max_lvtt_cnt); - localvariable_type_table_start = REALLOC_RESOURCE_ARRAY(const unsafe_u2*, localvariable_type_table_start, lvtt_cnt, max_lvtt_cnt); + localvariable_type_table_length = REALLOC_RESOURCE_ARRAY(localvariable_type_table_length, lvtt_cnt, max_lvtt_cnt); + localvariable_type_table_start = REALLOC_RESOURCE_ARRAY(localvariable_type_table_start, lvtt_cnt, max_lvtt_cnt); } localvariable_type_table_start[lvtt_cnt] = parse_localvariable_table(cfs, diff --git a/src/hotspot/share/classfile/classLoader.cpp b/src/hotspot/share/classfile/classLoader.cpp index eced83577cb..c19a1770aef 100644 --- a/src/hotspot/share/classfile/classLoader.cpp +++ b/src/hotspot/share/classfile/classLoader.cpp @@ -251,7 +251,7 @@ const char* ClassPathEntry::copy_path(const char* path) { } ClassPathDirEntry::~ClassPathDirEntry() { - FREE_C_HEAP_ARRAY(char, _dir); + FREE_C_HEAP_ARRAY(_dir); } ClassFileStream* ClassPathDirEntry::open_stream(JavaThread* current, const char* name) { @@ -280,7 +280,7 @@ ClassFileStream* ClassPathDirEntry::open_stream(JavaThread* current, const char* #ifdef ASSERT // Freeing path is a no-op here as buffer prevents it from being reclaimed. But we keep it for // debug builds so that we guard against use-after-free bugs. - FREE_RESOURCE_ARRAY_IN_THREAD(current, char, path, path_len); + FREE_RESOURCE_ARRAY_IN_THREAD(current, path, path_len); #endif // We don't verify the length of the classfile stream fits in an int, but this is the // bootloader so we have control of this. @@ -291,7 +291,7 @@ ClassFileStream* ClassPathDirEntry::open_stream(JavaThread* current, const char* } } } - FREE_RESOURCE_ARRAY_IN_THREAD(current, char, path, path_len); + FREE_RESOURCE_ARRAY_IN_THREAD(current, path, path_len); return nullptr; } @@ -302,7 +302,7 @@ ClassPathZipEntry::ClassPathZipEntry(jzfile* zip, const char* zip_name) : ClassP ClassPathZipEntry::~ClassPathZipEntry() { ZipLibrary::close(_zip); - FREE_C_HEAP_ARRAY(char, _zip_name); + FREE_C_HEAP_ARRAY(_zip_name); } bool ClassPathZipEntry::has_entry(JavaThread* current, const char* name) { @@ -1438,7 +1438,7 @@ bool ClassLoader::is_module_observable(const char* module_name) { struct stat st; const char *path = get_exploded_module_path(module_name, true); bool res = os::stat(path, &st) == 0; - FREE_C_HEAP_ARRAY(char, path); + FREE_C_HEAP_ARRAY(path); return res; } jlong size; diff --git a/src/hotspot/share/classfile/compactHashtable.cpp b/src/hotspot/share/classfile/compactHashtable.cpp index de67971c403..f06f1986d8b 100644 --- a/src/hotspot/share/classfile/compactHashtable.cpp +++ b/src/hotspot/share/classfile/compactHashtable.cpp @@ -69,7 +69,7 @@ CompactHashtableWriter::~CompactHashtableWriter() { delete bucket; } - FREE_C_HEAP_ARRAY(GrowableArray*, _buckets); + FREE_C_HEAP_ARRAY(_buckets); } // Add an entry to the temporary hash table diff --git a/src/hotspot/share/classfile/resolutionErrors.cpp b/src/hotspot/share/classfile/resolutionErrors.cpp index c41d5d2f052..958d4812cbb 100644 --- a/src/hotspot/share/classfile/resolutionErrors.cpp +++ b/src/hotspot/share/classfile/resolutionErrors.cpp @@ -114,15 +114,15 @@ ResolutionErrorEntry::~ResolutionErrorEntry() { Symbol::maybe_decrement_refcount(_cause); if (_message != nullptr) { - FREE_C_HEAP_ARRAY(char, _message); + FREE_C_HEAP_ARRAY(_message); } if (_cause_msg != nullptr) { - FREE_C_HEAP_ARRAY(char, _cause_msg); + FREE_C_HEAP_ARRAY(_cause_msg); } if (nest_host_error() != nullptr) { - FREE_C_HEAP_ARRAY(char, nest_host_error()); + FREE_C_HEAP_ARRAY(nest_host_error()); } } diff --git a/src/hotspot/share/code/aotCodeCache.cpp b/src/hotspot/share/code/aotCodeCache.cpp index d4f12936e96..89b7d16c31e 100644 --- a/src/hotspot/share/code/aotCodeCache.cpp +++ b/src/hotspot/share/code/aotCodeCache.cpp @@ -876,7 +876,7 @@ bool AOTCodeCache::finish_write() { current += size; uint n = write_bytes(&(entries_address[i]), sizeof(AOTCodeEntry)); if (n != sizeof(AOTCodeEntry)) { - FREE_C_HEAP_ARRAY(uint, search); + FREE_C_HEAP_ARRAY(search); return false; } search[entries_count*2 + 0] = entries_address[i].id(); @@ -897,7 +897,7 @@ bool AOTCodeCache::finish_write() { } if (entries_count == 0) { log_info(aot, codecache, exit)("AOT Code Cache was not created: no entires"); - FREE_C_HEAP_ARRAY(uint, search); + FREE_C_HEAP_ARRAY(search); return true; // Nothing to write } assert(entries_count <= store_count, "%d > %d", entries_count, store_count); @@ -913,7 +913,7 @@ bool AOTCodeCache::finish_write() { qsort(search, entries_count, 2*sizeof(uint), uint_cmp); search_size = 2 * entries_count * sizeof(uint); copy_bytes((const char*)search, (address)current, search_size); - FREE_C_HEAP_ARRAY(uint, search); + FREE_C_HEAP_ARRAY(search); current += search_size; // Write entries diff --git a/src/hotspot/share/code/aotCodeCache.hpp b/src/hotspot/share/code/aotCodeCache.hpp index 5b773a986f1..2f314fe1eb6 100644 --- a/src/hotspot/share/code/aotCodeCache.hpp +++ b/src/hotspot/share/code/aotCodeCache.hpp @@ -252,7 +252,7 @@ private: public: AOTStubData(BlobId blob_id) NOT_CDS({}); - ~AOTStubData() CDS_ONLY({FREE_C_HEAP_ARRAY(StubAddrRange, _ranges);}) NOT_CDS({}) + ~AOTStubData() CDS_ONLY({FREE_C_HEAP_ARRAY(_ranges);}) NOT_CDS({}) bool is_open() CDS_ONLY({ return (_flags & OPEN) != 0; }) NOT_CDS_RETURN_(false); bool is_using() CDS_ONLY({ return (_flags & USING) != 0; }) NOT_CDS_RETURN_(false); diff --git a/src/hotspot/share/code/codeCache.cpp b/src/hotspot/share/code/codeCache.cpp index c0b4918102e..afed39847d2 100644 --- a/src/hotspot/share/code/codeCache.cpp +++ b/src/hotspot/share/code/codeCache.cpp @@ -1715,7 +1715,7 @@ void CodeCache::print_internals() { } } - FREE_C_HEAP_ARRAY(int, buckets); + FREE_C_HEAP_ARRAY(buckets); print_memory_overhead(); } diff --git a/src/hotspot/share/code/exceptionHandlerTable.cpp b/src/hotspot/share/code/exceptionHandlerTable.cpp index a295d1271aa..f0ad9921cd0 100644 --- a/src/hotspot/share/code/exceptionHandlerTable.cpp +++ b/src/hotspot/share/code/exceptionHandlerTable.cpp @@ -32,7 +32,7 @@ void ExceptionHandlerTable::add_entry(HandlerTableEntry entry) { // not enough space => grow the table (amortized growth, double its size) guarantee(_size > 0, "no space allocated => cannot grow the table since it is part of nmethod"); int new_size = _size * 2; - _table = REALLOC_RESOURCE_ARRAY(HandlerTableEntry, _table, _size, new_size); + _table = REALLOC_RESOURCE_ARRAY(_table, _size, new_size); _size = new_size; } assert(_length < _size, "sanity check"); @@ -178,7 +178,7 @@ void ImplicitExceptionTable::append( uint exec_off, uint cont_off ) { if (_size == 0) _size = 4; _size *= 2; uint new_size_in_elements = _size*2; - _data = REALLOC_RESOURCE_ARRAY(uint, _data, old_size_in_elements, new_size_in_elements); + _data = REALLOC_RESOURCE_ARRAY(_data, old_size_in_elements, new_size_in_elements); } *(adr(l) ) = exec_off; *(adr(l)+1) = cont_off; diff --git a/src/hotspot/share/compiler/cHeapStringHolder.cpp b/src/hotspot/share/compiler/cHeapStringHolder.cpp index 261658e04eb..5a9c124688e 100644 --- a/src/hotspot/share/compiler/cHeapStringHolder.cpp +++ b/src/hotspot/share/compiler/cHeapStringHolder.cpp @@ -36,7 +36,7 @@ void CHeapStringHolder::set(const char* string) { void CHeapStringHolder::clear() { if (_string != nullptr) { - FREE_C_HEAP_ARRAY(char, _string); + FREE_C_HEAP_ARRAY(_string); _string = nullptr; } } diff --git a/src/hotspot/share/compiler/compilationMemoryStatistic.cpp b/src/hotspot/share/compiler/compilationMemoryStatistic.cpp index 1951fd066fc..82bd4c160d2 100644 --- a/src/hotspot/share/compiler/compilationMemoryStatistic.cpp +++ b/src/hotspot/share/compiler/compilationMemoryStatistic.cpp @@ -487,7 +487,7 @@ public: void clean_details() { if (_detail_stats != nullptr) { - FREE_C_HEAP_ARRAY(Details, _detail_stats); + FREE_C_HEAP_ARRAY(_detail_stats); _detail_stats = nullptr; } } diff --git a/src/hotspot/share/compiler/compileLog.cpp b/src/hotspot/share/compiler/compileLog.cpp index d0ea80d6019..d0833fbe7fa 100644 --- a/src/hotspot/share/compiler/compileLog.cpp +++ b/src/hotspot/share/compiler/compileLog.cpp @@ -64,8 +64,8 @@ CompileLog::~CompileLog() { _out = nullptr; // Remove partial file after merging in CompileLog::finish_log_on_error unlink(_file); - FREE_C_HEAP_ARRAY(char, _identities); - FREE_C_HEAP_ARRAY(char, _file); + FREE_C_HEAP_ARRAY(_identities); + FREE_C_HEAP_ARRAY(_file); } @@ -96,7 +96,7 @@ int CompileLog::identify(ciBaseObject* obj) { if (id >= _identities_capacity) { int new_cap = _identities_capacity * 2; if (new_cap <= id) new_cap = id + 100; - _identities = REALLOC_C_HEAP_ARRAY(char, _identities, new_cap, mtCompiler); + _identities = REALLOC_C_HEAP_ARRAY(_identities, new_cap, mtCompiler); _identities_capacity = new_cap; } while (id >= _identities_limit) { diff --git a/src/hotspot/share/compiler/compilerDirectives.cpp b/src/hotspot/share/compiler/compilerDirectives.cpp index 1cd8bd1b510..d0042d0e16c 100644 --- a/src/hotspot/share/compiler/compilerDirectives.cpp +++ b/src/hotspot/share/compiler/compilerDirectives.cpp @@ -256,7 +256,7 @@ ControlIntrinsicIter::ControlIntrinsicIter(ccstrlist option_value, bool disable_ } ControlIntrinsicIter::~ControlIntrinsicIter() { - FREE_C_HEAP_ARRAY(char, _list); + FREE_C_HEAP_ARRAY(_list); } // pre-increment diff --git a/src/hotspot/share/compiler/compilerDirectives.hpp b/src/hotspot/share/compiler/compilerDirectives.hpp index e4826b3056c..833d806f519 100644 --- a/src/hotspot/share/compiler/compilerDirectives.hpp +++ b/src/hotspot/share/compiler/compilerDirectives.hpp @@ -283,7 +283,7 @@ class ControlIntrinsicValidator { ~ControlIntrinsicValidator() { if (_bad != nullptr) { - FREE_C_HEAP_ARRAY(char, _bad); + FREE_C_HEAP_ARRAY(_bad); } } diff --git a/src/hotspot/share/compiler/directivesParser.cpp b/src/hotspot/share/compiler/directivesParser.cpp index a2da7c7e0e4..53a8325702e 100644 --- a/src/hotspot/share/compiler/directivesParser.cpp +++ b/src/hotspot/share/compiler/directivesParser.cpp @@ -198,7 +198,7 @@ bool DirectivesParser::push_key(const char* str, size_t len) { strncpy(s, str, len); s[len] = '\0'; error(KEY_ERROR, "No such key: '%s'.", s); - FREE_C_HEAP_ARRAY(char, s); + FREE_C_HEAP_ARRAY(s); return false; } @@ -370,7 +370,7 @@ bool DirectivesParser::set_option_flag(JSON_TYPE t, JSON_VAL* v, const key* opti #endif if (!valid) { - FREE_C_HEAP_ARRAY(char, s); + FREE_C_HEAP_ARRAY(s); return false; } (set->*test)((void *)&s); // Takes ownership. @@ -440,7 +440,7 @@ bool DirectivesParser::set_option(JSON_TYPE t, JSON_VAL* v) { assert (error_msg != nullptr, "Must have valid error message"); error(VALUE_ERROR, "Method pattern error: %s", error_msg); } - FREE_C_HEAP_ARRAY(char, s); + FREE_C_HEAP_ARRAY(s); } break; @@ -472,7 +472,7 @@ bool DirectivesParser::set_option(JSON_TYPE t, JSON_VAL* v) { error(VALUE_ERROR, "Method pattern error: %s", error_msg); } } - FREE_C_HEAP_ARRAY(char, s); + FREE_C_HEAP_ARRAY(s); } break; @@ -622,4 +622,3 @@ bool DirectivesParser::callback(JSON_TYPE t, JSON_VAL* v, uint rlimit) { } } } - diff --git a/src/hotspot/share/compiler/oopMap.cpp b/src/hotspot/share/compiler/oopMap.cpp index 87467d06400..c8d0c5d22ba 100644 --- a/src/hotspot/share/compiler/oopMap.cpp +++ b/src/hotspot/share/compiler/oopMap.cpp @@ -869,7 +869,7 @@ ImmutableOopMapSet* ImmutableOopMapSet::clone() const { } void ImmutableOopMapSet::operator delete(void* p) { - FREE_C_HEAP_ARRAY(unsigned char, p); + FREE_C_HEAP_ARRAY(p); } //------------------------------DerivedPointerTable--------------------------- diff --git a/src/hotspot/share/gc/epsilon/epsilonMonitoringSupport.cpp b/src/hotspot/share/gc/epsilon/epsilonMonitoringSupport.cpp index 213fc18b8ff..7ec4a0016db 100644 --- a/src/hotspot/share/gc/epsilon/epsilonMonitoringSupport.cpp +++ b/src/hotspot/share/gc/epsilon/epsilonMonitoringSupport.cpp @@ -70,7 +70,7 @@ public: } ~EpsilonSpaceCounters() { - FREE_C_HEAP_ARRAY(char, _name_space); + FREE_C_HEAP_ARRAY(_name_space); } inline void update_all(size_t capacity, size_t used) { diff --git a/src/hotspot/share/gc/g1/g1Allocator.cpp b/src/hotspot/share/gc/g1/g1Allocator.cpp index 78710084ee3..e9d1c13af7a 100644 --- a/src/hotspot/share/gc/g1/g1Allocator.cpp +++ b/src/hotspot/share/gc/g1/g1Allocator.cpp @@ -63,8 +63,8 @@ G1Allocator::~G1Allocator() { _mutator_alloc_regions[i].~MutatorAllocRegion(); _survivor_gc_alloc_regions[i].~SurvivorGCAllocRegion(); } - FREE_C_HEAP_ARRAY(MutatorAllocRegion, _mutator_alloc_regions); - FREE_C_HEAP_ARRAY(SurvivorGCAllocRegion, _survivor_gc_alloc_regions); + FREE_C_HEAP_ARRAY(_mutator_alloc_regions); + FREE_C_HEAP_ARRAY(_survivor_gc_alloc_regions); } #ifdef ASSERT @@ -315,7 +315,7 @@ G1PLABAllocator::PLABData::~PLABData() { for (uint node_index = 0; node_index < _num_alloc_buffers; node_index++) { delete _alloc_buffer[node_index]; } - FREE_C_HEAP_ARRAY(PLAB*, _alloc_buffer); + FREE_C_HEAP_ARRAY(_alloc_buffer); } void G1PLABAllocator::PLABData::initialize(uint num_alloc_buffers, size_t desired_plab_size, size_t tolerated_refills) { diff --git a/src/hotspot/share/gc/g1/g1Arguments.cpp b/src/hotspot/share/gc/g1/g1Arguments.cpp index c3bbd5a3b52..a0acd903b0f 100644 --- a/src/hotspot/share/gc/g1/g1Arguments.cpp +++ b/src/hotspot/share/gc/g1/g1Arguments.cpp @@ -98,7 +98,7 @@ void G1Arguments::initialize_verification_types() { parse_verification_type(token); token = strtok_r(nullptr, delimiter, &save_ptr); } - FREE_C_HEAP_ARRAY(char, type_list); + FREE_C_HEAP_ARRAY(type_list); } } diff --git a/src/hotspot/share/gc/g1/g1CardSet.cpp b/src/hotspot/share/gc/g1/g1CardSet.cpp index 60ad63e812c..f0db638a2fe 100644 --- a/src/hotspot/share/gc/g1/g1CardSet.cpp +++ b/src/hotspot/share/gc/g1/g1CardSet.cpp @@ -145,7 +145,7 @@ G1CardSetConfiguration::G1CardSetConfiguration(uint inline_ptr_bits_per_card, } G1CardSetConfiguration::~G1CardSetConfiguration() { - FREE_C_HEAP_ARRAY(size_t, _card_set_alloc_options); + FREE_C_HEAP_ARRAY(_card_set_alloc_options); } void G1CardSetConfiguration::init_card_set_alloc_options() { diff --git a/src/hotspot/share/gc/g1/g1CardSetMemory.cpp b/src/hotspot/share/gc/g1/g1CardSetMemory.cpp index 0da2f90da3f..95a32bae766 100644 --- a/src/hotspot/share/gc/g1/g1CardSetMemory.cpp +++ b/src/hotspot/share/gc/g1/g1CardSetMemory.cpp @@ -90,7 +90,7 @@ G1CardSetMemoryManager::~G1CardSetMemoryManager() { for (uint i = 0; i < num_mem_object_types(); i++) { _allocators[i].~G1CardSetAllocator(); } - FREE_C_HEAP_ARRAY(G1CardSetAllocator, _allocators); + FREE_C_HEAP_ARRAY(_allocators); } void G1CardSetMemoryManager::free(uint type, void* value) { diff --git a/src/hotspot/share/gc/g1/g1CardTableClaimTable.cpp b/src/hotspot/share/gc/g1/g1CardTableClaimTable.cpp index d8cabaa00a4..27b41ef165f 100644 --- a/src/hotspot/share/gc/g1/g1CardTableClaimTable.cpp +++ b/src/hotspot/share/gc/g1/g1CardTableClaimTable.cpp @@ -39,7 +39,7 @@ G1CardTableClaimTable::G1CardTableClaimTable(uint chunks_per_region) : } G1CardTableClaimTable::~G1CardTableClaimTable() { - FREE_C_HEAP_ARRAY(uint, _card_claims); + FREE_C_HEAP_ARRAY(_card_claims); } void G1CardTableClaimTable::initialize(uint max_reserved_regions) { diff --git a/src/hotspot/share/gc/g1/g1CollectionSet.cpp b/src/hotspot/share/gc/g1/g1CollectionSet.cpp index b3bcf6094ab..d2f9d30d87a 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSet.cpp +++ b/src/hotspot/share/gc/g1/g1CollectionSet.cpp @@ -72,7 +72,7 @@ G1CollectionSet::G1CollectionSet(G1CollectedHeap* g1h, G1Policy* policy) : } G1CollectionSet::~G1CollectionSet() { - FREE_C_HEAP_ARRAY(uint, _regions); + FREE_C_HEAP_ARRAY(_regions); abandon_all_candidates(); } @@ -766,7 +766,7 @@ public: } } ~G1VerifyYoungCSetIndicesClosure() { - FREE_C_HEAP_ARRAY(int, _heap_region_indices); + FREE_C_HEAP_ARRAY(_heap_region_indices); } virtual bool do_heap_region(G1HeapRegion* r) { diff --git a/src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp b/src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp index 2113db1163b..3637d477229 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp +++ b/src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp @@ -214,7 +214,7 @@ G1CollectionSetCandidates::G1CollectionSetCandidates() : { } G1CollectionSetCandidates::~G1CollectionSetCandidates() { - FREE_C_HEAP_ARRAY(CandidateOrigin, _contains_map); + FREE_C_HEAP_ARRAY(_contains_map); _from_marking_groups.clear(); _retained_groups.clear(); } @@ -413,7 +413,7 @@ void G1CollectionSetCandidates::verify() { static_cast::type>(verify_map[i])); } - FREE_C_HEAP_ARRAY(CandidateOrigin, verify_map); + FREE_C_HEAP_ARRAY(verify_map); } #endif diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp index dbb5ba509a2..d5e3b9cc69d 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp @@ -249,7 +249,7 @@ G1CMMarkStack::ChunkAllocator::~ChunkAllocator() { } } - FREE_C_HEAP_ARRAY(TaskQueueEntryChunk*, _buckets); + FREE_C_HEAP_ARRAY(_buckets); } bool G1CMMarkStack::ChunkAllocator::reserve(size_t new_capacity) { @@ -676,9 +676,9 @@ void G1ConcurrentMark::reset_at_marking_complete() { } G1ConcurrentMark::~G1ConcurrentMark() { - FREE_C_HEAP_ARRAY(Atomic, _top_at_mark_starts); - FREE_C_HEAP_ARRAY(Atomic, _top_at_rebuild_starts); - FREE_C_HEAP_ARRAY(G1RegionMarkStats, _region_mark_stats); + FREE_C_HEAP_ARRAY(_top_at_mark_starts); + FREE_C_HEAP_ARRAY(_top_at_rebuild_starts); + FREE_C_HEAP_ARRAY(_region_mark_stats); // The G1ConcurrentMark instance is never freed. ShouldNotReachHere(); } diff --git a/src/hotspot/share/gc/g1/g1EvacFailureRegions.cpp b/src/hotspot/share/gc/g1/g1EvacFailureRegions.cpp index 37553e2aa56..03c20346eb3 100644 --- a/src/hotspot/share/gc/g1/g1EvacFailureRegions.cpp +++ b/src/hotspot/share/gc/g1/g1EvacFailureRegions.cpp @@ -55,7 +55,7 @@ void G1EvacFailureRegions::post_collection() { _regions_pinned.resize(0); _regions_alloc_failed.resize(0); - FREE_C_HEAP_ARRAY(uint, _evac_failed_regions); + FREE_C_HEAP_ARRAY(_evac_failed_regions); _evac_failed_regions = nullptr; } diff --git a/src/hotspot/share/gc/g1/g1FullCollector.cpp b/src/hotspot/share/gc/g1/g1FullCollector.cpp index c835dd159a6..8b38509d1d8 100644 --- a/src/hotspot/share/gc/g1/g1FullCollector.cpp +++ b/src/hotspot/share/gc/g1/g1FullCollector.cpp @@ -167,10 +167,10 @@ G1FullCollector::~G1FullCollector() { delete _partial_array_state_manager; - FREE_C_HEAP_ARRAY(G1FullGCMarker*, _markers); - FREE_C_HEAP_ARRAY(G1FullGCCompactionPoint*, _compaction_points); - FREE_C_HEAP_ARRAY(Atomic, _compaction_tops); - FREE_C_HEAP_ARRAY(G1RegionMarkStats, _live_stats); + FREE_C_HEAP_ARRAY(_markers); + FREE_C_HEAP_ARRAY(_compaction_points); + FREE_C_HEAP_ARRAY(_compaction_tops); + FREE_C_HEAP_ARRAY(_live_stats); } class PrepareRegionsClosure : public G1HeapRegionClosure { diff --git a/src/hotspot/share/gc/g1/g1HeapRegionManager.cpp b/src/hotspot/share/gc/g1/g1HeapRegionManager.cpp index 3c0318827ef..214f1a2d2b6 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionManager.cpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionManager.cpp @@ -718,7 +718,7 @@ G1HeapRegionClaimer::G1HeapRegionClaimer(uint n_workers) : } G1HeapRegionClaimer::~G1HeapRegionClaimer() { - FREE_C_HEAP_ARRAY(uint, _claims); + FREE_C_HEAP_ARRAY(_claims); } uint G1HeapRegionClaimer::offset_for_worker(uint worker_id) const { @@ -759,7 +759,7 @@ public: for (uint worker = 0; worker < _num_workers; worker++) { _worker_freelists[worker].~G1FreeRegionList(); } - FREE_C_HEAP_ARRAY(G1FreeRegionList, _worker_freelists); + FREE_C_HEAP_ARRAY(_worker_freelists); } G1FreeRegionList* worker_freelist(uint worker) { diff --git a/src/hotspot/share/gc/g1/g1HeapRegionSet.cpp b/src/hotspot/share/gc/g1/g1HeapRegionSet.cpp index 70186adcdfc..930a4bd953f 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionSet.cpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionSet.cpp @@ -384,7 +384,7 @@ G1FreeRegionList::NodeInfo::NodeInfo() : _numa(G1NUMA::numa()), _length_of_node( } G1FreeRegionList::NodeInfo::~NodeInfo() { - FREE_C_HEAP_ARRAY(uint, _length_of_node); + FREE_C_HEAP_ARRAY(_length_of_node); } void G1FreeRegionList::NodeInfo::clear() { diff --git a/src/hotspot/share/gc/g1/g1HeapTransition.cpp b/src/hotspot/share/gc/g1/g1HeapTransition.cpp index 30ad4c72bf6..690bda4e7e6 100644 --- a/src/hotspot/share/gc/g1/g1HeapTransition.cpp +++ b/src/hotspot/share/gc/g1/g1HeapTransition.cpp @@ -55,8 +55,8 @@ G1HeapTransition::Data::Data(G1CollectedHeap* g1_heap) : } G1HeapTransition::Data::~Data() { - FREE_C_HEAP_ARRAY(uint, _eden_length_per_node); - FREE_C_HEAP_ARRAY(uint, _survivor_length_per_node); + FREE_C_HEAP_ARRAY(_eden_length_per_node); + FREE_C_HEAP_ARRAY(_survivor_length_per_node); } G1HeapTransition::G1HeapTransition(G1CollectedHeap* g1_heap) : _g1_heap(g1_heap), _before(g1_heap) { } diff --git a/src/hotspot/share/gc/g1/g1MonotonicArena.cpp b/src/hotspot/share/gc/g1/g1MonotonicArena.cpp index 3f97870a67f..aea6f4335e8 100644 --- a/src/hotspot/share/gc/g1/g1MonotonicArena.cpp +++ b/src/hotspot/share/gc/g1/g1MonotonicArena.cpp @@ -52,7 +52,7 @@ void G1MonotonicArena::Segment::delete_segment(Segment* segment) { GlobalCounter::write_synchronize(); } segment->~Segment(); - FREE_C_HEAP_ARRAY(_mem_tag, segment); + FREE_C_HEAP_ARRAY(segment); } void G1MonotonicArena::SegmentFreeList::bulk_add(Segment& first, diff --git a/src/hotspot/share/gc/g1/g1MonotonicArenaFreePool.cpp b/src/hotspot/share/gc/g1/g1MonotonicArenaFreePool.cpp index 922c68bfba4..c12321b851a 100644 --- a/src/hotspot/share/gc/g1/g1MonotonicArenaFreePool.cpp +++ b/src/hotspot/share/gc/g1/g1MonotonicArenaFreePool.cpp @@ -159,7 +159,7 @@ G1MonotonicArenaFreePool::~G1MonotonicArenaFreePool() { for (uint i = 0; i < _num_free_lists; i++) { _free_lists[i].~SegmentFreeList(); } - FREE_C_HEAP_ARRAY(mtGC, _free_lists); + FREE_C_HEAP_ARRAY(_free_lists); } G1MonotonicArenaMemoryStats G1MonotonicArenaFreePool::memory_sizes() const { diff --git a/src/hotspot/share/gc/g1/g1NUMA.cpp b/src/hotspot/share/gc/g1/g1NUMA.cpp index 778ed31d7b5..db42b8c10fc 100644 --- a/src/hotspot/share/gc/g1/g1NUMA.cpp +++ b/src/hotspot/share/gc/g1/g1NUMA.cpp @@ -123,8 +123,8 @@ void G1NUMA::initialize(bool use_numa) { G1NUMA::~G1NUMA() { delete _stats; - FREE_C_HEAP_ARRAY(uint, _node_id_to_index_map); - FREE_C_HEAP_ARRAY(uint, _node_ids); + FREE_C_HEAP_ARRAY(_node_id_to_index_map); + FREE_C_HEAP_ARRAY(_node_ids); } void G1NUMA::set_region_info(size_t region_size, size_t page_size) { @@ -280,9 +280,9 @@ G1NodeIndexCheckClosure::~G1NodeIndexCheckClosure() { _ls->print("%u: %u/%u/%u ", numa_ids[i], _matched[i], _mismatched[i], _total[i]); } - FREE_C_HEAP_ARRAY(uint, _matched); - FREE_C_HEAP_ARRAY(uint, _mismatched); - FREE_C_HEAP_ARRAY(uint, _total); + FREE_C_HEAP_ARRAY(_matched); + FREE_C_HEAP_ARRAY(_mismatched); + FREE_C_HEAP_ARRAY(_total); } bool G1NodeIndexCheckClosure::do_heap_region(G1HeapRegion* hr) { diff --git a/src/hotspot/share/gc/g1/g1NUMAStats.cpp b/src/hotspot/share/gc/g1/g1NUMAStats.cpp index aaebfa1be8f..ce62d34f847 100644 --- a/src/hotspot/share/gc/g1/g1NUMAStats.cpp +++ b/src/hotspot/share/gc/g1/g1NUMAStats.cpp @@ -45,9 +45,9 @@ G1NUMAStats::NodeDataArray::NodeDataArray(uint num_nodes) { G1NUMAStats::NodeDataArray::~NodeDataArray() { for (uint row = 0; row < _num_row; row++) { - FREE_C_HEAP_ARRAY(size_t, _data[row]); + FREE_C_HEAP_ARRAY(_data[row]); } - FREE_C_HEAP_ARRAY(size_t*, _data); + FREE_C_HEAP_ARRAY(_data); } void G1NUMAStats::NodeDataArray::create_hit_rate(Stat* result) const { diff --git a/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp b/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp index 52c8d4d4389..50438c641c2 100644 --- a/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp +++ b/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp @@ -131,9 +131,9 @@ size_t G1ParScanThreadState::flush_stats(size_t* surviving_young_words, uint num G1ParScanThreadState::~G1ParScanThreadState() { delete _plab_allocator; delete _closures; - FREE_C_HEAP_ARRAY(size_t, _surviving_young_words_base); + FREE_C_HEAP_ARRAY(_surviving_young_words_base); delete[] _oops_into_optional_regions; - FREE_C_HEAP_ARRAY(size_t, _obj_alloc_stat); + FREE_C_HEAP_ARRAY(_obj_alloc_stat); } size_t G1ParScanThreadState::lab_waste_words() const { @@ -730,8 +730,8 @@ G1ParScanThreadStateSet::G1ParScanThreadStateSet(G1CollectedHeap* g1h, G1ParScanThreadStateSet::~G1ParScanThreadStateSet() { assert(_flushed, "thread local state from the per thread states should have been flushed"); - FREE_C_HEAP_ARRAY(G1ParScanThreadState*, _states); - FREE_C_HEAP_ARRAY(size_t, _surviving_young_words_total); + FREE_C_HEAP_ARRAY(_states); + FREE_C_HEAP_ARRAY(_surviving_young_words_total); } #if TASKQUEUE_STATS diff --git a/src/hotspot/share/gc/g1/g1RegionMarkStatsCache.cpp b/src/hotspot/share/gc/g1/g1RegionMarkStatsCache.cpp index c5f55e1d20c..a9f4115df94 100644 --- a/src/hotspot/share/gc/g1/g1RegionMarkStatsCache.cpp +++ b/src/hotspot/share/gc/g1/g1RegionMarkStatsCache.cpp @@ -38,7 +38,7 @@ G1RegionMarkStatsCache::G1RegionMarkStatsCache(G1RegionMarkStats* target, uint n } G1RegionMarkStatsCache::~G1RegionMarkStatsCache() { - FREE_C_HEAP_ARRAY(G1RegionMarkStatsCacheEntry, _cache); + FREE_C_HEAP_ARRAY(_cache); } void G1RegionMarkStatsCache::add_live_words(oop obj) { diff --git a/src/hotspot/share/gc/g1/g1RegionsOnNodes.cpp b/src/hotspot/share/gc/g1/g1RegionsOnNodes.cpp index c1c0d471796..9550e57698e 100644 --- a/src/hotspot/share/gc/g1/g1RegionsOnNodes.cpp +++ b/src/hotspot/share/gc/g1/g1RegionsOnNodes.cpp @@ -32,7 +32,7 @@ G1RegionsOnNodes::G1RegionsOnNodes() : _count_per_node(nullptr), _numa(G1NUMA::n } G1RegionsOnNodes::~G1RegionsOnNodes() { - FREE_C_HEAP_ARRAY(uint, _count_per_node); + FREE_C_HEAP_ARRAY(_count_per_node); } void G1RegionsOnNodes::add(G1HeapRegion* hr) { diff --git a/src/hotspot/share/gc/g1/g1RemSet.cpp b/src/hotspot/share/gc/g1/g1RemSet.cpp index 9f9f0ecdf3a..be18a3065e9 100644 --- a/src/hotspot/share/gc/g1/g1RemSet.cpp +++ b/src/hotspot/share/gc/g1/g1RemSet.cpp @@ -124,8 +124,8 @@ class G1RemSetScanState : public CHeapObj { } ~G1DirtyRegions() { - FREE_C_HEAP_ARRAY(uint, _buffer); - FREE_C_HEAP_ARRAY(Atomic, _contains); + FREE_C_HEAP_ARRAY(_buffer); + FREE_C_HEAP_ARRAY(_contains); } void reset() { @@ -245,7 +245,7 @@ public: _scan_top(nullptr) { } ~G1RemSetScanState() { - FREE_C_HEAP_ARRAY(HeapWord*, _scan_top); + FREE_C_HEAP_ARRAY(_scan_top); } void initialize(uint max_reserved_regions) { diff --git a/src/hotspot/share/gc/g1/g1RemSetSummary.cpp b/src/hotspot/share/gc/g1/g1RemSetSummary.cpp index 3e9cf938097..1c0e15757cc 100644 --- a/src/hotspot/share/gc/g1/g1RemSetSummary.cpp +++ b/src/hotspot/share/gc/g1/g1RemSetSummary.cpp @@ -98,7 +98,7 @@ G1RemSetSummary::G1RemSetSummary(bool should_update) : } G1RemSetSummary::~G1RemSetSummary() { - FREE_C_HEAP_ARRAY(jlong, _worker_threads_cpu_times); + FREE_C_HEAP_ARRAY(_worker_threads_cpu_times); } void G1RemSetSummary::set(G1RemSetSummary* other) { diff --git a/src/hotspot/share/gc/g1/g1SurvRateGroup.cpp b/src/hotspot/share/gc/g1/g1SurvRateGroup.cpp index f858b93b13d..15c6d3d1f15 100644 --- a/src/hotspot/share/gc/g1/g1SurvRateGroup.cpp +++ b/src/hotspot/share/gc/g1/g1SurvRateGroup.cpp @@ -65,8 +65,8 @@ void G1SurvRateGroup::start_adding_regions() { void G1SurvRateGroup::stop_adding_regions() { if (_num_added_regions > _stats_arrays_length) { - _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); + _accum_surv_rate_pred = REALLOC_C_HEAP_ARRAY(_accum_surv_rate_pred, _num_added_regions, mtGC); + _surv_rate_predictors = REALLOC_C_HEAP_ARRAY(_surv_rate_predictors, _num_added_regions, mtGC); for (uint i = _stats_arrays_length; i < _num_added_regions; ++i) { // Initialize predictors and accumulated survivor rate predictions. diff --git a/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp b/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp index 14282383e29..11da3cb8263 100644 --- a/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp +++ b/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp @@ -802,7 +802,7 @@ public: for (uint worker = 0; worker < _active_workers; worker++) { _worker_stats[worker].~FreeCSetStats(); } - FREE_C_HEAP_ARRAY(FreeCSetStats, _worker_stats); + FREE_C_HEAP_ARRAY(_worker_stats); _g1h->clear_collection_set(); diff --git a/src/hotspot/share/gc/g1/g1YoungGCPreEvacuateTasks.cpp b/src/hotspot/share/gc/g1/g1YoungGCPreEvacuateTasks.cpp index 936457659b6..7889fd4fb31 100644 --- a/src/hotspot/share/gc/g1/g1YoungGCPreEvacuateTasks.cpp +++ b/src/hotspot/share/gc/g1/g1YoungGCPreEvacuateTasks.cpp @@ -73,7 +73,7 @@ public: ~JavaThreadRetireTLABs() { static_assert(std::is_trivially_destructible::value, "must be"); - FREE_C_HEAP_ARRAY(ThreadLocalAllocStats, _local_tlab_stats); + FREE_C_HEAP_ARRAY(_local_tlab_stats); } void do_work(uint worker_id) override { diff --git a/src/hotspot/share/gc/parallel/mutableNUMASpace.cpp b/src/hotspot/share/gc/parallel/mutableNUMASpace.cpp index c5d112ffbc1..8b514fe7199 100644 --- a/src/hotspot/share/gc/parallel/mutableNUMASpace.cpp +++ b/src/hotspot/share/gc/parallel/mutableNUMASpace.cpp @@ -55,7 +55,7 @@ MutableNUMASpace::MutableNUMASpace(size_t page_size) : MutableSpace(page_size) { lgrp_spaces()->append(new LGRPSpace(lgrp_ids[i], page_size)); } - FREE_C_HEAP_ARRAY(uint, lgrp_ids); + FREE_C_HEAP_ARRAY(lgrp_ids); } MutableNUMASpace::~MutableNUMASpace() { diff --git a/src/hotspot/share/gc/shared/bufferNode.cpp b/src/hotspot/share/gc/shared/bufferNode.cpp index 90e50f52e84..855f872afab 100644 --- a/src/hotspot/share/gc/shared/bufferNode.cpp +++ b/src/hotspot/share/gc/shared/bufferNode.cpp @@ -41,7 +41,7 @@ void* BufferNode::AllocatorConfig::allocate() { void BufferNode::AllocatorConfig::deallocate(void* node) { assert(node != nullptr, "precondition"); - FREE_C_HEAP_ARRAY(char, node); + FREE_C_HEAP_ARRAY(node); } BufferNode::Allocator::Allocator(const char* name, size_t buffer_capacity) : diff --git a/src/hotspot/share/gc/shared/classUnloadingContext.cpp b/src/hotspot/share/gc/shared/classUnloadingContext.cpp index 4eac2561e67..d2b4a2fc636 100644 --- a/src/hotspot/share/gc/shared/classUnloadingContext.cpp +++ b/src/hotspot/share/gc/shared/classUnloadingContext.cpp @@ -54,7 +54,7 @@ ClassUnloadingContext::~ClassUnloadingContext() { for (uint i = 0; i < _num_nmethod_unlink_workers; ++i) { delete _unlinked_nmethods[i]; } - FREE_C_HEAP_ARRAY(NMethodSet*, _unlinked_nmethods); + FREE_C_HEAP_ARRAY(_unlinked_nmethods); assert(_context == this, "context not set correctly"); _context = nullptr; diff --git a/src/hotspot/share/gc/shared/collectorCounters.cpp b/src/hotspot/share/gc/shared/collectorCounters.cpp index f01997f9854..1624c693470 100644 --- a/src/hotspot/share/gc/shared/collectorCounters.cpp +++ b/src/hotspot/share/gc/shared/collectorCounters.cpp @@ -62,7 +62,7 @@ CollectorCounters::CollectorCounters(const char* name, int ordinal) { } CollectorCounters::~CollectorCounters() { - FREE_C_HEAP_ARRAY(char, _name_space); + FREE_C_HEAP_ARRAY(_name_space); } TraceCollectorStats::TraceCollectorStats(CollectorCounters* c) : diff --git a/src/hotspot/share/gc/shared/generationCounters.cpp b/src/hotspot/share/gc/shared/generationCounters.cpp index f6bbc1c2618..85da4c99cbb 100644 --- a/src/hotspot/share/gc/shared/generationCounters.cpp +++ b/src/hotspot/share/gc/shared/generationCounters.cpp @@ -64,7 +64,7 @@ GenerationCounters::GenerationCounters(const char* name, } GenerationCounters::~GenerationCounters() { - FREE_C_HEAP_ARRAY(char, _name_space); + FREE_C_HEAP_ARRAY(_name_space); } void GenerationCounters::update_capacity(size_t curr_capacity) { diff --git a/src/hotspot/share/gc/shared/hSpaceCounters.cpp b/src/hotspot/share/gc/shared/hSpaceCounters.cpp index a873bc2f45c..5dd9d5bfaa8 100644 --- a/src/hotspot/share/gc/shared/hSpaceCounters.cpp +++ b/src/hotspot/share/gc/shared/hSpaceCounters.cpp @@ -66,7 +66,7 @@ HSpaceCounters::HSpaceCounters(const char* name_space, } HSpaceCounters::~HSpaceCounters() { - FREE_C_HEAP_ARRAY(char, _name_space); + FREE_C_HEAP_ARRAY(_name_space); } void HSpaceCounters::update_capacity(size_t v) { diff --git a/src/hotspot/share/gc/shared/oopStorage.cpp b/src/hotspot/share/gc/shared/oopStorage.cpp index 21e63f6fc32..8aea565cdf7 100644 --- a/src/hotspot/share/gc/shared/oopStorage.cpp +++ b/src/hotspot/share/gc/shared/oopStorage.cpp @@ -136,7 +136,7 @@ OopStorage::ActiveArray* OopStorage::ActiveArray::create(size_t size, void OopStorage::ActiveArray::destroy(ActiveArray* ba) { ba->~ActiveArray(); - FREE_C_HEAP_ARRAY(char, ba); + FREE_C_HEAP_ARRAY(ba); } size_t OopStorage::ActiveArray::size() const { @@ -362,7 +362,7 @@ OopStorage::Block* OopStorage::Block::new_block(const OopStorage* owner) { void OopStorage::Block::delete_block(const Block& block) { void* memory = block._memory; block.Block::~Block(); - FREE_C_HEAP_ARRAY(char, memory); + FREE_C_HEAP_ARRAY(memory); } // This can return a false positive if ptr is not contained by some diff --git a/src/hotspot/share/gc/shared/partialArrayState.cpp b/src/hotspot/share/gc/shared/partialArrayState.cpp index d3b21c2fdaa..4679ac2f51c 100644 --- a/src/hotspot/share/gc/shared/partialArrayState.cpp +++ b/src/hotspot/share/gc/shared/partialArrayState.cpp @@ -114,7 +114,7 @@ PartialArrayStateManager::PartialArrayStateManager(uint max_allocators) PartialArrayStateManager::~PartialArrayStateManager() { reset(); - FREE_C_HEAP_ARRAY(Arena, _arenas); + FREE_C_HEAP_ARRAY(_arenas); } Arena* PartialArrayStateManager::register_allocator() { diff --git a/src/hotspot/share/gc/shared/preservedMarks.cpp b/src/hotspot/share/gc/shared/preservedMarks.cpp index 605b7afe072..6a69fe10f95 100644 --- a/src/hotspot/share/gc/shared/preservedMarks.cpp +++ b/src/hotspot/share/gc/shared/preservedMarks.cpp @@ -148,7 +148,7 @@ void PreservedMarksSet::reclaim() { } if (_in_c_heap) { - FREE_C_HEAP_ARRAY(Padded, _stacks); + FREE_C_HEAP_ARRAY(_stacks); } else { // the array was resource-allocated, so nothing to do } diff --git a/src/hotspot/share/gc/shared/stringdedup/stringDedup.cpp b/src/hotspot/share/gc/shared/stringdedup/stringDedup.cpp index b3f96da1cce..ab1b15b0447 100644 --- a/src/hotspot/share/gc/shared/stringdedup/stringDedup.cpp +++ b/src/hotspot/share/gc/shared/stringdedup/stringDedup.cpp @@ -182,7 +182,7 @@ void StringDedup::Requests::flush() { assert(_storage_for_requests != nullptr, "invariant"); _storage_for_requests->storage()->release(_buffer, _index); } - FREE_C_HEAP_ARRAY(oop*, _buffer); + FREE_C_HEAP_ARRAY(_buffer); _buffer = nullptr; } if (_storage_for_requests != nullptr) { diff --git a/src/hotspot/share/gc/shared/stringdedup/stringDedupTable.cpp b/src/hotspot/share/gc/shared/stringdedup/stringDedupTable.cpp index a376f3b96de..546efa4774b 100644 --- a/src/hotspot/share/gc/shared/stringdedup/stringDedupTable.cpp +++ b/src/hotspot/share/gc/shared/stringdedup/stringDedupTable.cpp @@ -455,7 +455,7 @@ void StringDedup::Table::free_buckets(Bucket* buckets, size_t number_of_buckets) while (number_of_buckets > 0) { buckets[--number_of_buckets].~Bucket(); } - FREE_C_HEAP_ARRAY(Bucket, buckets); + FREE_C_HEAP_ARRAY(buckets); } // Compute the hash code for obj using halfsiphash_32. As this is a high diff --git a/src/hotspot/share/gc/shared/taskqueue.inline.hpp b/src/hotspot/share/gc/shared/taskqueue.inline.hpp index b142aadc580..c942b6cc3e9 100644 --- a/src/hotspot/share/gc/shared/taskqueue.inline.hpp +++ b/src/hotspot/share/gc/shared/taskqueue.inline.hpp @@ -48,7 +48,7 @@ inline GenericTaskQueueSet::GenericTaskQueueSet(uint n) : _n(n) { template inline GenericTaskQueueSet::~GenericTaskQueueSet() { - FREE_C_HEAP_ARRAY(T*, _queues); + FREE_C_HEAP_ARRAY(_queues); } #if TASKQUEUE_STATS diff --git a/src/hotspot/share/gc/shared/workerDataArray.inline.hpp b/src/hotspot/share/gc/shared/workerDataArray.inline.hpp index 34549bc079e..3b7658ec4c8 100644 --- a/src/hotspot/share/gc/shared/workerDataArray.inline.hpp +++ b/src/hotspot/share/gc/shared/workerDataArray.inline.hpp @@ -72,7 +72,7 @@ WorkerDataArray::~WorkerDataArray() { for (uint i = 0; i < MaxThreadWorkItems; i++) { delete _thread_work_items[i]; } - FREE_C_HEAP_ARRAY(T, _data); + FREE_C_HEAP_ARRAY(_data); } template diff --git a/src/hotspot/share/gc/shared/workerUtils.cpp b/src/hotspot/share/gc/shared/workerUtils.cpp index 1826b9d7df8..736a9b007dd 100644 --- a/src/hotspot/share/gc/shared/workerUtils.cpp +++ b/src/hotspot/share/gc/shared/workerUtils.cpp @@ -122,7 +122,7 @@ bool SubTasksDone::try_claim_task(uint t) { SubTasksDone::~SubTasksDone() { assert(_verification_done.load_relaxed(), "all_tasks_claimed must have been called."); - FREE_C_HEAP_ARRAY(Atomic, _tasks); + FREE_C_HEAP_ARRAY(_tasks); } // *** SequentialSubTasksDone diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp index c595d1fd9cd..7a2be24f84c 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp @@ -111,12 +111,12 @@ ShenandoahAdaptiveHeuristics::ShenandoahAdaptiveHeuristics(ShenandoahSpaceInfo* } ShenandoahAdaptiveHeuristics::~ShenandoahAdaptiveHeuristics() { - FREE_C_HEAP_ARRAY(double, _spike_acceleration_rate_samples); - FREE_C_HEAP_ARRAY(double, _spike_acceleration_rate_timestamps); - FREE_C_HEAP_ARRAY(double, _gc_time_timestamps); - FREE_C_HEAP_ARRAY(double, _gc_time_samples); - FREE_C_HEAP_ARRAY(double, _gc_time_xy); - FREE_C_HEAP_ARRAY(double, _gc_time_xx); + FREE_C_HEAP_ARRAY(_spike_acceleration_rate_samples); + FREE_C_HEAP_ARRAY(_spike_acceleration_rate_timestamps); + FREE_C_HEAP_ARRAY(_gc_time_timestamps); + FREE_C_HEAP_ARRAY(_gc_time_samples); + FREE_C_HEAP_ARRAY(_gc_time_xy); + FREE_C_HEAP_ARRAY(_gc_time_xx); } void ShenandoahAdaptiveHeuristics::initialize() { diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.cpp index 3091b19b600..d2010d921b1 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.cpp @@ -73,7 +73,7 @@ ShenandoahHeuristics::ShenandoahHeuristics(ShenandoahSpaceInfo* space_info) : } ShenandoahHeuristics::~ShenandoahHeuristics() { - FREE_C_HEAP_ARRAY(RegionGarbage, _region_data); + FREE_C_HEAP_ARRAY(_region_data); } void ShenandoahHeuristics::choose_collection_set(ShenandoahCollectionSet* collection_set) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.cpp b/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.cpp index a81efa99d70..4989c929b32 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.cpp @@ -70,15 +70,15 @@ ShenandoahAgeCensus::~ShenandoahAgeCensus() { for (uint i = 0; i < MAX_SNAPSHOTS; i++) { delete _global_age_tables[i]; } - FREE_C_HEAP_ARRAY(AgeTable*, _global_age_tables); - FREE_C_HEAP_ARRAY(uint, _tenuring_threshold); - CENSUS_NOISE(FREE_C_HEAP_ARRAY(ShenandoahNoiseStats, _global_noise)); + FREE_C_HEAP_ARRAY(_global_age_tables); + FREE_C_HEAP_ARRAY(_tenuring_threshold); + CENSUS_NOISE(FREE_C_HEAP_ARRAY(_global_noise)); if (_local_age_tables) { for (uint i = 0; i < _max_workers; i++) { delete _local_age_tables[i]; } - FREE_C_HEAP_ARRAY(AgeTable*, _local_age_tables); - CENSUS_NOISE(FREE_C_HEAP_ARRAY(ShenandoahNoiseStats, _local_noise)); + FREE_C_HEAP_ARRAY(_local_age_tables); + CENSUS_NOISE(FREE_C_HEAP_ARRAY(_local_noise)); } } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp index 21b1fd9e0a8..34092a744d5 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp @@ -261,7 +261,7 @@ void ShenandoahFullGC::do_it(GCCause::Cause gc_cause) { for (uint i = 0; i < heap->max_workers(); i++) { delete worker_slices[i]; } - FREE_C_HEAP_ARRAY(ShenandoahHeapRegionSet*, worker_slices); + FREE_C_HEAP_ARRAY(worker_slices); heap->set_full_gc_move_in_progress(false); heap->set_full_gc_in_progress(false); @@ -688,7 +688,7 @@ void ShenandoahFullGC::distribute_slices(ShenandoahHeapRegionSet** worker_slices } } - FREE_C_HEAP_ARRAY(size_t, live); + FREE_C_HEAP_ARRAY(live); #ifdef ASSERT ResourceBitMap map(n_regions); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionCounters.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionCounters.cpp index aaf152e2890..3e809ea84b9 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionCounters.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionCounters.cpp @@ -77,8 +77,8 @@ ShenandoahHeapRegionCounters::ShenandoahHeapRegionCounters() : } ShenandoahHeapRegionCounters::~ShenandoahHeapRegionCounters() { - if (_name_space != nullptr) FREE_C_HEAP_ARRAY(char, _name_space); - if (_regions_data != nullptr) FREE_C_HEAP_ARRAY(PerfVariable*, _regions_data); + if (_name_space != nullptr) FREE_C_HEAP_ARRAY(_name_space); + if (_regions_data != nullptr) FREE_C_HEAP_ARRAY(_regions_data); } void ShenandoahHeapRegionCounters::write_snapshot(PerfLongVariable** regions, diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionSet.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionSet.cpp index 560de816db9..1d2cd97b75d 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionSet.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionSet.cpp @@ -47,7 +47,7 @@ ShenandoahHeapRegionSet::ShenandoahHeapRegionSet() : } ShenandoahHeapRegionSet::~ShenandoahHeapRegionSet() { - FREE_C_HEAP_ARRAY(jbyte, _set_map); + FREE_C_HEAP_ARRAY(_set_map); } void ShenandoahHeapRegionSet::add_region(ShenandoahHeapRegion* r) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahNMethod.cpp b/src/hotspot/share/gc/shenandoah/shenandoahNMethod.cpp index 594ad614d90..1b9532b3748 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahNMethod.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahNMethod.cpp @@ -48,7 +48,7 @@ ShenandoahNMethod::ShenandoahNMethod(nmethod* nm, GrowableArray& oops, boo ShenandoahNMethod::~ShenandoahNMethod() { if (_oops != nullptr) { - FREE_C_HEAP_ARRAY(oop*, _oops); + FREE_C_HEAP_ARRAY(_oops); } } @@ -60,7 +60,7 @@ void ShenandoahNMethod::update() { detect_reloc_oops(nm(), oops, non_immediate_oops); if (oops.length() != _oops_count) { if (_oops != nullptr) { - FREE_C_HEAP_ARRAY(oop*, _oops); + FREE_C_HEAP_ARRAY(_oops); _oops = nullptr; } @@ -394,7 +394,7 @@ ShenandoahNMethodList::ShenandoahNMethodList(int size) : ShenandoahNMethodList::~ShenandoahNMethodList() { assert(_list != nullptr, "Sanity"); assert(_ref_count == 0, "Must be"); - FREE_C_HEAP_ARRAY(ShenandoahNMethod*, _list); + FREE_C_HEAP_ARRAY(_list); } void ShenandoahNMethodList::transfer(ShenandoahNMethodList* const list, int limit) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahNumberSeq.cpp b/src/hotspot/share/gc/shenandoah/shenandoahNumberSeq.cpp index 1ddd8e1c032..82b027faca2 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahNumberSeq.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahNumberSeq.cpp @@ -39,10 +39,10 @@ HdrSeq::~HdrSeq() { for (int c = 0; c < MagBuckets; c++) { int* sub = _hdr[c]; if (sub != nullptr) { - FREE_C_HEAP_ARRAY(int, sub); + FREE_C_HEAP_ARRAY(sub); } } - FREE_C_HEAP_ARRAY(int*, _hdr); + FREE_C_HEAP_ARRAY(_hdr); } void HdrSeq::add(double val) { @@ -191,7 +191,7 @@ BinaryMagnitudeSeq::BinaryMagnitudeSeq() { } BinaryMagnitudeSeq::~BinaryMagnitudeSeq() { - FREE_C_HEAP_ARRAY(size_t, _mags); + FREE_C_HEAP_ARRAY(_mags); } void BinaryMagnitudeSeq::clear() { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.hpp b/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.hpp index 53f00e64a03..244ed7edd4c 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.hpp @@ -413,7 +413,7 @@ public: } ~ShenandoahCardCluster() { - FREE_C_HEAP_ARRAY(crossing_info, _object_starts); + FREE_C_HEAP_ARRAY(_object_starts); _object_starts = nullptr; } @@ -751,7 +751,7 @@ public: for (uint i = 0; i < ParallelGCThreads; i++) { delete _card_stats[i]; } - FREE_C_HEAP_ARRAY(HdrSeq*, _card_stats); + FREE_C_HEAP_ARRAY(_card_stats); _card_stats = nullptr; } assert(_card_stats == nullptr, "Error"); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahSimpleBitMap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahSimpleBitMap.cpp index 82a759e34db..d0029b60167 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahSimpleBitMap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahSimpleBitMap.cpp @@ -35,7 +35,7 @@ ShenandoahSimpleBitMap::ShenandoahSimpleBitMap(idx_t num_bits) : ShenandoahSimpleBitMap::~ShenandoahSimpleBitMap() { if (_bitmap != nullptr) { - FREE_C_HEAP_ARRAY(uintx, _bitmap); + FREE_C_HEAP_ARRAY(_bitmap); } } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp index 8299cbe62c6..a801023fcc4 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp @@ -1073,7 +1073,7 @@ void ShenandoahVerifier::verify_at_safepoint(ShenandoahGeneration* generation, log_info(gc)("Verify %s, Level %zd (%zu reachable, %zu marked)", label, ShenandoahVerifyLevel, count_reachable, count_marked); - FREE_C_HEAP_ARRAY(ShenandoahLivenessData, ld); + FREE_C_HEAP_ARRAY(ld); } void ShenandoahVerifier::verify_generic(ShenandoahGeneration* generation, VerifyOption vo) { diff --git a/src/hotspot/share/gc/z/zForwardingAllocator.cpp b/src/hotspot/share/gc/z/zForwardingAllocator.cpp index 451a1d62754..37b5b8f520c 100644 --- a/src/hotspot/share/gc/z/zForwardingAllocator.cpp +++ b/src/hotspot/share/gc/z/zForwardingAllocator.cpp @@ -30,11 +30,11 @@ ZForwardingAllocator::ZForwardingAllocator() _top(nullptr) {} ZForwardingAllocator::~ZForwardingAllocator() { - FREE_C_HEAP_ARRAY(char, _start); + FREE_C_HEAP_ARRAY(_start); } void ZForwardingAllocator::reset(size_t size) { - _start = REALLOC_C_HEAP_ARRAY(char, _start, size, mtGC); + _start = REALLOC_C_HEAP_ARRAY(_start, size, mtGC); _top.store_relaxed(_start); _end = _start + size; } diff --git a/src/hotspot/share/interpreter/oopMapCache.cpp b/src/hotspot/share/interpreter/oopMapCache.cpp index af45f7f9bed..34e226b00bf 100644 --- a/src/hotspot/share/interpreter/oopMapCache.cpp +++ b/src/hotspot/share/interpreter/oopMapCache.cpp @@ -156,7 +156,7 @@ InterpreterOopMap::InterpreterOopMap() { InterpreterOopMap::~InterpreterOopMap() { if (has_valid_mask() && mask_size() > small_mask_limit) { assert(_bit_mask[0] != 0, "should have pointer to C heap"); - FREE_C_HEAP_ARRAY(uintptr_t, _bit_mask[0]); + FREE_C_HEAP_ARRAY((uintptr_t*)_bit_mask[0]); } } @@ -288,7 +288,7 @@ void OopMapCacheEntry::deallocate_bit_mask() { if (mask_size() > small_mask_limit && _bit_mask[0] != 0) { assert(!Thread::current()->resource_area()->contains((void*)_bit_mask[0]), "This bit mask should not be in the resource area"); - FREE_C_HEAP_ARRAY(uintptr_t, _bit_mask[0]); + FREE_C_HEAP_ARRAY((uintptr_t*)_bit_mask[0]); DEBUG_ONLY(_bit_mask[0] = 0;) } } diff --git a/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp b/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp index a6e97ab227a..32710595d27 100644 --- a/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp +++ b/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp @@ -528,7 +528,7 @@ const char* JfrJavaSupport::c_str(jstring string, Thread* thread, bool c_heap /* void JfrJavaSupport::free_c_str(const char* str, bool c_heap) { if (c_heap) { - FREE_C_HEAP_ARRAY(char, str); + FREE_C_HEAP_ARRAY(str); } } diff --git a/src/hotspot/share/jfr/leakprofiler/sampling/samplePriorityQueue.cpp b/src/hotspot/share/jfr/leakprofiler/sampling/samplePriorityQueue.cpp index 644cd25ec8a..5eac068467f 100644 --- a/src/hotspot/share/jfr/leakprofiler/sampling/samplePriorityQueue.cpp +++ b/src/hotspot/share/jfr/leakprofiler/sampling/samplePriorityQueue.cpp @@ -36,7 +36,7 @@ SamplePriorityQueue::SamplePriorityQueue(size_t size) : } SamplePriorityQueue::~SamplePriorityQueue() { - FREE_C_HEAP_ARRAY(ObjectSample*, _items); + FREE_C_HEAP_ARRAY(_items); _items = nullptr; } diff --git a/src/hotspot/share/jfr/periodic/jfrNetworkUtilization.cpp b/src/hotspot/share/jfr/periodic/jfrNetworkUtilization.cpp index 11e211f6505..1650ad7d9c0 100644 --- a/src/hotspot/share/jfr/periodic/jfrNetworkUtilization.cpp +++ b/src/hotspot/share/jfr/periodic/jfrNetworkUtilization.cpp @@ -46,7 +46,7 @@ static GrowableArray* _interfaces = nullptr; void JfrNetworkUtilization::destroy() { if (_interfaces != nullptr) { for (int i = 0; i < _interfaces->length(); ++i) { - FREE_C_HEAP_ARRAY(char, _interfaces->at(i).name); + FREE_C_HEAP_ARRAY(_interfaces->at(i).name); } delete _interfaces; _interfaces = nullptr; diff --git a/src/hotspot/share/jfr/recorder/service/jfrOptionSet.cpp b/src/hotspot/share/jfr/recorder/service/jfrOptionSet.cpp index b212ee4ccba..ec8ab36d75a 100644 --- a/src/hotspot/share/jfr/recorder/service/jfrOptionSet.cpp +++ b/src/hotspot/share/jfr/recorder/service/jfrOptionSet.cpp @@ -799,7 +799,7 @@ void JfrOptionSet::release_start_flight_recording_options() { if (start_flight_recording_options_array != nullptr) { const int length = start_flight_recording_options_array->length(); for (int i = 0; i < length; ++i) { - FREE_C_HEAP_ARRAY(char, start_flight_recording_options_array->at(i)); + FREE_C_HEAP_ARRAY(start_flight_recording_options_array->at(i)); } delete start_flight_recording_options_array; start_flight_recording_options_array = nullptr; diff --git a/src/hotspot/share/jfr/recorder/stacktrace/jfrStackFilter.cpp b/src/hotspot/share/jfr/recorder/stacktrace/jfrStackFilter.cpp index 1eb057b564e..39a1c621888 100644 --- a/src/hotspot/share/jfr/recorder/stacktrace/jfrStackFilter.cpp +++ b/src/hotspot/share/jfr/recorder/stacktrace/jfrStackFilter.cpp @@ -55,6 +55,6 @@ JfrStackFilter::~JfrStackFilter() { Symbol::maybe_decrement_refcount(_method_names[i]); Symbol::maybe_decrement_refcount(_class_names[i]); } - FREE_C_HEAP_ARRAY(Symbol*, _method_names); - FREE_C_HEAP_ARRAY(Symbol*, _class_names); + FREE_C_HEAP_ARRAY(_method_names); + FREE_C_HEAP_ARRAY(_class_names); } diff --git a/src/hotspot/share/jfr/recorder/stacktrace/jfrStackFilterRegistry.cpp b/src/hotspot/share/jfr/recorder/stacktrace/jfrStackFilterRegistry.cpp index 0721604b1c1..cb9811e7cae 100644 --- a/src/hotspot/share/jfr/recorder/stacktrace/jfrStackFilterRegistry.cpp +++ b/src/hotspot/share/jfr/recorder/stacktrace/jfrStackFilterRegistry.cpp @@ -43,8 +43,8 @@ int64_t JfrStackFilterRegistry::add(jobjectArray classes, jobjectArray methods, Symbol** method_names = JfrJavaSupport::symbol_array(methods, jt, &m_size, true); assert(method_names != nullptr, "invariant"); if (c_size != m_size) { - FREE_C_HEAP_ARRAY(Symbol*, class_names); - FREE_C_HEAP_ARRAY(Symbol*, method_names); + FREE_C_HEAP_ARRAY(class_names); + FREE_C_HEAP_ARRAY(method_names); JfrJavaSupport::throw_internal_error("Method array size doesn't match class array size", jt); return STACK_FILTER_ERROR_CODE; } diff --git a/src/hotspot/share/jfr/support/methodtracer/jfrFilter.cpp b/src/hotspot/share/jfr/support/methodtracer/jfrFilter.cpp index 2a977f9e823..767036b57f2 100644 --- a/src/hotspot/share/jfr/support/methodtracer/jfrFilter.cpp +++ b/src/hotspot/share/jfr/support/methodtracer/jfrFilter.cpp @@ -51,10 +51,10 @@ JfrFilter::~JfrFilter() { Symbol::maybe_decrement_refcount(_method_names[i]); Symbol::maybe_decrement_refcount(_annotation_names[i]); } - FREE_C_HEAP_ARRAY(Symbol*, _class_names); - FREE_C_HEAP_ARRAY(Symbol*, _method_names); - FREE_C_HEAP_ARRAY(Symbol*, _annotation_names); - FREE_C_HEAP_ARRAY(int, _modifications); + FREE_C_HEAP_ARRAY(_class_names); + FREE_C_HEAP_ARRAY(_method_names); + FREE_C_HEAP_ARRAY(_annotation_names); + FREE_C_HEAP_ARRAY(_modifications); } bool JfrFilter::can_instrument_module(const ModuleEntry* module) const { diff --git a/src/hotspot/share/jfr/support/methodtracer/jfrFilterManager.cpp b/src/hotspot/share/jfr/support/methodtracer/jfrFilterManager.cpp index d9081efa08c..ea031f9f205 100644 --- a/src/hotspot/share/jfr/support/methodtracer/jfrFilterManager.cpp +++ b/src/hotspot/share/jfr/support/methodtracer/jfrFilterManager.cpp @@ -130,10 +130,10 @@ bool JfrFilterManager::install(jobjectArray classes, jobjectArray methods, jobje modifications[i] = modification_tah->int_at(i); } if (class_size != method_size || class_size != annotation_size || class_size != modification_size) { - FREE_C_HEAP_ARRAY(Symbol*, class_names); - FREE_C_HEAP_ARRAY(Symbol*, method_names); - FREE_C_HEAP_ARRAY(Symbol*, annotation_names); - FREE_C_HEAP_ARRAY(int, modifications); + FREE_C_HEAP_ARRAY(class_names); + FREE_C_HEAP_ARRAY(method_names); + FREE_C_HEAP_ARRAY(annotation_names); + FREE_C_HEAP_ARRAY(modifications); JfrJavaSupport::throw_internal_error("Method array sizes don't match", jt); return false; } diff --git a/src/hotspot/share/jfr/utilities/jfrConcurrentHashtable.inline.hpp b/src/hotspot/share/jfr/utilities/jfrConcurrentHashtable.inline.hpp index 6d6908234a3..22028a96e55 100644 --- a/src/hotspot/share/jfr/utilities/jfrConcurrentHashtable.inline.hpp +++ b/src/hotspot/share/jfr/utilities/jfrConcurrentHashtable.inline.hpp @@ -59,7 +59,7 @@ inline JfrConcurrentHashtable::JfrConcurrentHashtable(uns template class TableEntry> inline JfrConcurrentHashtable::~JfrConcurrentHashtable() { - FREE_C_HEAP_ARRAY(Bucket, _buckets); + FREE_C_HEAP_ARRAY(_buckets); } template class TableEntry> diff --git a/src/hotspot/share/jfr/utilities/jfrHashtable.hpp b/src/hotspot/share/jfr/utilities/jfrHashtable.hpp index 0be2d92ed19..ce4c920cf8b 100644 --- a/src/hotspot/share/jfr/utilities/jfrHashtable.hpp +++ b/src/hotspot/share/jfr/utilities/jfrHashtable.hpp @@ -93,7 +93,7 @@ class JfrBasicHashtable : public CHeapObj { --_number_of_entries; } void free_buckets() { - FREE_C_HEAP_ARRAY(Bucket, _buckets); + FREE_C_HEAP_ARRAY(_buckets); } TableEntry* bucket(size_t i) { return _buckets[i].get_entry();} TableEntry** bucket_addr(size_t i) { return _buckets[i].entry_addr(); } diff --git a/src/hotspot/share/jfr/utilities/jfrSet.hpp b/src/hotspot/share/jfr/utilities/jfrSet.hpp index c443434800a..3e828d51ec3 100644 --- a/src/hotspot/share/jfr/utilities/jfrSet.hpp +++ b/src/hotspot/share/jfr/utilities/jfrSet.hpp @@ -82,7 +82,7 @@ class JfrSetStorage : public AnyObj { ~JfrSetStorage() { if (CONFIG::alloc_type() == C_HEAP) { - FREE_C_HEAP_ARRAY(K, _table); + FREE_C_HEAP_ARRAY(_table); } } @@ -160,7 +160,7 @@ class JfrSet : public JfrSetStorage { } } if (CONFIG::alloc_type() == AnyObj::C_HEAP) { - FREE_C_HEAP_ARRAY(K, old_table); + FREE_C_HEAP_ARRAY(old_table); } assert(_table_mask + 1 == this->_table_size, "invariant"); assert(_resize_threshold << 1 == this->_table_size, "invariant"); diff --git a/src/hotspot/share/libadt/vectset.cpp b/src/hotspot/share/libadt/vectset.cpp index 176660d8302..bd9e97d9877 100644 --- a/src/hotspot/share/libadt/vectset.cpp +++ b/src/hotspot/share/libadt/vectset.cpp @@ -51,7 +51,7 @@ void VectorSet::grow(uint new_word_capacity) { assert(new_word_capacity < (1U << 30), ""); uint x = next_power_of_2(new_word_capacity); if (x > _data_size) { - _data = REALLOC_ARENA_ARRAY(_set_arena, uint32_t, _data, _size, x); + _data = REALLOC_ARENA_ARRAY(_set_arena, _data, _size, x); _data_size = x; } Copy::zero_to_bytes(_data + _size, (x - _size) * sizeof(uint32_t)); diff --git a/src/hotspot/share/logging/logAsyncWriter.hpp b/src/hotspot/share/logging/logAsyncWriter.hpp index a93b1ca58f6..933482929c7 100644 --- a/src/hotspot/share/logging/logAsyncWriter.hpp +++ b/src/hotspot/share/logging/logAsyncWriter.hpp @@ -124,7 +124,7 @@ class AsyncLogWriter : public NonJavaThread { } ~Buffer() { - FREE_C_HEAP_ARRAY(char, _buf); + FREE_C_HEAP_ARRAY(_buf); } void push_flush_token(); diff --git a/src/hotspot/share/logging/logConfiguration.cpp b/src/hotspot/share/logging/logConfiguration.cpp index b883dbccacf..1ba45cc050f 100644 --- a/src/hotspot/share/logging/logConfiguration.cpp +++ b/src/hotspot/share/logging/logConfiguration.cpp @@ -123,7 +123,7 @@ void LogConfiguration::initialize(jlong vm_start_time) { void LogConfiguration::finalize() { disable_outputs(); - FREE_C_HEAP_ARRAY(LogOutput*, _outputs); + FREE_C_HEAP_ARRAY(_outputs); } // Normalizes the given LogOutput name to type=name form. @@ -206,7 +206,7 @@ LogOutput* LogConfiguration::new_output(const char* name, size_t LogConfiguration::add_output(LogOutput* output) { size_t idx = _n_outputs++; - _outputs = REALLOC_C_HEAP_ARRAY(LogOutput*, _outputs, _n_outputs, mtLogging); + _outputs = REALLOC_C_HEAP_ARRAY(_outputs, _n_outputs, mtLogging); _outputs[idx] = output; return idx; } @@ -218,7 +218,7 @@ void LogConfiguration::delete_output(size_t idx) { LogOutput* output = _outputs[idx]; // Swap places with the last output and shrink the array _outputs[idx] = _outputs[--_n_outputs]; - _outputs = REALLOC_C_HEAP_ARRAY(LogOutput*, _outputs, _n_outputs, mtLogging); + _outputs = REALLOC_C_HEAP_ARRAY(_outputs, _n_outputs, mtLogging); delete output; } @@ -546,7 +546,7 @@ bool LogConfiguration::parse_log_arguments(const char* outputstr, } } - FREE_C_HEAP_ARRAY(char, normalized); + FREE_C_HEAP_ARRAY(normalized); if (idx == SIZE_MAX) { return false; } @@ -724,8 +724,7 @@ void LogConfiguration::register_update_listener(UpdateListenerFunction cb) { assert(cb != nullptr, "Should not register nullptr as listener"); ConfigurationLock cl; size_t idx = _n_listener_callbacks++; - _listener_callbacks = REALLOC_C_HEAP_ARRAY(UpdateListenerFunction, - _listener_callbacks, + _listener_callbacks = REALLOC_C_HEAP_ARRAY(_listener_callbacks, _n_listener_callbacks, mtLogging); _listener_callbacks[idx] = cb; diff --git a/src/hotspot/share/logging/logFileOutput.cpp b/src/hotspot/share/logging/logFileOutput.cpp index 9d6d19d739e..c805a3e1077 100644 --- a/src/hotspot/share/logging/logFileOutput.cpp +++ b/src/hotspot/share/logging/logFileOutput.cpp @@ -160,8 +160,8 @@ static uint next_file_number(const char* filename, } } - FREE_C_HEAP_ARRAY(char, oldest_name); - FREE_C_HEAP_ARRAY(char, archive_name); + FREE_C_HEAP_ARRAY(oldest_name); + FREE_C_HEAP_ARRAY(archive_name); return next_num; } diff --git a/src/hotspot/share/logging/logMessageBuffer.cpp b/src/hotspot/share/logging/logMessageBuffer.cpp index 8f308b1f015..4714cd65f8a 100644 --- a/src/hotspot/share/logging/logMessageBuffer.cpp +++ b/src/hotspot/share/logging/logMessageBuffer.cpp @@ -31,7 +31,7 @@ static void grow(T*& buffer, size_t& capacity, size_t minimum_length = 0) { if (new_size < minimum_length) { new_size = minimum_length; } - buffer = REALLOC_C_HEAP_ARRAY(T, buffer, new_size, mtLogging); + buffer = REALLOC_C_HEAP_ARRAY(buffer, new_size, mtLogging); capacity = new_size; } @@ -48,8 +48,8 @@ LogMessageBuffer::LogMessageBuffer() : _message_buffer_size(0), LogMessageBuffer::~LogMessageBuffer() { if (_allocated) { - FREE_C_HEAP_ARRAY(char, _message_buffer); - FREE_C_HEAP_ARRAY(LogLine, _lines); + FREE_C_HEAP_ARRAY(_message_buffer); + FREE_C_HEAP_ARRAY(_lines); } } diff --git a/src/hotspot/share/logging/logOutput.cpp b/src/hotspot/share/logging/logOutput.cpp index e3c68b49b13..f74e614e539 100644 --- a/src/hotspot/share/logging/logOutput.cpp +++ b/src/hotspot/share/logging/logOutput.cpp @@ -181,7 +181,7 @@ static void add_selections(LogSelection** selections, // Ensure there's enough room for both wildcard_match and exact_match if (*n_selections + 2 > *selections_cap) { *selections_cap *= 2; - *selections = REALLOC_C_HEAP_ARRAY(LogSelection, *selections, *selections_cap, mtLogging); + *selections = REALLOC_C_HEAP_ARRAY(*selections, *selections_cap, mtLogging); } // Add found matching selections to the result array @@ -317,8 +317,8 @@ void LogOutput::update_config_string(const size_t on_level[LogLevel::Count]) { break; } } - FREE_C_HEAP_ARRAY(LogTagSet*, deviates); - FREE_C_HEAP_ARRAY(Selection, selections); + FREE_C_HEAP_ARRAY(deviates); + FREE_C_HEAP_ARRAY(selections); } bool LogOutput::parse_options(const char* options, outputStream* errstream) { diff --git a/src/hotspot/share/logging/logTagSet.cpp b/src/hotspot/share/logging/logTagSet.cpp index 667c76ec306..28b0d697b14 100644 --- a/src/hotspot/share/logging/logTagSet.cpp +++ b/src/hotspot/share/logging/logTagSet.cpp @@ -215,5 +215,5 @@ void LogTagSet::list_all_tagsets(outputStream* out) { os::free(tagset_labels[idx]); } out->cr(); - FREE_C_HEAP_ARRAY(char*, tagset_labels); + FREE_C_HEAP_ARRAY(tagset_labels); } diff --git a/src/hotspot/share/memory/allocation.hpp b/src/hotspot/share/memory/allocation.hpp index 15b7750a363..d43add7cb66 100644 --- a/src/hotspot/share/memory/allocation.hpp +++ b/src/hotspot/share/memory/allocation.hpp @@ -95,7 +95,7 @@ typedef AllocFailStrategy::AllocFailEnum AllocFailType; // // char* AllocateHeap(size_t size, MemTag mem_tag, const NativeCallStack& stack, AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM); // char* AllocateHeap(size_t size, MemTag mem_tag, AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM); -// char* ReallocateHeap(char *old, size_t size, MemTag mem_tag, AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM); +// char* ReallocateHeap(char* old, size_t size, MemTag mem_tag, AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM); // void FreeHeap(void* p); // @@ -112,7 +112,7 @@ char* AllocateHeap(size_t size, MemTag mem_tag, AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM); -char* ReallocateHeap(char *old, +char* ReallocateHeap(char* old, size_t size, MemTag mem_tag, AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM); @@ -374,9 +374,9 @@ extern char* resource_allocate_bytes(size_t size, AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM); extern char* resource_allocate_bytes(Thread* thread, size_t size, AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM); -extern char* resource_reallocate_bytes( char *old, size_t old_size, size_t new_size, +extern char* resource_reallocate_bytes(char* old, size_t old_size, size_t new_size, AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM); -extern void resource_free_bytes( Thread* thread, char *old, size_t size ); +extern void resource_free_bytes(Thread* thread, char* obj, size_t size); //---------------------------------------------------------------------- // Base class for objects allocated in the resource area. @@ -479,6 +479,8 @@ protected: #endif // PRODUCT }; +#define REALLOC_RETURN_TYPE(old) typename std::remove_reference::type + // One of the following macros must be used when allocating an array // or object to determine whether it should reside in the C heap on in // the resource area. @@ -495,21 +497,18 @@ protected: #define NEW_RESOURCE_ARRAY_IN_THREAD_RETURN_NULL(thread, type, size)\ (type*) resource_allocate_bytes(thread, (size) * sizeof(type), AllocFailStrategy::RETURN_NULL) -#define REALLOC_RESOURCE_ARRAY(type, old, old_size, new_size)\ - (type*) resource_reallocate_bytes((char*)(old), (old_size) * sizeof(type), (new_size) * sizeof(type)) +#define REALLOC_RESOURCE_ARRAY(old, old_size, new_size)\ + (REALLOC_RETURN_TYPE(old)) resource_reallocate_bytes((char*)(old), (old_size) * sizeof(*old), (new_size) * sizeof(*old)) -#define REALLOC_RESOURCE_ARRAY_RETURN_NULL(type, old, old_size, new_size)\ - (type*) resource_reallocate_bytes((char*)(old), (old_size) * sizeof(type),\ - (new_size) * sizeof(type), AllocFailStrategy::RETURN_NULL) +#define REALLOC_RESOURCE_ARRAY_RETURN_NULL(old, old_size, new_size)\ + (REALLOC_RETURN_TYPE(old)) resource_reallocate_bytes((char*)(old), (old_size) * sizeof(*old), \ + (new_size) * sizeof(*old), AllocFailStrategy::RETURN_NULL) -#define FREE_RESOURCE_ARRAY(type, old, size)\ - resource_free_bytes(Thread::current(), (char*)(old), (size) * sizeof(type)) +#define FREE_RESOURCE_ARRAY(obj, size)\ + resource_free_bytes(Thread::current(), (char*)(obj), (size) * sizeof(*obj)) -#define FREE_RESOURCE_ARRAY_IN_THREAD(thread, type, old, size)\ - resource_free_bytes(thread, (char*)(old), (size) * sizeof(type)) - -#define FREE_FAST(old)\ - /* nop */ +#define FREE_RESOURCE_ARRAY_IN_THREAD(thread, obj, size)\ + resource_free_bytes(thread, (char*)(obj), (size) * sizeof(*obj)) #define NEW_RESOURCE_OBJ(type)\ NEW_RESOURCE_ARRAY(type, 1) @@ -532,14 +531,14 @@ protected: #define NEW_C_HEAP_ARRAY_RETURN_NULL(type, size, mem_tag)\ NEW_C_HEAP_ARRAY2(type, (size), mem_tag, AllocFailStrategy::RETURN_NULL) -#define REALLOC_C_HEAP_ARRAY(type, old, size, mem_tag)\ - (type*) (ReallocateHeap((char*)(old), (size) * sizeof(type), mem_tag)) +#define REALLOC_C_HEAP_ARRAY(old, size, mem_tag)\ + (REALLOC_RETURN_TYPE(old)) ReallocateHeap((char*)(old), (size) * sizeof(*old), mem_tag) -#define REALLOC_C_HEAP_ARRAY_RETURN_NULL(type, old, size, mem_tag)\ - (type*) (ReallocateHeap((char*)(old), (size) * sizeof(type), mem_tag, AllocFailStrategy::RETURN_NULL)) +#define REALLOC_C_HEAP_ARRAY_RETURN_NULL(old, size, mem_tag)\ + (REALLOC_RETURN_TYPE(old)) ReallocateHeap((char*)(old), (size) * sizeof(*old), mem_tag, AllocFailStrategy::RETURN_NULL) -#define FREE_C_HEAP_ARRAY(type, old) \ - FreeHeap((char*)(old)) +#define FREE_C_HEAP_ARRAY(obj) \ + FreeHeap((void*)(obj)) // allocate type in heap without calling ctor #define NEW_C_HEAP_OBJ(type, mem_tag)\ @@ -548,9 +547,9 @@ protected: #define NEW_C_HEAP_OBJ_RETURN_NULL(type, mem_tag)\ NEW_C_HEAP_ARRAY_RETURN_NULL(type, 1, mem_tag) -// deallocate obj of type in heap without calling dtor -#define FREE_C_HEAP_OBJ(objname)\ - FreeHeap((char*)objname); +// deallocate obj in heap without calling dtor +#define FREE_C_HEAP_OBJ(obj)\ + FREE_C_HEAP_ARRAY(obj) //------------------------------ReallocMark--------------------------------- diff --git a/src/hotspot/share/memory/arena.hpp b/src/hotspot/share/memory/arena.hpp index 7d88c79ca52..252e511f615 100644 --- a/src/hotspot/share/memory/arena.hpp +++ b/src/hotspot/share/memory/arena.hpp @@ -240,12 +240,12 @@ private: #define NEW_ARENA_ARRAY(arena, type, size) \ (type*) (arena)->Amalloc((size) * sizeof(type)) -#define REALLOC_ARENA_ARRAY(arena, type, old, old_size, new_size) \ - (type*) (arena)->Arealloc((char*)(old), (old_size) * sizeof(type), \ - (new_size) * sizeof(type) ) +#define REALLOC_ARENA_ARRAY(arena, old, old_size, new_size) \ + (REALLOC_RETURN_TYPE(old)) (arena)->Arealloc((char*)(old), (old_size) * sizeof(*old), \ + (new_size) * sizeof(*old) ) -#define FREE_ARENA_ARRAY(arena, type, old, size) \ - (arena)->Afree((char*)(old), (size) * sizeof(type)) +#define FREE_ARENA_ARRAY(arena, obj, size) \ + (arena)->Afree((char*)(obj), (size) * sizeof(*obj)) #define NEW_ARENA_OBJ(arena, type) \ NEW_ARENA_ARRAY(arena, type, 1) diff --git a/src/hotspot/share/memory/heapInspection.cpp b/src/hotspot/share/memory/heapInspection.cpp index aae3c99a634..5abb7e4ddcc 100644 --- a/src/hotspot/share/memory/heapInspection.cpp +++ b/src/hotspot/share/memory/heapInspection.cpp @@ -189,7 +189,7 @@ KlassInfoTable::~KlassInfoTable() { for (int index = 0; index < _num_buckets; index++) { _buckets[index].empty(); } - FREE_C_HEAP_ARRAY(KlassInfoBucket, _buckets); + FREE_C_HEAP_ARRAY(_buckets); _buckets = nullptr; } } diff --git a/src/hotspot/share/memory/memRegion.cpp b/src/hotspot/share/memory/memRegion.cpp index 3c481926025..dde4b0ace9a 100644 --- a/src/hotspot/share/memory/memRegion.cpp +++ b/src/hotspot/share/memory/memRegion.cpp @@ -115,5 +115,5 @@ void MemRegion::destroy_array(MemRegion* array, size_t length) { for (size_t i = 0; i < length; i++) { array[i].~MemRegion(); } - FREE_C_HEAP_ARRAY(MemRegion, array); + FREE_C_HEAP_ARRAY(array); } diff --git a/src/hotspot/share/memory/metaspace/rootChunkArea.cpp b/src/hotspot/share/memory/metaspace/rootChunkArea.cpp index a178e122788..39407b46999 100644 --- a/src/hotspot/share/memory/metaspace/rootChunkArea.cpp +++ b/src/hotspot/share/memory/metaspace/rootChunkArea.cpp @@ -473,7 +473,7 @@ RootChunkAreaLUT::~RootChunkAreaLUT() { for (int i = 0; i < _num; i++) { _arr[i].~RootChunkArea(); } - FREE_C_HEAP_ARRAY(RootChunkArea, _arr); + FREE_C_HEAP_ARRAY(_arr); } #ifdef ASSERT diff --git a/src/hotspot/share/memory/resourceArea.cpp b/src/hotspot/share/memory/resourceArea.cpp index bab652c17ea..63f7ed61d17 100644 --- a/src/hotspot/share/memory/resourceArea.cpp +++ b/src/hotspot/share/memory/resourceArea.cpp @@ -70,10 +70,10 @@ extern char* resource_allocate_bytes(Thread* thread, size_t size, AllocFailType return thread->resource_area()->allocate_bytes(size, alloc_failmode); } -extern char* resource_reallocate_bytes( char *old, size_t old_size, size_t new_size, AllocFailType alloc_failmode){ +extern char* resource_reallocate_bytes(char* old, size_t old_size, size_t new_size, AllocFailType alloc_failmode){ return (char*)Thread::current()->resource_area()->Arealloc(old, old_size, new_size, alloc_failmode); } -extern void resource_free_bytes( Thread* thread, char *old, size_t size ) { - thread->resource_area()->Afree(old, size); +extern void resource_free_bytes(Thread* thread, char* obj, size_t size) { + thread->resource_area()->Afree(obj, size); } diff --git a/src/hotspot/share/memory/universe.cpp b/src/hotspot/share/memory/universe.cpp index a78b245cc07..aecaa1cac22 100644 --- a/src/hotspot/share/memory/universe.cpp +++ b/src/hotspot/share/memory/universe.cpp @@ -1256,7 +1256,7 @@ void Universe::initialize_verify_flags() { } token = strtok_r(nullptr, delimiter, &save_ptr); } - FREE_C_HEAP_ARRAY(char, subset_list); + FREE_C_HEAP_ARRAY(subset_list); } bool Universe::should_verify_subset(uint subset) { diff --git a/src/hotspot/share/nmt/nmtNativeCallStackStorage.cpp b/src/hotspot/share/nmt/nmtNativeCallStackStorage.cpp index 9a2ecd57ecc..bbf93c5d898 100644 --- a/src/hotspot/share/nmt/nmtNativeCallStackStorage.cpp +++ b/src/hotspot/share/nmt/nmtNativeCallStackStorage.cpp @@ -55,7 +55,7 @@ NativeCallStackStorage::NativeCallStackStorage(bool is_detailed_mode, int table_ } } NativeCallStackStorage::~NativeCallStackStorage() { - FREE_C_HEAP_ARRAY(LinkPtr, _table); + FREE_C_HEAP_ARRAY(_table); } NativeCallStackStorage::NativeCallStackStorage(const NativeCallStackStorage& other) diff --git a/src/hotspot/share/nmt/vmatree.cpp b/src/hotspot/share/nmt/vmatree.cpp index 6c5ab691f6d..1fc05133d22 100644 --- a/src/hotspot/share/nmt/vmatree.cpp +++ b/src/hotspot/share/nmt/vmatree.cpp @@ -807,7 +807,7 @@ void VMATree::SummaryDiff::grow_and_rehash() { // Clear previous -- if applicable if (_members != _small) { - FREE_C_HEAP_ARRAY(KVEntry, _members); + FREE_C_HEAP_ARRAY(_members); } _members = NEW_C_HEAP_ARRAY(KVEntry, new_len, mtNMT); @@ -847,7 +847,7 @@ void VMATree::SummaryDiff::add(const SummaryDiff& other) { void VMATree::SummaryDiff::clear() { if (_members != _small) { - FREE_C_HEAP_ARRAY(KVEntry, _members); + FREE_C_HEAP_ARRAY(_members); } memset(_small, 0, sizeof(_small)); } diff --git a/src/hotspot/share/nmt/vmatree.hpp b/src/hotspot/share/nmt/vmatree.hpp index ae732a4b0d3..7054249319f 100644 --- a/src/hotspot/share/nmt/vmatree.hpp +++ b/src/hotspot/share/nmt/vmatree.hpp @@ -264,7 +264,7 @@ public: } ~SummaryDiff() { if (_members != _small) { - FREE_C_HEAP_ARRAY(KVEntry, _members); + FREE_C_HEAP_ARRAY(_members); } } diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp index d675e61cc05..9f33e6351a9 100644 --- a/src/hotspot/share/oops/instanceKlass.cpp +++ b/src/hotspot/share/oops/instanceKlass.cpp @@ -2542,7 +2542,7 @@ void InstanceKlass::update_methods_jmethod_cache() { new_cache[i] = cache[i]; } _methods_jmethod_ids = new_cache; - FREE_C_HEAP_ARRAY(jmethodID, cache); + FREE_C_HEAP_ARRAY(cache); } } } @@ -3016,7 +3016,7 @@ void InstanceKlass::release_C_heap_structures(bool release_sub_metadata) { } #endif - FREE_C_HEAP_ARRAY(char, _source_debug_extension); + FREE_C_HEAP_ARRAY(_source_debug_extension); if (release_sub_metadata) { constants()->release_C_heap_structures(); diff --git a/src/hotspot/share/opto/block.cpp b/src/hotspot/share/opto/block.cpp index a93e2e43a29..1da63ce8180 100644 --- a/src/hotspot/share/opto/block.cpp +++ b/src/hotspot/share/opto/block.cpp @@ -1430,7 +1430,7 @@ void UnionFind::extend( uint from_idx, uint to_idx ) { if( from_idx >= _max ) { uint size = 16; while( size <= from_idx ) size <<=1; - _indices = REALLOC_RESOURCE_ARRAY( uint, _indices, _max, size ); + _indices = REALLOC_RESOURCE_ARRAY( _indices, _max, size ); _max = size; } while( _cnt <= from_idx ) _indices[_cnt++] = 0; diff --git a/src/hotspot/share/opto/chaitin.cpp b/src/hotspot/share/opto/chaitin.cpp index ef017ee15ec..606d45d4a12 100644 --- a/src/hotspot/share/opto/chaitin.cpp +++ b/src/hotspot/share/opto/chaitin.cpp @@ -265,7 +265,7 @@ PhaseChaitin::PhaseChaitin(uint unique, PhaseCFG &cfg, Matcher &matcher, bool sc assert((&buckets[0][0] + nr_blocks) == offset, "should be"); // Free the now unused memory - FREE_RESOURCE_ARRAY(Block*, buckets[1], (NUMBUCKS-1)*nr_blocks); + FREE_RESOURCE_ARRAY(buckets[1], (NUMBUCKS-1)*nr_blocks); // Finally, point the _blks to our memory _blks = buckets[0]; diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index e05df8ea716..382c8f89a5f 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -1618,7 +1618,7 @@ void Compile::grow_alias_types() { const int new_ats = old_ats; // how many more? const int grow_ats = old_ats+new_ats; // how many now? _max_alias_types = grow_ats; - _alias_types = REALLOC_ARENA_ARRAY(comp_arena(), AliasType*, _alias_types, old_ats, grow_ats); + _alias_types = REALLOC_ARENA_ARRAY(comp_arena(), _alias_types, old_ats, grow_ats); AliasType* ats = NEW_ARENA_ARRAY(comp_arena(), AliasType, new_ats); Copy::zero_to_bytes(ats, sizeof(AliasType)*new_ats); for (int i = 0; i < new_ats; i++) _alias_types[old_ats+i] = &ats[i]; diff --git a/src/hotspot/share/opto/loopnode.cpp b/src/hotspot/share/opto/loopnode.cpp index 35a9108892c..13feeb77947 100644 --- a/src/hotspot/share/opto/loopnode.cpp +++ b/src/hotspot/share/opto/loopnode.cpp @@ -5938,8 +5938,8 @@ void PhaseIdealLoop::set_idom(Node* d, Node* n, uint dom_depth) { uint idx = d->_idx; if (idx >= _idom_size) { uint newsize = next_power_of_2(idx); - _idom = REALLOC_ARENA_ARRAY(&_arena, Node*, _idom,_idom_size,newsize); - _dom_depth = REALLOC_ARENA_ARRAY(&_arena, uint, _dom_depth,_idom_size,newsize); + _idom = REALLOC_ARENA_ARRAY(&_arena, _idom, _idom_size, newsize); + _dom_depth = REALLOC_ARENA_ARRAY(&_arena, _dom_depth, _idom_size, newsize); memset( _dom_depth + _idom_size, 0, (newsize - _idom_size) * sizeof(uint) ); _idom_size = newsize; } diff --git a/src/hotspot/share/opto/loopnode.hpp b/src/hotspot/share/opto/loopnode.hpp index 26b82259327..4eef2fed415 100644 --- a/src/hotspot/share/opto/loopnode.hpp +++ b/src/hotspot/share/opto/loopnode.hpp @@ -914,7 +914,7 @@ class PhaseIdealLoop : public PhaseTransform { void reallocate_preorders() { _nesting.check(); // Check if a potential re-allocation in the resource arena is safe if ( _max_preorder < C->unique() ) { - _preorders = REALLOC_RESOURCE_ARRAY(uint, _preorders, _max_preorder, C->unique()); + _preorders = REALLOC_RESOURCE_ARRAY(_preorders, _max_preorder, C->unique()); _max_preorder = C->unique(); } memset(_preorders, 0, sizeof(uint) * _max_preorder); @@ -926,7 +926,7 @@ class PhaseIdealLoop : public PhaseTransform { _nesting.check(); // Check if a potential re-allocation in the resource arena is safe if ( _max_preorder < C->unique() ) { uint newsize = _max_preorder<<1; // double size of array - _preorders = REALLOC_RESOURCE_ARRAY(uint, _preorders, _max_preorder, newsize); + _preorders = REALLOC_RESOURCE_ARRAY(_preorders, _max_preorder, newsize); memset(&_preorders[_max_preorder],0,sizeof(uint)*(newsize-_max_preorder)); _max_preorder = newsize; } diff --git a/src/hotspot/share/opto/node.cpp b/src/hotspot/share/opto/node.cpp index 3eafd97d7c1..997ce92fe1c 100644 --- a/src/hotspot/share/opto/node.cpp +++ b/src/hotspot/share/opto/node.cpp @@ -3095,7 +3095,7 @@ void Node_Stack::grow() { size_t old_top = pointer_delta(_inode_top,_inodes,sizeof(INode)); // save _top size_t old_max = pointer_delta(_inode_max,_inodes,sizeof(INode)); size_t max = old_max << 1; // max * 2 - _inodes = REALLOC_ARENA_ARRAY(_a, INode, _inodes, old_max, max); + _inodes = REALLOC_ARENA_ARRAY(_a, _inodes, old_max, max); _inode_max = _inodes + max; _inode_top = _inodes + old_top; // restore _top } @@ -3213,4 +3213,3 @@ Node* TypeNode::Ideal(PhaseGVN* phase, bool can_reshape) { return Node::Ideal(phase, can_reshape); } - diff --git a/src/hotspot/share/opto/phasetype.hpp b/src/hotspot/share/opto/phasetype.hpp index 2b599ace03a..3d316112b2d 100644 --- a/src/hotspot/share/opto/phasetype.hpp +++ b/src/hotspot/share/opto/phasetype.hpp @@ -204,7 +204,7 @@ class PhaseNameValidator { ~PhaseNameValidator() { if (_bad != nullptr) { - FREE_C_HEAP_ARRAY(char, _bad); + FREE_C_HEAP_ARRAY(_bad); } } diff --git a/src/hotspot/share/opto/regmask.hpp b/src/hotspot/share/opto/regmask.hpp index 421031fdf61..99b10c1c557 100644 --- a/src/hotspot/share/opto/regmask.hpp +++ b/src/hotspot/share/opto/regmask.hpp @@ -285,8 +285,9 @@ class RegMask { _rm_word_ext = NEW_ARENA_ARRAY(_arena, uintptr_t, new_ext_size); } else { assert(_original_ext_address == &_rm_word_ext, "clone sanity check"); - _rm_word_ext = REALLOC_ARENA_ARRAY(_arena, uintptr_t, _rm_word_ext, + _rm_word_ext = REALLOC_ARENA_ARRAY(_arena, _rm_word_ext, old_ext_size, new_ext_size); + } if (initialize_by_infinite_stack) { int fill = 0; diff --git a/src/hotspot/share/opto/traceAutoVectorizationTag.hpp b/src/hotspot/share/opto/traceAutoVectorizationTag.hpp index 4f67aff9b07..47def1aed1e 100644 --- a/src/hotspot/share/opto/traceAutoVectorizationTag.hpp +++ b/src/hotspot/share/opto/traceAutoVectorizationTag.hpp @@ -142,7 +142,7 @@ class TraceAutoVectorizationTagValidator { ~TraceAutoVectorizationTagValidator() { if (_bad != nullptr) { - FREE_C_HEAP_ARRAY(char, _bad); + FREE_C_HEAP_ARRAY(_bad); } } diff --git a/src/hotspot/share/opto/traceMergeStoresTag.hpp b/src/hotspot/share/opto/traceMergeStoresTag.hpp index 214173c02f7..32ade413673 100644 --- a/src/hotspot/share/opto/traceMergeStoresTag.hpp +++ b/src/hotspot/share/opto/traceMergeStoresTag.hpp @@ -111,7 +111,7 @@ namespace TraceMergeStores { ~TagValidator() { if (_bad != nullptr) { - FREE_C_HEAP_ARRAY(char, _bad); + FREE_C_HEAP_ARRAY(_bad); } } diff --git a/src/hotspot/share/prims/jni.cpp b/src/hotspot/share/prims/jni.cpp index 73082c6047d..d6a435d34d1 100644 --- a/src/hotspot/share/prims/jni.cpp +++ b/src/hotspot/share/prims/jni.cpp @@ -2895,7 +2895,7 @@ JNI_ENTRY(void, jni_ReleaseStringCritical(JNIEnv *env, jstring str, const jchar if (is_latin1) { // For latin1 string, free jchar array allocated by earlier call to GetStringCritical. // This assumes that ReleaseStringCritical bookends GetStringCritical. - FREE_C_HEAP_ARRAY(jchar, chars); + FREE_C_HEAP_ARRAY(chars); } else { // StringDedup can have replaced the value array, so don't fetch the array from 's'. // Instead, we calculate the address based on the jchar array exposed with GetStringCritical. diff --git a/src/hotspot/share/prims/jvmtiAgent.cpp b/src/hotspot/share/prims/jvmtiAgent.cpp index 66cb68b44b0..5fe5378995b 100644 --- a/src/hotspot/share/prims/jvmtiAgent.cpp +++ b/src/hotspot/share/prims/jvmtiAgent.cpp @@ -247,7 +247,7 @@ static void vm_exit(const JvmtiAgent* agent, const char* sub_msg1, const char* s jio_snprintf(buf, len, "%s%s%s%s", not_found_error_msg, agent->name(), sub_msg1, &ebuf[0]); } vm_exit_during_initialization(buf, nullptr); - FREE_C_HEAP_ARRAY(char, buf); + FREE_C_HEAP_ARRAY(buf); } #ifdef ASSERT diff --git a/src/hotspot/share/prims/jvmtiClassFileReconstituter.cpp b/src/hotspot/share/prims/jvmtiClassFileReconstituter.cpp index 5077a1743b9..3037ffa5063 100644 --- a/src/hotspot/share/prims/jvmtiClassFileReconstituter.cpp +++ b/src/hotspot/share/prims/jvmtiClassFileReconstituter.cpp @@ -955,7 +955,7 @@ address JvmtiClassFileReconstituter::writeable_address(size_t size) { * initial_buffer_size; // VM goes belly-up if the memory isn't available, so cannot do OOM processing - _buffer = REALLOC_RESOURCE_ARRAY(u1, _buffer, _buffer_size, new_buffer_size); + _buffer = REALLOC_RESOURCE_ARRAY(_buffer, _buffer_size, new_buffer_size); _buffer_size = new_buffer_size; _buffer_ptr = _buffer + used_size; } diff --git a/src/hotspot/share/prims/jvmtiExport.cpp b/src/hotspot/share/prims/jvmtiExport.cpp index fca348fda26..98d8cfd990d 100644 --- a/src/hotspot/share/prims/jvmtiExport.cpp +++ b/src/hotspot/share/prims/jvmtiExport.cpp @@ -1160,7 +1160,7 @@ class JvmtiCompiledMethodLoadEventMark : public JvmtiMethodEventMark { JvmtiCodeBlobEvents::build_jvmti_addr_location_map(nm, &_map, &_map_length); } ~JvmtiCompiledMethodLoadEventMark() { - FREE_C_HEAP_ARRAY(jvmtiAddrLocationMap, _map); + FREE_C_HEAP_ARRAY(_map); } jint code_size() { return _code_size; } diff --git a/src/hotspot/share/prims/jvmtiTagMap.cpp b/src/hotspot/share/prims/jvmtiTagMap.cpp index 04cb70863cd..26724f42e53 100644 --- a/src/hotspot/share/prims/jvmtiTagMap.cpp +++ b/src/hotspot/share/prims/jvmtiTagMap.cpp @@ -716,7 +716,7 @@ static jint invoke_string_value_callback(jvmtiStringPrimitiveValueCallback cb, user_data); if (is_latin1 && s_len > 0) { - FREE_C_HEAP_ARRAY(jchar, value); + FREE_C_HEAP_ARRAY(value); } return res; } diff --git a/src/hotspot/share/prims/unsafe.cpp b/src/hotspot/share/prims/unsafe.cpp index c950690e8ab..368c40abbc9 100644 --- a/src/hotspot/share/prims/unsafe.cpp +++ b/src/hotspot/share/prims/unsafe.cpp @@ -702,11 +702,11 @@ static jclass Unsafe_DefineClass_impl(JNIEnv *env, jstring name, jbyteArray data result = JVM_DefineClass(env, utfName, loader, body, length, pd); if (utfName && utfName != buf) { - FREE_C_HEAP_ARRAY(char, utfName); + FREE_C_HEAP_ARRAY(utfName); } free_body: - FREE_C_HEAP_ARRAY(jbyte, body); + FREE_C_HEAP_ARRAY(body); return result; } diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index 2d40ee1822a..72e3c4fc4b4 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -851,7 +851,7 @@ static bool set_string_flag(JVMFlag* flag, const char* value, JVMFlagOrigin orig } if (JVMFlagAccess::set_ccstr(flag, &value, origin) != JVMFlag::SUCCESS) return false; // Contract: JVMFlag always returns a pointer that needs freeing. - FREE_C_HEAP_ARRAY(char, value); + FREE_C_HEAP_ARRAY(value); return true; } @@ -876,9 +876,9 @@ static bool append_to_string_flag(JVMFlag* flag, const char* new_value, JVMFlagO } (void) JVMFlagAccess::set_ccstr(flag, &value, origin); // JVMFlag always returns a pointer that needs freeing. - FREE_C_HEAP_ARRAY(char, value); + FREE_C_HEAP_ARRAY(value); // JVMFlag made its own copy, so I must delete my own temp. buffer. - FREE_C_HEAP_ARRAY(char, free_this_too); + FREE_C_HEAP_ARRAY(free_this_too); return true; } @@ -1013,7 +1013,7 @@ void Arguments::add_string(char*** bldarray, int* count, const char* arg) { if (*bldarray == nullptr) { *bldarray = NEW_C_HEAP_ARRAY(char*, new_count, mtArguments); } else { - *bldarray = REALLOC_C_HEAP_ARRAY(char*, *bldarray, new_count, mtArguments); + *bldarray = REALLOC_C_HEAP_ARRAY(*bldarray, new_count, mtArguments); } (*bldarray)[*count] = os::strdup_check_oom(arg); *count = new_count; @@ -2050,7 +2050,7 @@ int Arguments::process_patch_mod_option(const char* patch_mod_tail) { *(module_name + module_len) = '\0'; // The path piece begins one past the module_equal sign add_patch_mod_prefix(module_name, module_equal + 1); - FREE_C_HEAP_ARRAY(char, module_name); + FREE_C_HEAP_ARRAY(module_name); if (!create_numbered_module_property("jdk.module.patch", patch_mod_tail, patch_mod_count++)) { return JNI_ENOMEM; } @@ -2201,8 +2201,8 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, JVMFlagOrigin } #endif // !INCLUDE_JVMTI JvmtiAgentList::add_xrun(name, options, false); - FREE_C_HEAP_ARRAY(char, name); - FREE_C_HEAP_ARRAY(char, options); + FREE_C_HEAP_ARRAY(name); + FREE_C_HEAP_ARRAY(options); } } else if (match_option(option, "--add-reads=", &tail)) { if (!create_numbered_module_property("jdk.module.addreads", tail, addreads_count++)) { @@ -2331,7 +2331,7 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, JVMFlagOrigin char *options = NEW_C_HEAP_ARRAY(char, length, mtArguments); jio_snprintf(options, length, "%s", tail); JvmtiAgentList::add("instrument", options, false); - FREE_C_HEAP_ARRAY(char, options); + FREE_C_HEAP_ARRAY(options); // java agents need module java.instrument if (!create_numbered_module_property("jdk.module.addmods", "java.instrument", _addmods_count++)) { @@ -3066,7 +3066,7 @@ class ScopedVMInitArgs : public StackObj { for (int i = 0; i < _args.nOptions; i++) { os::free(_args.options[i].optionString); } - FREE_C_HEAP_ARRAY(JavaVMOption, _args.options); + FREE_C_HEAP_ARRAY(_args.options); } // Insert options into this option list, to replace option at @@ -3215,7 +3215,7 @@ jint Arguments::parse_vm_options_file(const char* file_name, ScopedVMInitArgs* v ssize_t bytes_read = ::read(fd, (void *)buf, (unsigned)bytes_alloc); ::close(fd); if (bytes_read < 0) { - FREE_C_HEAP_ARRAY(char, buf); + FREE_C_HEAP_ARRAY(buf); jio_fprintf(defaultStream::error_stream(), "Could not read options file '%s'\n", file_name); return JNI_ERR; @@ -3223,13 +3223,13 @@ jint Arguments::parse_vm_options_file(const char* file_name, ScopedVMInitArgs* v if (bytes_read == 0) { // tell caller there is no option data and that is ok - FREE_C_HEAP_ARRAY(char, buf); + FREE_C_HEAP_ARRAY(buf); return JNI_OK; } retcode = parse_options_buffer(file_name, buf, bytes_read, vm_args); - FREE_C_HEAP_ARRAY(char, buf); + FREE_C_HEAP_ARRAY(buf); return retcode; } @@ -3562,7 +3562,7 @@ jint Arguments::parse(const JavaVMInitArgs* initial_cmd_args) { char *vmoptions = ClassLoader::lookup_vm_options(); if (vmoptions != nullptr) { code = parse_options_buffer("vm options resource", vmoptions, strlen(vmoptions), &initial_vm_options_args); - FREE_C_HEAP_ARRAY(char, vmoptions); + FREE_C_HEAP_ARRAY(vmoptions); if (code != JNI_OK) { return code; } diff --git a/src/hotspot/share/runtime/deoptimization.cpp b/src/hotspot/share/runtime/deoptimization.cpp index cfdcf52a5eb..9db9c676268 100644 --- a/src/hotspot/share/runtime/deoptimization.cpp +++ b/src/hotspot/share/runtime/deoptimization.cpp @@ -249,9 +249,9 @@ Deoptimization::UnrollBlock::UnrollBlock(int size_of_deoptimized_frame, } Deoptimization::UnrollBlock::~UnrollBlock() { - FREE_C_HEAP_ARRAY(intptr_t, _frame_sizes); - FREE_C_HEAP_ARRAY(intptr_t, _frame_pcs); - FREE_C_HEAP_ARRAY(intptr_t, _register_block); + FREE_C_HEAP_ARRAY(_frame_sizes); + FREE_C_HEAP_ARRAY(_frame_pcs); + FREE_C_HEAP_ARRAY(_register_block); } int Deoptimization::UnrollBlock::size_of_frames() const { diff --git a/src/hotspot/share/runtime/flags/jvmFlag.cpp b/src/hotspot/share/runtime/flags/jvmFlag.cpp index 405b47e1813..1c965360599 100644 --- a/src/hotspot/share/runtime/flags/jvmFlag.cpp +++ b/src/hotspot/share/runtime/flags/jvmFlag.cpp @@ -648,7 +648,7 @@ void JVMFlag::printSetFlags(outputStream* out) { } } out->cr(); - FREE_C_HEAP_ARRAY(JVMFlag*, array); + FREE_C_HEAP_ARRAY(array); } #ifndef PRODUCT diff --git a/src/hotspot/share/runtime/flags/jvmFlagAccess.cpp b/src/hotspot/share/runtime/flags/jvmFlagAccess.cpp index 2db9f198ddd..8efa8f2de62 100644 --- a/src/hotspot/share/runtime/flags/jvmFlagAccess.cpp +++ b/src/hotspot/share/runtime/flags/jvmFlagAccess.cpp @@ -329,7 +329,7 @@ JVMFlag::Error JVMFlagAccess::set_ccstr(JVMFlag* flag, ccstr* value, JVMFlagOrig flag->set_ccstr(new_value); if (!flag->is_default() && old_value != nullptr) { // Old value is heap allocated so free it. - FREE_C_HEAP_ARRAY(char, old_value); + FREE_C_HEAP_ARRAY(old_value); } // Unlike the other APIs, the old value is NOT returned, so the caller won't need to free it. // The callers typically don't care what the old value is. diff --git a/src/hotspot/share/runtime/javaThread.cpp b/src/hotspot/share/runtime/javaThread.cpp index 77a567d4a09..c96ec9a7c0d 100644 --- a/src/hotspot/share/runtime/javaThread.cpp +++ b/src/hotspot/share/runtime/javaThread.cpp @@ -308,7 +308,7 @@ static jlong* resize_counters_array(jlong* old_counters, int current_size, int n if (new_size > current_size) { memset(new_counters + current_size, 0, sizeof(jlong) * (new_size - current_size)); } - FREE_C_HEAP_ARRAY(jlong, old_counters); + FREE_C_HEAP_ARRAY(old_counters); } return new_counters; } @@ -700,7 +700,7 @@ JavaThread::~JavaThread() { #if INCLUDE_JVMCI if (JVMCICounterSize > 0) { - FREE_C_HEAP_ARRAY(jlong, _jvmci_counters); + FREE_C_HEAP_ARRAY(_jvmci_counters); } #endif // INCLUDE_JVMCI } @@ -1884,7 +1884,7 @@ WordSize JavaThread::popframe_preserved_args_size_in_words() { void JavaThread::popframe_free_preserved_args() { assert(_popframe_preserved_args != nullptr, "should not free PopFrame preserved arguments twice"); - FREE_C_HEAP_ARRAY(char, (char*)_popframe_preserved_args); + FREE_C_HEAP_ARRAY((char*)_popframe_preserved_args); _popframe_preserved_args = nullptr; _popframe_preserved_args_size = 0; } diff --git a/src/hotspot/share/runtime/nonJavaThread.cpp b/src/hotspot/share/runtime/nonJavaThread.cpp index cb0c3f8910d..e8f01086058 100644 --- a/src/hotspot/share/runtime/nonJavaThread.cpp +++ b/src/hotspot/share/runtime/nonJavaThread.cpp @@ -133,7 +133,7 @@ NamedThread::NamedThread() : {} NamedThread::~NamedThread() { - FREE_C_HEAP_ARRAY(char, _name); + FREE_C_HEAP_ARRAY(_name); } void NamedThread::set_name(const char* format, ...) { diff --git a/src/hotspot/share/runtime/objectMonitorTable.cpp b/src/hotspot/share/runtime/objectMonitorTable.cpp index bc173992d7a..9f087ad5dee 100644 --- a/src/hotspot/share/runtime/objectMonitorTable.cpp +++ b/src/hotspot/share/runtime/objectMonitorTable.cpp @@ -192,7 +192,7 @@ public: } ~Table() { - FREE_C_HEAP_ARRAY(Atomic, _buckets); + FREE_C_HEAP_ARRAY(_buckets); } Table* prev() { diff --git a/src/hotspot/share/runtime/os.cpp b/src/hotspot/share/runtime/os.cpp index d55cf454256..f9e3a513a78 100644 --- a/src/hotspot/share/runtime/os.cpp +++ b/src/hotspot/share/runtime/os.cpp @@ -303,10 +303,10 @@ static void free_array_of_char_arrays(char** a, size_t n) { while (n > 0) { n--; if (a[n] != nullptr) { - FREE_C_HEAP_ARRAY(char, a[n]); + FREE_C_HEAP_ARRAY(a[n]); } } - FREE_C_HEAP_ARRAY(char*, a); + FREE_C_HEAP_ARRAY(a); } bool os::dll_locate_lib(char *buffer, size_t buflen, @@ -353,7 +353,7 @@ bool os::dll_locate_lib(char *buffer, size_t buflen, } } - FREE_C_HEAP_ARRAY(char*, fullfname); + FREE_C_HEAP_ARRAY(fullfname); return retval; } @@ -562,7 +562,7 @@ void* os::find_agent_function(JvmtiAgent *agent_lib, bool check_lib, const char char* agent_function_name = build_agent_function_name(sym, lib_name, agent_lib->is_absolute_path()); if (agent_function_name != nullptr) { entryName = dll_lookup(handle, agent_function_name); - FREE_C_HEAP_ARRAY(char, agent_function_name); + FREE_C_HEAP_ARRAY(agent_function_name); } return entryName; } @@ -1510,20 +1510,20 @@ bool os::set_boot_path(char fileSep, char pathSep) { bool has_jimage = (os::stat(jimage, &st) == 0); if (has_jimage) { Arguments::set_boot_class_path(jimage, true); - FREE_C_HEAP_ARRAY(char, jimage); + FREE_C_HEAP_ARRAY(jimage); return true; } - FREE_C_HEAP_ARRAY(char, jimage); + FREE_C_HEAP_ARRAY(jimage); // check if developer build with exploded modules char* base_classes = format_boot_path("%/modules/" JAVA_BASE_NAME, home, home_len, fileSep, pathSep); if (base_classes == nullptr) return false; if (os::stat(base_classes, &st) == 0) { Arguments::set_boot_class_path(base_classes, false); - FREE_C_HEAP_ARRAY(char, base_classes); + FREE_C_HEAP_ARRAY(base_classes); return true; } - FREE_C_HEAP_ARRAY(char, base_classes); + FREE_C_HEAP_ARRAY(base_classes); return false; } @@ -1653,7 +1653,7 @@ char** os::split_path(const char* path, size_t* elements, size_t file_name_lengt opath[i] = s; p += len + 1; } - FREE_C_HEAP_ARRAY(char, inpath); + FREE_C_HEAP_ARRAY(inpath); *elements = count; return opath; } diff --git a/src/hotspot/share/runtime/os_perf.hpp b/src/hotspot/share/runtime/os_perf.hpp index 8e39b75deb6..a9a82a41b7e 100644 --- a/src/hotspot/share/runtime/os_perf.hpp +++ b/src/hotspot/share/runtime/os_perf.hpp @@ -152,9 +152,9 @@ class SystemProcess : public CHeapObj { } virtual ~SystemProcess(void) { - FREE_C_HEAP_ARRAY(char, _name); - FREE_C_HEAP_ARRAY(char, _path); - FREE_C_HEAP_ARRAY(char, _command_line); + FREE_C_HEAP_ARRAY(_name); + FREE_C_HEAP_ARRAY(_path); + FREE_C_HEAP_ARRAY(_command_line); } }; diff --git a/src/hotspot/share/runtime/perfData.cpp b/src/hotspot/share/runtime/perfData.cpp index 7532ada8f5a..1502995203d 100644 --- a/src/hotspot/share/runtime/perfData.cpp +++ b/src/hotspot/share/runtime/perfData.cpp @@ -118,9 +118,9 @@ PerfData::PerfData(CounterNS ns, const char* name, Units u, Variability v) } PerfData::~PerfData() { - FREE_C_HEAP_ARRAY(char, _name); + FREE_C_HEAP_ARRAY(_name); if (is_on_c_heap()) { - FREE_C_HEAP_ARRAY(PerfDataEntry, _pdep); + FREE_C_HEAP_ARRAY(_pdep); } } diff --git a/src/hotspot/share/runtime/perfMemory.cpp b/src/hotspot/share/runtime/perfMemory.cpp index 9594149333e..134d1c47230 100644 --- a/src/hotspot/share/runtime/perfMemory.cpp +++ b/src/hotspot/share/runtime/perfMemory.cpp @@ -247,7 +247,7 @@ char* PerfMemory::get_perfdata_file_path() { dest_file = NEW_C_HEAP_ARRAY(char, JVM_MAXPATHLEN, mtInternal); if(!Arguments::copy_expand_pid(PerfDataSaveFile, strlen(PerfDataSaveFile), dest_file, JVM_MAXPATHLEN)) { - FREE_C_HEAP_ARRAY(char, dest_file); + FREE_C_HEAP_ARRAY(dest_file); log_debug(perf)("invalid performance data file path name specified, fall back to a default name"); } else { return dest_file; diff --git a/src/hotspot/share/runtime/sharedRuntime.cpp b/src/hotspot/share/runtime/sharedRuntime.cpp index 352c90f913b..3b5a6fa7ff8 100644 --- a/src/hotspot/share/runtime/sharedRuntime.cpp +++ b/src/hotspot/share/runtime/sharedRuntime.cpp @@ -3085,7 +3085,7 @@ AdapterHandlerEntry::~AdapterHandlerEntry() { _fingerprint = nullptr; } #ifdef ASSERT - FREE_C_HEAP_ARRAY(unsigned char, _saved_code); + FREE_C_HEAP_ARRAY(_saved_code); #endif FreeHeap(this); } @@ -3376,7 +3376,7 @@ JRT_LEAF(intptr_t*, SharedRuntime::OSR_migration_begin( JavaThread *current) ) JRT_END JRT_LEAF(void, SharedRuntime::OSR_migration_end( intptr_t* buf) ) - FREE_C_HEAP_ARRAY(intptr_t, buf); + FREE_C_HEAP_ARRAY(buf); JRT_END const char* AdapterHandlerLibrary::name(AdapterHandlerEntry* handler) { diff --git a/src/hotspot/share/runtime/threadSMR.cpp b/src/hotspot/share/runtime/threadSMR.cpp index 4c68648fec8..d70b7dcbd34 100644 --- a/src/hotspot/share/runtime/threadSMR.cpp +++ b/src/hotspot/share/runtime/threadSMR.cpp @@ -667,7 +667,7 @@ ThreadsList::ThreadsList(int entries) : ThreadsList::~ThreadsList() { if (_threads != empty_threads_list_data) { - FREE_C_HEAP_ARRAY(JavaThread*, _threads); + FREE_C_HEAP_ARRAY(_threads); } _magic = 0xDEADBEEF; } diff --git a/src/hotspot/share/runtime/threads.cpp b/src/hotspot/share/runtime/threads.cpp index b83389a1929..27c4c588429 100644 --- a/src/hotspot/share/runtime/threads.cpp +++ b/src/hotspot/share/runtime/threads.cpp @@ -1062,7 +1062,7 @@ void Threads::destroy_vm() { #if INCLUDE_JVMCI if (JVMCICounterSize > 0) { - FREE_C_HEAP_ARRAY(jlong, JavaThread::_jvmci_old_thread_counters); + FREE_C_HEAP_ARRAY(JavaThread::_jvmci_old_thread_counters); } #endif diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index ad9463443b2..6ae9de05518 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -2086,10 +2086,10 @@ static int recursiveFindType(VMTypeEntry* origtypes, const char* typeName, bool s[len-1] = '\0'; // tty->print_cr("checking \"%s\" for \"%s\"", s, typeName); if (recursiveFindType(origtypes, s, true) == 1) { - FREE_C_HEAP_ARRAY(char, s); + FREE_C_HEAP_ARRAY(s); return 1; } - FREE_C_HEAP_ARRAY(char, s); + FREE_C_HEAP_ARRAY(s); } const char* start = nullptr; if (strstr(typeName, "GrowableArray<") == typeName) { @@ -2105,10 +2105,10 @@ static int recursiveFindType(VMTypeEntry* origtypes, const char* typeName, bool s[len-1] = '\0'; // tty->print_cr("checking \"%s\" for \"%s\"", s, typeName); if (recursiveFindType(origtypes, s, true) == 1) { - FREE_C_HEAP_ARRAY(char, s); + FREE_C_HEAP_ARRAY(s); return 1; } - FREE_C_HEAP_ARRAY(char, s); + FREE_C_HEAP_ARRAY(s); } if (strstr(typeName, "const ") == typeName) { const char * s = typeName + strlen("const "); diff --git a/src/hotspot/share/services/diagnosticArgument.cpp b/src/hotspot/share/services/diagnosticArgument.cpp index 247ab50bde7..0ba7bda2719 100644 --- a/src/hotspot/share/services/diagnosticArgument.cpp +++ b/src/hotspot/share/services/diagnosticArgument.cpp @@ -36,7 +36,7 @@ StringArrayArgument::StringArrayArgument() { StringArrayArgument::~StringArrayArgument() { for (int i=0; i<_array->length(); i++) { - FREE_C_HEAP_ARRAY(char, _array->at(i)); + FREE_C_HEAP_ARRAY(_array->at(i)); } delete _array; } @@ -183,7 +183,7 @@ template <> void DCmdArgument::init_value(TRAPS) { template <> void DCmdArgument::destroy_value() { } template <> void DCmdArgument::destroy_value() { - FREE_C_HEAP_ARRAY(char, _value); + FREE_C_HEAP_ARRAY(_value); set_value(nullptr); } @@ -194,14 +194,14 @@ template <> void DCmdArgument::parse_value(const char* str, } else { // Use realloc as we may have a default set. if (strcmp(type(), "FILE") == 0) { - _value = REALLOC_C_HEAP_ARRAY(char, _value, JVM_MAXPATHLEN, mtInternal); + _value = REALLOC_C_HEAP_ARRAY(_value, JVM_MAXPATHLEN, mtInternal); if (!Arguments::copy_expand_pid(str, len, _value, JVM_MAXPATHLEN)) { stringStream error_msg; error_msg.print("File path invalid or too long: %s", str); THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), error_msg.base()); } } else { - _value = REALLOC_C_HEAP_ARRAY(char, _value, len + 1, mtInternal); + _value = REALLOC_C_HEAP_ARRAY(_value, len + 1, mtInternal); int n = os::snprintf(_value, len + 1, "%.*s", (int)len, str); assert((size_t)n <= len, "Unexpected number of characters in string"); } diff --git a/src/hotspot/share/services/finalizerService.cpp b/src/hotspot/share/services/finalizerService.cpp index 9acf17b8cfd..d57d0fb5b50 100644 --- a/src/hotspot/share/services/finalizerService.cpp +++ b/src/hotspot/share/services/finalizerService.cpp @@ -93,7 +93,7 @@ FinalizerEntry::FinalizerEntry(const InstanceKlass* ik) : _total_finalizers_run(0) {} FinalizerEntry::~FinalizerEntry() { - FREE_C_HEAP_ARRAY(char, _codesource); + FREE_C_HEAP_ARRAY(_codesource); } const InstanceKlass* FinalizerEntry::klass() const { diff --git a/src/hotspot/share/services/heapDumper.cpp b/src/hotspot/share/services/heapDumper.cpp index bfb4546a8a1..c850a3a711f 100644 --- a/src/hotspot/share/services/heapDumper.cpp +++ b/src/hotspot/share/services/heapDumper.cpp @@ -2308,7 +2308,7 @@ class VM_HeapDumper : public VM_GC_Operation, public WorkerTask, public Unmounte for (int i = 0; i < _thread_dumpers_count; i++) { delete _thread_dumpers[i]; } - FREE_C_HEAP_ARRAY(ThreadDumper*, _thread_dumpers); + FREE_C_HEAP_ARRAY(_thread_dumpers); } if (_dumper_controller != nullptr) { diff --git a/src/hotspot/share/services/management.cpp b/src/hotspot/share/services/management.cpp index 664fb5a8ef3..36db3df056f 100644 --- a/src/hotspot/share/services/management.cpp +++ b/src/hotspot/share/services/management.cpp @@ -1715,7 +1715,7 @@ ThreadTimesClosure::~ThreadTimesClosure() { for (int i = 0; i < _count; i++) { os::free(_names_chars[i]); } - FREE_C_HEAP_ARRAY(char *, _names_chars); + FREE_C_HEAP_ARRAY(_names_chars); } // Fills names with VM internal thread names and times with the corresponding diff --git a/src/hotspot/share/services/memoryManager.cpp b/src/hotspot/share/services/memoryManager.cpp index ef9babbb20d..2d725db85b5 100644 --- a/src/hotspot/share/services/memoryManager.cpp +++ b/src/hotspot/share/services/memoryManager.cpp @@ -163,8 +163,8 @@ GCStatInfo::GCStatInfo(int num_pools) { } GCStatInfo::~GCStatInfo() { - FREE_C_HEAP_ARRAY(MemoryUsage*, _before_gc_usage_array); - FREE_C_HEAP_ARRAY(MemoryUsage*, _after_gc_usage_array); + FREE_C_HEAP_ARRAY(_before_gc_usage_array); + FREE_C_HEAP_ARRAY(_after_gc_usage_array); } void GCStatInfo::set_gc_usage(int pool_index, MemoryUsage usage, bool before_gc) { diff --git a/src/hotspot/share/utilities/concurrentHashTable.inline.hpp b/src/hotspot/share/utilities/concurrentHashTable.inline.hpp index 62d2dd29dab..d5f6dee336b 100644 --- a/src/hotspot/share/utilities/concurrentHashTable.inline.hpp +++ b/src/hotspot/share/utilities/concurrentHashTable.inline.hpp @@ -217,7 +217,7 @@ template inline ConcurrentHashTable:: InternalTable::~InternalTable() { - FREE_C_HEAP_ARRAY(Bucket, _buckets); + FREE_C_HEAP_ARRAY(_buckets); } // ScopedCS diff --git a/src/hotspot/share/utilities/elfFile.cpp b/src/hotspot/share/utilities/elfFile.cpp index 0b7713e9ca9..e81f9128292 100644 --- a/src/hotspot/share/utilities/elfFile.cpp +++ b/src/hotspot/share/utilities/elfFile.cpp @@ -942,7 +942,7 @@ bool DwarfFile::ArangesCache::add_entry(const AddressDescriptor& descriptor, uin bool DwarfFile::ArangesCache::grow() { size_t new_capacity = _capacity == 0 ? 128 : _capacity * 1.5; - ArangesEntry* new_entries = REALLOC_C_HEAP_ARRAY_RETURN_NULL(ArangesEntry, _entries, new_capacity, mtInternal); + ArangesEntry* new_entries = REALLOC_C_HEAP_ARRAY_RETURN_NULL(_entries, new_capacity, mtInternal); if (new_entries == nullptr) { return false; } diff --git a/src/hotspot/share/utilities/elfFile.hpp b/src/hotspot/share/utilities/elfFile.hpp index 8abd846364c..0bfa821e256 100644 --- a/src/hotspot/share/utilities/elfFile.hpp +++ b/src/hotspot/share/utilities/elfFile.hpp @@ -487,7 +487,7 @@ class DwarfFile : public ElfFile { bool grow(); void free() { if (_entries != nullptr) { - FREE_C_HEAP_ARRAY(ArangesEntry, _entries); + FREE_C_HEAP_ARRAY(_entries); _entries = nullptr; } } diff --git a/src/hotspot/share/utilities/istream.cpp b/src/hotspot/share/utilities/istream.cpp index ce622c2c282..c78fa5d1efa 100644 --- a/src/hotspot/share/utilities/istream.cpp +++ b/src/hotspot/share/utilities/istream.cpp @@ -265,7 +265,7 @@ bool inputStream::expand_buffer(size_t new_length) { } else { // realloc COV(EXB_R); - new_buf = REALLOC_C_HEAP_ARRAY(char, _buffer, new_length, mtInternal); + new_buf = REALLOC_C_HEAP_ARRAY(_buffer, new_length, mtInternal); assert(new_buf != nullptr, "would have exited VM if OOM"); } diff --git a/src/hotspot/share/utilities/numberSeq.cpp b/src/hotspot/share/utilities/numberSeq.cpp index 536f6563866..9d4ece105ed 100644 --- a/src/hotspot/share/utilities/numberSeq.cpp +++ b/src/hotspot/share/utilities/numberSeq.cpp @@ -144,7 +144,7 @@ TruncatedSeq::TruncatedSeq(int length, double alpha): } TruncatedSeq::~TruncatedSeq() { - FREE_C_HEAP_ARRAY(double, _sequence); + FREE_C_HEAP_ARRAY(_sequence); } void TruncatedSeq::add(double val) { diff --git a/src/hotspot/share/utilities/ostream.cpp b/src/hotspot/share/utilities/ostream.cpp index 1ac34e3d9cb..f052431d55e 100644 --- a/src/hotspot/share/utilities/ostream.cpp +++ b/src/hotspot/share/utilities/ostream.cpp @@ -369,7 +369,7 @@ void stringStream::grow(size_t new_capacity) { } zero_terminate(); } else { - _buffer = REALLOC_C_HEAP_ARRAY(char, _buffer, new_capacity, mtInternal); + _buffer = REALLOC_C_HEAP_ARRAY(_buffer, new_capacity, mtInternal); _capacity = new_capacity; } } @@ -437,7 +437,7 @@ char* stringStream::as_string(Arena* arena) const { stringStream::~stringStream() { if (!_is_fixed && _buffer != _small_buffer) { - FREE_C_HEAP_ARRAY(char, _buffer); + FREE_C_HEAP_ARRAY(_buffer); } } @@ -676,7 +676,7 @@ fileStream* defaultStream::open_file(const char* log_name) { } fileStream* file = new (mtInternal) fileStream(try_name); - FREE_C_HEAP_ARRAY(char, try_name); + FREE_C_HEAP_ARRAY(try_name); if (file->is_open()) { return file; } @@ -694,7 +694,7 @@ fileStream* defaultStream::open_file(const char* log_name) { jio_printf("Warning: Forcing option -XX:LogFile=%s\n", try_name); file = new (mtInternal) fileStream(try_name); - FREE_C_HEAP_ARRAY(char, try_name); + FREE_C_HEAP_ARRAY(try_name); if (file->is_open()) { return file; } @@ -1051,7 +1051,7 @@ void bufferedStream::write(const char* s, size_t len) { } } if (buffer_length < end) { - buffer = REALLOC_C_HEAP_ARRAY(char, buffer, end, mtInternal); + buffer = REALLOC_C_HEAP_ARRAY(buffer, end, mtInternal); buffer_length = end; } } @@ -1070,7 +1070,7 @@ char* bufferedStream::as_string() { } bufferedStream::~bufferedStream() { - FREE_C_HEAP_ARRAY(char, buffer); + FREE_C_HEAP_ARRAY(buffer); } #ifndef PRODUCT diff --git a/src/hotspot/share/utilities/resizableHashTable.hpp b/src/hotspot/share/utilities/resizableHashTable.hpp index a5b53698b11..8e6528f6a3c 100644 --- a/src/hotspot/share/utilities/resizableHashTable.hpp +++ b/src/hotspot/share/utilities/resizableHashTable.hpp @@ -45,7 +45,7 @@ protected: ~ResizeableHashTableStorage() { if (ALLOC_TYPE == C_HEAP) { - FREE_C_HEAP_ARRAY(Node*, _table); + FREE_C_HEAP_ARRAY(_table); } } @@ -151,7 +151,7 @@ public: } if (ALLOC_TYPE == AnyObj::C_HEAP) { - FREE_C_HEAP_ARRAY(Node*, old_table); + FREE_C_HEAP_ARRAY(old_table); } BASE::_table = new_table; BASE::_table_size = new_size; diff --git a/src/hotspot/share/utilities/stack.inline.hpp b/src/hotspot/share/utilities/stack.inline.hpp index 49ccf416629..78e575a0eaf 100644 --- a/src/hotspot/share/utilities/stack.inline.hpp +++ b/src/hotspot/share/utilities/stack.inline.hpp @@ -145,7 +145,7 @@ E* Stack::alloc(size_t bytes) template void Stack::free(E* addr, size_t bytes) { - FREE_C_HEAP_ARRAY(char, (char*) addr); + FREE_C_HEAP_ARRAY((char*) addr); } // Stack is used by the GC code and in some hot paths a lot of the Stack diff --git a/src/hotspot/share/utilities/stringUtils.cpp b/src/hotspot/share/utilities/stringUtils.cpp index 0872ce43d4b..d133d21e52f 100644 --- a/src/hotspot/share/utilities/stringUtils.cpp +++ b/src/hotspot/share/utilities/stringUtils.cpp @@ -125,7 +125,7 @@ bool StringUtils::is_star_match(const char* star_pattern, const char* str) { } StringUtils::CommaSeparatedStringIterator::~CommaSeparatedStringIterator() { - FREE_C_HEAP_ARRAY(char, _list); + FREE_C_HEAP_ARRAY(_list); } ccstrlist StringUtils::CommaSeparatedStringIterator::canonicalize(ccstrlist option_value) { diff --git a/src/hotspot/share/utilities/xmlstream.cpp b/src/hotspot/share/utilities/xmlstream.cpp index 6dacab1dc25..3ebc1b4b4ac 100644 --- a/src/hotspot/share/utilities/xmlstream.cpp +++ b/src/hotspot/share/utilities/xmlstream.cpp @@ -65,7 +65,7 @@ void xmlStream::initialize(outputStream* out) { #ifdef ASSERT xmlStream::~xmlStream() { - FREE_C_HEAP_ARRAY(char, _element_close_stack_low); + FREE_C_HEAP_ARRAY(_element_close_stack_low); } #endif @@ -169,7 +169,7 @@ void xmlStream::see_tag(const char* tag, bool push) { _element_close_stack_high = new_high; _element_close_stack_low = new_low; _element_close_stack_ptr = new_ptr; - FREE_C_HEAP_ARRAY(char, old_low); + FREE_C_HEAP_ARRAY(old_low); push_ptr = new_ptr - (tag_len+1); } assert(push_ptr >= _element_close_stack_low, "in range"); diff --git a/test/hotspot/gtest/concurrentTestRunner.inline.hpp b/test/hotspot/gtest/concurrentTestRunner.inline.hpp index 4cdb342d45c..dcc025bdbf5 100644 --- a/test/hotspot/gtest/concurrentTestRunner.inline.hpp +++ b/test/hotspot/gtest/concurrentTestRunner.inline.hpp @@ -86,7 +86,7 @@ public: done.wait(); } - FREE_C_HEAP_ARRAY(UnitTestThread**, t); + FREE_C_HEAP_ARRAY(t); } private: diff --git a/test/hotspot/gtest/gc/g1/test_freeRegionList.cpp b/test/hotspot/gtest/gc/g1/test_freeRegionList.cpp index e61ce43fdb6..344f32d5ec8 100644 --- a/test/hotspot/gtest/gc/g1/test_freeRegionList.cpp +++ b/test/hotspot/gtest/gc/g1/test_freeRegionList.cpp @@ -91,5 +91,5 @@ TEST_OTHER_VM(G1FreeRegionList, length) { bot_storage->uncommit_regions(0, num_regions_in_test); delete bot_storage; os::release_memory(addr, sz); - FREE_C_HEAP_ARRAY(HeapWord, bot_data); + FREE_C_HEAP_ARRAY(bot_data); } diff --git a/test/hotspot/gtest/gc/g1/test_g1BatchedGangTask.cpp b/test/hotspot/gtest/gc/g1/test_g1BatchedGangTask.cpp index 08df547585a..01e512b6b22 100644 --- a/test/hotspot/gtest/gc/g1/test_g1BatchedGangTask.cpp +++ b/test/hotspot/gtest/gc/g1/test_g1BatchedGangTask.cpp @@ -87,7 +87,7 @@ public: ~G1TestSubTask() { check_and_inc_phase(3); - FREE_C_HEAP_ARRAY(Atomic, _do_work_called_by); + FREE_C_HEAP_ARRAY(_do_work_called_by); } double worker_cost() const override { diff --git a/test/hotspot/gtest/gc/g1/test_g1CardSetContainers.cpp b/test/hotspot/gtest/gc/g1/test_g1CardSetContainers.cpp index 91951b35405..2236b4e83aa 100644 --- a/test/hotspot/gtest/gc/g1/test_g1CardSetContainers.cpp +++ b/test/hotspot/gtest/gc/g1/test_g1CardSetContainers.cpp @@ -69,7 +69,7 @@ public: } ~G1FindCardsInRange() { - FREE_C_HEAP_ARRAY(mtGC, _cards_found); + FREE_C_HEAP_ARRAY(_cards_found); } void operator()(uint card) { ASSERT_TRUE((card - _range_min) < _num_cards); @@ -185,7 +185,7 @@ void G1CardSetContainersTest::cardset_array_test(uint cards_per_array) { found.verify_all_found(); } - FREE_C_HEAP_ARRAY(mtGC, cardset_data); + FREE_C_HEAP_ARRAY(cardset_data); } void G1CardSetContainersTest::cardset_bitmap_test(uint threshold, uint size_in_bits) { @@ -232,7 +232,7 @@ void G1CardSetContainersTest::cardset_bitmap_test(uint threshold, uint size_in_b found.verify_part_found(threshold); } - FREE_C_HEAP_ARRAY(mtGC, cardset_data); + FREE_C_HEAP_ARRAY(cardset_data); } TEST_VM_F(G1CardSetContainersTest, basic_cardset_inptr_test) { diff --git a/test/hotspot/gtest/gc/shared/test_oopStorage.cpp b/test/hotspot/gtest/gc/shared/test_oopStorage.cpp index b343e7fc47f..61115fe9ea0 100644 --- a/test/hotspot/gtest/gc/shared/test_oopStorage.cpp +++ b/test/hotspot/gtest/gc/shared/test_oopStorage.cpp @@ -486,7 +486,7 @@ public: EXPECT_EQ(storage().block_count(), empty_block_count(storage())); - FREE_C_HEAP_ARRAY(oop*, to_release); + FREE_C_HEAP_ARRAY(to_release); } struct PointerCompare { @@ -534,7 +534,7 @@ TEST_VM_F(OopStorageTest, invalid_malloc_pointer) { oop* ptr = reinterpret_cast(align_down(mem + 250, sizeof(oop))); // Predicate returns false for some malloc'ed block. EXPECT_EQ(OopStorage::INVALID_ENTRY, storage().allocation_status(ptr)); - FREE_C_HEAP_ARRAY(char, mem); + FREE_C_HEAP_ARRAY(mem); } TEST_VM_F(OopStorageTest, invalid_random_pointer) { diff --git a/test/hotspot/gtest/gc/shared/test_oopStorage_parperf.cpp b/test/hotspot/gtest/gc/shared/test_oopStorage_parperf.cpp index 3f049eda6ea..72dd61c5cf4 100644 --- a/test/hotspot/gtest/gc/shared/test_oopStorage_parperf.cpp +++ b/test/hotspot/gtest/gc/shared/test_oopStorage_parperf.cpp @@ -137,7 +137,7 @@ public: } ~Task() { - FREE_C_HEAP_ARRAY(Tickspan, _worker_times); + FREE_C_HEAP_ARRAY(_worker_times); } virtual void work(uint worker_id) { diff --git a/test/hotspot/gtest/gc/shenandoah/test_shenandoahMarkBitMap.cpp b/test/hotspot/gtest/gc/shenandoah/test_shenandoahMarkBitMap.cpp index 18cf3b3333f..d395bd27db2 100644 --- a/test/hotspot/gtest/gc/shenandoah/test_shenandoahMarkBitMap.cpp +++ b/test/hotspot/gtest/gc/shenandoah/test_shenandoahMarkBitMap.cpp @@ -555,7 +555,7 @@ public: is_weakly_marked_object_after_2nd_clear, is_strongly_marked_object_after_2nd_clear, all_marked_objects_after_2nd_clear, my_heap_memory, end_of_my_heap); - FREE_C_HEAP_ARRAY(HeapWord, my_bitmap_memory); + FREE_C_HEAP_ARRAY(my_bitmap_memory); _success = true; return true; } diff --git a/test/hotspot/gtest/logging/logTestFixture.cpp b/test/hotspot/gtest/logging/logTestFixture.cpp index 77cc3ee1f75..5a50d050511 100644 --- a/test/hotspot/gtest/logging/logTestFixture.cpp +++ b/test/hotspot/gtest/logging/logTestFixture.cpp @@ -116,7 +116,7 @@ void LogTestFixture::clear_snapshot() { for (size_t i = 0; i < _n_snapshots; i++) { os::free(_configuration_snapshot[i]); } - FREE_C_HEAP_ARRAY(char*, _configuration_snapshot); + FREE_C_HEAP_ARRAY(_configuration_snapshot); _configuration_snapshot = nullptr; _n_snapshots = 0; } diff --git a/test/hotspot/gtest/logging/logTestUtils.inline.hpp b/test/hotspot/gtest/logging/logTestUtils.inline.hpp index 93cace9c689..59045b3a7af 100644 --- a/test/hotspot/gtest/logging/logTestUtils.inline.hpp +++ b/test/hotspot/gtest/logging/logTestUtils.inline.hpp @@ -126,7 +126,7 @@ static inline char* read_line(FILE* fp) { char* ret = fgets(buf, buflen, fp); while (ret != nullptr && buf[strlen(buf) - 1] != '\n' && !feof(fp)) { // retry with a larger buffer - buf = REALLOC_RESOURCE_ARRAY(char, buf, buflen, buflen * 2); + buf = REALLOC_RESOURCE_ARRAY(buf, buflen, buflen * 2); buflen *= 2; // rewind to beginning of line fseek(fp, pos, SEEK_SET); diff --git a/test/hotspot/gtest/logging/test_asynclog.cpp b/test/hotspot/gtest/logging/test_asynclog.cpp index 2634b8dac77..61502f37d80 100644 --- a/test/hotspot/gtest/logging/test_asynclog.cpp +++ b/test/hotspot/gtest/logging/test_asynclog.cpp @@ -234,7 +234,7 @@ TEST_VM_F(AsyncLogTest, logBuffer) { EXPECT_FALSE(buffer->iterator().hasNext()); delete output; // close file - FREE_C_HEAP_ARRAY(char, name); + FREE_C_HEAP_ARRAY(name); const char* strs[4]; strs[0] = "a log line"; diff --git a/test/hotspot/gtest/logging/test_logMessageTest.cpp b/test/hotspot/gtest/logging/test_logMessageTest.cpp index 8ac92f66665..2bc644d9d0c 100644 --- a/test/hotspot/gtest/logging/test_logMessageTest.cpp +++ b/test/hotspot/gtest/logging/test_logMessageTest.cpp @@ -158,7 +158,7 @@ TEST_VM_F(LogMessageTest, long_message) { const char* expected[] = { start_marker, "0123456789", end_marker, nullptr }; EXPECT_TRUE(file_contains_substrings_in_order(_level_filename[LogLevel::Trace], expected)) << "unable to print long line"; - FREE_C_HEAP_ARRAY(char, data); + FREE_C_HEAP_ARRAY(data); } TEST_VM_F(LogMessageTest, message_with_many_lines) { diff --git a/test/hotspot/gtest/memory/test_arena.cpp b/test/hotspot/gtest/memory/test_arena.cpp index 9773aa2d027..abd108a698f 100644 --- a/test/hotspot/gtest/memory/test_arena.cpp +++ b/test/hotspot/gtest/memory/test_arena.cpp @@ -306,9 +306,9 @@ TEST_VM(Arena, random_allocs) { } // Free temp data - FREE_C_HEAP_ARRAY(char*, ptrs); - FREE_C_HEAP_ARRAY(size_t, sizes); - FREE_C_HEAP_ARRAY(size_t, alignments); + FREE_C_HEAP_ARRAY(ptrs); + FREE_C_HEAP_ARRAY(sizes); + FREE_C_HEAP_ARRAY(alignments); } #ifndef LP64 diff --git a/test/hotspot/gtest/metaspace/metaspaceGtestCommon.hpp b/test/hotspot/gtest/metaspace/metaspaceGtestCommon.hpp index 4c9bf67997b..cfa70919bed 100644 --- a/test/hotspot/gtest/metaspace/metaspaceGtestCommon.hpp +++ b/test/hotspot/gtest/metaspace/metaspaceGtestCommon.hpp @@ -42,7 +42,7 @@ public: _arr = NEW_C_HEAP_ARRAY(char, len, mtInternal); memset(_arr, 0, _len); } - ~TestMap() { FREE_C_HEAP_ARRAY(char, _arr); } + ~TestMap() { FREE_C_HEAP_ARRAY(_arr); } int get_num_set(size_t from, size_t to) const { int result = 0; @@ -193,7 +193,7 @@ public: } ~FeederBuffer() { - FREE_C_HEAP_ARRAY(MetaWord, _buf); + FREE_C_HEAP_ARRAY(_buf); } MetaWord* get(size_t word_size) { diff --git a/test/hotspot/gtest/metaspace/metaspaceGtestSparseArray.hpp b/test/hotspot/gtest/metaspace/metaspaceGtestSparseArray.hpp index 6ca6b68baa3..c4ddca624aa 100644 --- a/test/hotspot/gtest/metaspace/metaspaceGtestSparseArray.hpp +++ b/test/hotspot/gtest/metaspace/metaspaceGtestSparseArray.hpp @@ -100,7 +100,7 @@ public: } ~SparseArray() { - FREE_C_HEAP_ARRAY(T, _slots); + FREE_C_HEAP_ARRAY(_slots); } T at(int i) { return _slots[i]; } @@ -165,4 +165,3 @@ public: }; #endif // GTEST_METASPACE_METASPACEGTESTSPARSEARRAY_HPP - diff --git a/test/hotspot/gtest/nmt/test_nmt_locationprinting.cpp b/test/hotspot/gtest/nmt/test_nmt_locationprinting.cpp index c8711004f10..23575fe2c13 100644 --- a/test/hotspot/gtest/nmt/test_nmt_locationprinting.cpp +++ b/test/hotspot/gtest/nmt/test_nmt_locationprinting.cpp @@ -63,7 +63,7 @@ static void test_for_live_c_heap_block(size_t sz, ssize_t offset) { // NMT disabled: we should see nothing. test_pointer(c + offset, false, ""); } - FREE_C_HEAP_ARRAY(char, c); + FREE_C_HEAP_ARRAY(c); } #ifdef LINUX @@ -90,7 +90,7 @@ static void test_for_dead_c_heap_block(size_t sz, ssize_t offset) { test_pointer(c + offset, true, expected_string); hdr->revive(); - FREE_C_HEAP_ARRAY(char, c); + FREE_C_HEAP_ARRAY(c); } #endif diff --git a/test/hotspot/gtest/nmt/test_nmtpreinitmap.cpp b/test/hotspot/gtest/nmt/test_nmtpreinitmap.cpp index c37f5772a5d..6bf42c6f044 100644 --- a/test/hotspot/gtest/nmt/test_nmtpreinitmap.cpp +++ b/test/hotspot/gtest/nmt/test_nmtpreinitmap.cpp @@ -110,7 +110,7 @@ TEST_VM(NMTPreInit, stress_test_map) { print_and_check_table(table, 0); - FREE_C_HEAP_ARRAY(NMTPreInitAllocation*, allocations); + FREE_C_HEAP_ARRAY(allocations); } #ifdef ASSERT diff --git a/test/hotspot/gtest/runtime/test_os.cpp b/test/hotspot/gtest/runtime/test_os.cpp index 094f16a4262..26c8fb8cd72 100644 --- a/test/hotspot/gtest/runtime/test_os.cpp +++ b/test/hotspot/gtest/runtime/test_os.cpp @@ -746,7 +746,7 @@ static void test_show_mappings(address start, size_t size) { #endif // buf[buflen - 1] = '\0'; // tty->print_raw(buf); - FREE_C_HEAP_ARRAY(char, buf); + FREE_C_HEAP_ARRAY(buf); } TEST_VM(os, show_mappings_small_range) { diff --git a/test/hotspot/gtest/threadHelper.inline.hpp b/test/hotspot/gtest/threadHelper.inline.hpp index 07764c45a7a..cc11b0f6ff5 100644 --- a/test/hotspot/gtest/threadHelper.inline.hpp +++ b/test/hotspot/gtest/threadHelper.inline.hpp @@ -169,7 +169,7 @@ public: } } ~TestThreadGroup() { - FREE_C_HEAP_ARRAY(BasicTestThread*, _threads); + FREE_C_HEAP_ARRAY(_threads); } void doit() { diff --git a/test/hotspot/gtest/utilities/test_bitMap_popcnt.cpp b/test/hotspot/gtest/utilities/test_bitMap_popcnt.cpp index 7f2b0eedaa4..bd5c80093d4 100644 --- a/test/hotspot/gtest/utilities/test_bitMap_popcnt.cpp +++ b/test/hotspot/gtest/utilities/test_bitMap_popcnt.cpp @@ -42,7 +42,7 @@ public: } ~SimpleFakeBitmap() { - FREE_C_HEAP_ARRAY(char, _buffer); + FREE_C_HEAP_ARRAY(_buffer); } // Set or clear the specified bit. diff --git a/test/hotspot/gtest/utilities/test_concurrentHashtable.cpp b/test/hotspot/gtest/utilities/test_concurrentHashtable.cpp index 8094e93b944..163b11c213e 100644 --- a/test/hotspot/gtest/utilities/test_concurrentHashtable.cpp +++ b/test/hotspot/gtest/utilities/test_concurrentHashtable.cpp @@ -609,7 +609,7 @@ class ValueSaver { _vals[_it++] = *val; if (_it == _size) { _size *= 2; - _vals = REALLOC_RESOURCE_ARRAY(uintptr_t, _vals, _size/2, _size); + _vals = REALLOC_RESOURCE_ARRAY(_vals, _size/2, _size); } return true; } diff --git a/test/hotspot/gtest/utilities/test_lockFreeStack.cpp b/test/hotspot/gtest/utilities/test_lockFreeStack.cpp index bdba49b48c0..3c3558f0018 100644 --- a/test/hotspot/gtest/utilities/test_lockFreeStack.cpp +++ b/test/hotspot/gtest/utilities/test_lockFreeStack.cpp @@ -300,5 +300,5 @@ TEST_VM(LockFreeStackTest, stress) { ASSERT_EQ(nelements, final_stack.length()); while (final_stack.pop() != nullptr) {} - FREE_C_HEAP_ARRAY(Element, elements); + FREE_C_HEAP_ARRAY(elements); } diff --git a/test/hotspot/gtest/utilities/test_quicksort.cpp b/test/hotspot/gtest/utilities/test_quicksort.cpp index acdd6a315e5..a84d5ecef92 100644 --- a/test/hotspot/gtest/utilities/test_quicksort.cpp +++ b/test/hotspot/gtest/utilities/test_quicksort.cpp @@ -129,7 +129,7 @@ TEST(QuickSort, random) { // Compare sorting to stdlib::qsort() qsort(expected_array, length, sizeof(int), test_stdlib_comparator); EXPECT_TRUE(sort_and_compare(test_array, expected_array, length, test_comparator)); - FREE_C_HEAP_ARRAY(int, test_array); - FREE_C_HEAP_ARRAY(int, expected_array); + FREE_C_HEAP_ARRAY(test_array); + FREE_C_HEAP_ARRAY(expected_array); } } From f65c177f6deea72f488bd0b6604b179a6e923dac Mon Sep 17 00:00:00 2001 From: Ruben Ayrapetyan Date: Mon, 20 Apr 2026 11:14:36 +0000 Subject: [PATCH 358/359] 8365147: AArch64: Replace DMB + LD + DMB with LDAR for C1 volatile field loads Co-authored-by: Andrew Haley Reviewed-by: aph, fgao --- src/hotspot/cpu/aarch64/assembler_aarch64.hpp | 8 ++ .../cpu/aarch64/c1_LIRAssembler_aarch64.cpp | 77 ++++++++++++++++--- .../cpu/aarch64/c1_LIRAssembler_aarch64.hpp | 6 ++ .../cpu/aarch64/c1_LIRGenerator_aarch64.cpp | 9 --- .../c1/shenandoahBarrierSetC1_aarch64.cpp | 12 +-- src/hotspot/cpu/arm/c1_LIRGenerator_arm.cpp | 5 +- src/hotspot/cpu/ppc/c1_LIRGenerator_ppc.cpp | 1 + .../cpu/riscv/c1_LIRGenerator_riscv.cpp | 1 + src/hotspot/cpu/s390/c1_LIRGenerator_s390.cpp | 1 + src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp | 1 + src/hotspot/share/c1/c1_LIRGenerator.hpp | 3 +- .../share/gc/shared/c1/barrierSetC1.cpp | 6 +- src/hotspot/share/oops/accessDecorators.hpp | 3 +- .../gcbarriers/TestImplicitNullChecks.java | 2 + 14 files changed, 102 insertions(+), 33 deletions(-) diff --git a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp b/src/hotspot/cpu/aarch64/assembler_aarch64.hpp index 4c1c8d9bbc8..c8d5ee2eaeb 100644 --- a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/assembler_aarch64.hpp @@ -1,6 +1,7 @@ /* * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2024, Red Hat Inc. All rights reserved. + * Copyright 2026 Arm Limited 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 @@ -1254,6 +1255,13 @@ public: sz, 0b000, ordered); } + void load_store_volatile(Register data, BasicType type, Register addr, + bool is_load) { + load_store_exclusive(dummy_reg, data, dummy_reg, addr, + (Assembler::operand_size)exact_log2(type2aelembytes(type)), + is_load ? 0b110 : 0b100, /* ordered = */ true); + } + #define INSN4(NAME, sz, op, o0) /* Four registers */ \ void NAME(Register Rs, Register Rt1, Register Rt2, Register Rn) { \ guarantee(Rs != Rn && Rs != Rt1 && Rs != Rt2, "unpredictable instruction"); \ diff --git a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp index 4de6237304d..4eb4e3d5ac7 100644 --- a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp @@ -1,6 +1,7 @@ /* * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved. + * Copyright 2026 Arm Limited 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 @@ -911,8 +912,15 @@ void LIR_Assembler::stack2stack(LIR_Opr src, LIR_Opr dest, BasicType type) { reg2stack(temp, dest, dest->type()); } +void LIR_Assembler::mem2reg(LIR_Opr src, LIR_Opr dest, BasicType type, + LIR_PatchCode patch_code, CodeEmitInfo* info, + bool wide) { + mem2reg(src, dest, type, patch_code, info, wide, false); +} -void LIR_Assembler::mem2reg(LIR_Opr src, LIR_Opr dest, BasicType type, LIR_PatchCode patch_code, CodeEmitInfo* info, bool wide) { +void LIR_Assembler::mem2reg(LIR_Opr src, LIR_Opr dest, BasicType type, + LIR_PatchCode patch_code, CodeEmitInfo* info, + bool wide, bool is_volatile) { LIR_Address* addr = src->as_address_ptr(); LIR_Address* from_addr = src->as_address_ptr(); @@ -925,10 +933,27 @@ void LIR_Assembler::mem2reg(LIR_Opr src, LIR_Opr dest, BasicType type, LIR_Patch return; } + if (is_volatile) { + load_volatile(from_addr, dest, type, info); + } else { + load_unordered(from_addr, dest, type, wide, info); + } + + if (is_reference_type(type)) { + if (UseCompressedOops && !wide) { + __ decode_heap_oop(dest->as_register()); + } + + __ verify_oop(dest->as_register()); + } +} + +void LIR_Assembler::load_unordered(LIR_Address *from_addr, LIR_Opr dest, + BasicType type, bool wide, CodeEmitInfo* info) { if (info != nullptr) { add_debug_info_for_null_check_here(info); } - int null_check_here = code_offset(); + switch (type) { case T_FLOAT: { __ ldrs(dest->as_float_reg(), as_Address(from_addr)); @@ -986,16 +1011,44 @@ void LIR_Assembler::mem2reg(LIR_Opr src, LIR_Opr dest, BasicType type, LIR_Patch default: ShouldNotReachHere(); } - - if (is_reference_type(type)) { - if (UseCompressedOops && !wide) { - __ decode_heap_oop(dest->as_register()); - } - - __ verify_oop(dest->as_register()); - } } +void LIR_Assembler::load_volatile(LIR_Address *from_addr, LIR_Opr dest, + BasicType type, CodeEmitInfo* info) { + __ lea(rscratch1, as_Address(from_addr)); + + Register dest_reg = rscratch2; + if (!is_floating_point_type(type)) { + dest_reg = (dest->is_single_cpu() + ? dest->as_register() : dest->as_register_lo()); + } + + if (info != nullptr) { + add_debug_info_for_null_check_here(info); + } + + // Uses LDAR to ensure memory ordering. + __ load_store_volatile(dest_reg, type, rscratch1, /*is_load*/true); + + switch (type) { + // LDAR is unsigned so need to sign-extend for byte and short + case T_BYTE: + __ sxtb(dest_reg, dest_reg); + break; + case T_SHORT: + __ sxth(dest_reg, dest_reg); + break; + // need to move from GPR to FPR after LDAR with FMOV for floating types + case T_FLOAT: + __ fmovs(dest->as_float_reg(), dest_reg); + break; + case T_DOUBLE: + __ fmovd(dest->as_double_reg(), dest_reg); + break; + default: + break; + } +} int LIR_Assembler::array_element_size(BasicType type) const { int elem_size = type2aelembytes(type); @@ -2764,7 +2817,9 @@ void LIR_Assembler::rt_call(LIR_Opr result, address dest, const LIR_OprList* arg } void LIR_Assembler::volatile_move_op(LIR_Opr src, LIR_Opr dest, BasicType type, CodeEmitInfo* info) { - if (dest->is_address() || src->is_address()) { + if (src->is_address()) { + mem2reg(src, dest, type, lir_patch_none, info, /*wide*/false, /*is_volatile*/true); + } else if (dest->is_address()) { move_op(src, dest, type, lir_patch_none, info, /*wide*/false); } else { ShouldNotReachHere(); diff --git a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.hpp index 5af06fc6a1c..367256d2f69 100644 --- a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.hpp @@ -57,6 +57,12 @@ friend class ArrayCopyStub; void casw(Register addr, Register newval, Register cmpval); void casl(Register addr, Register newval, Register cmpval); + void mem2reg(LIR_Opr src, LIR_Opr dest, BasicType type, + LIR_PatchCode patch_code, + CodeEmitInfo* info, bool wide, bool is_volatile); + void load_unordered(LIR_Address *from_addr, LIR_Opr dest, BasicType type, bool wide, CodeEmitInfo* info); + void load_volatile(LIR_Address *from_addr, LIR_Opr dest, BasicType type, CodeEmitInfo* info); + static const int max_tableswitches = 20; struct tableswitch switches[max_tableswitches]; int tableswitch_count; diff --git a/src/hotspot/cpu/aarch64/c1_LIRGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_LIRGenerator_aarch64.cpp index f10c5197d91..7e82f410a95 100644 --- a/src/hotspot/cpu/aarch64/c1_LIRGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_LIRGenerator_aarch64.cpp @@ -1398,14 +1398,5 @@ void LIRGenerator::volatile_field_store(LIR_Opr value, LIR_Address* address, void LIRGenerator::volatile_field_load(LIR_Address* address, LIR_Opr result, CodeEmitInfo* info) { - // 8179954: We need to make sure that the code generated for - // volatile accesses forms a sequentially-consistent set of - // operations when combined with STLR and LDAR. Without a leading - // membar it's possible for a simple Dekker test to fail if loads - // use LD;DMB but stores use STLR. This can happen if C2 compiles - // the stores in one method and C1 compiles the loads in another. - if (!CompilerConfig::is_c1_only_no_jvmci()) { - __ membar(); - } __ volatile_load_mem_reg(address, result, info); } diff --git a/src/hotspot/cpu/aarch64/gc/shenandoah/c1/shenandoahBarrierSetC1_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/shenandoah/c1/shenandoahBarrierSetC1_aarch64.cpp index e4db8a9ab1f..e31a58243b5 100644 --- a/src/hotspot/cpu/aarch64/gc/shenandoah/c1/shenandoahBarrierSetC1_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/gc/shenandoah/c1/shenandoahBarrierSetC1_aarch64.cpp @@ -50,14 +50,10 @@ void LIR_OpShenandoahCompareAndSwap::emit_code(LIR_Assembler* masm) { ShenandoahBarrierSet::assembler()->cmpxchg_oop(masm->masm(), addr, cmpval, newval, /*acquire*/ true, /*release*/ true, /*is_cae*/ false, result); - if (CompilerConfig::is_c1_only_no_jvmci()) { - // The membar here is necessary to prevent reordering between the - // release store in the CAS above and a subsequent volatile load. - // However for tiered compilation C1 inserts a full barrier before - // volatile loads which means we don't need an additional barrier - // here (see LIRGenerator::volatile_field_load()). - __ membar(__ AnyAny); - } + // The membar here is necessary to prevent reordering between the + // release store in the CAS above and a subsequent volatile load. + // See also: LIR_Assembler::casw, LIR_Assembler::casl. + __ membar(__ AnyAny); } #undef __ diff --git a/src/hotspot/cpu/arm/c1_LIRGenerator_arm.cpp b/src/hotspot/cpu/arm/c1_LIRGenerator_arm.cpp index 4c339968f85..46ec87290ae 100644 --- a/src/hotspot/cpu/arm/c1_LIRGenerator_arm.cpp +++ b/src/hotspot/cpu/arm/c1_LIRGenerator_arm.cpp @@ -1332,7 +1332,8 @@ void LIRGenerator::volatile_field_load(LIR_Address* address, LIR_Opr result, load_addr = address; } __ volatile_load_mem_reg(load_addr, result, info); - return; + } else { + __ load(address, result, info, lir_patch_none); } - __ load(address, result, info, lir_patch_none); + __ membar_acquire(); } diff --git a/src/hotspot/cpu/ppc/c1_LIRGenerator_ppc.cpp b/src/hotspot/cpu/ppc/c1_LIRGenerator_ppc.cpp index 5f030676bcb..a652a155f62 100644 --- a/src/hotspot/cpu/ppc/c1_LIRGenerator_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_LIRGenerator_ppc.cpp @@ -1143,6 +1143,7 @@ void LIRGenerator::volatile_field_load(LIR_Address* address, LIR_Opr result, Unimplemented(); // __ volatile_load_mem_reg(address, result, info); #endif + __ membar_acquire(); } diff --git a/src/hotspot/cpu/riscv/c1_LIRGenerator_riscv.cpp b/src/hotspot/cpu/riscv/c1_LIRGenerator_riscv.cpp index f290708a231..5e0deb84a14 100644 --- a/src/hotspot/cpu/riscv/c1_LIRGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_LIRGenerator_riscv.cpp @@ -1169,4 +1169,5 @@ void LIRGenerator::volatile_field_store(LIR_Opr value, LIR_Address* address, void LIRGenerator::volatile_field_load(LIR_Address* address, LIR_Opr result, CodeEmitInfo* info) { __ volatile_load_mem_reg(address, result, info); + __ membar_acquire(); } diff --git a/src/hotspot/cpu/s390/c1_LIRGenerator_s390.cpp b/src/hotspot/cpu/s390/c1_LIRGenerator_s390.cpp index 5a0fd5f9561..1ffd172df8f 100644 --- a/src/hotspot/cpu/s390/c1_LIRGenerator_s390.cpp +++ b/src/hotspot/cpu/s390/c1_LIRGenerator_s390.cpp @@ -1046,6 +1046,7 @@ void LIRGenerator::volatile_field_store(LIR_Opr value, LIR_Address* address, void LIRGenerator::volatile_field_load(LIR_Address* address, LIR_Opr result, CodeEmitInfo* info) { __ load(address, result, info); + __ membar_acquire(); } void LIRGenerator::do_update_CRC32(Intrinsic* x) { diff --git a/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp b/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp index f448e4ee17f..cc068cda7a9 100644 --- a/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp +++ b/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp @@ -1432,4 +1432,5 @@ void LIRGenerator::volatile_field_load(LIR_Address* address, LIR_Opr result, } else { __ load(address, result, info); } + __ membar_acquire(); } diff --git a/src/hotspot/share/c1/c1_LIRGenerator.hpp b/src/hotspot/share/c1/c1_LIRGenerator.hpp index ec0ea5dc047..8e30d05af6d 100644 --- a/src/hotspot/share/c1/c1_LIRGenerator.hpp +++ b/src/hotspot/share/c1/c1_LIRGenerator.hpp @@ -330,8 +330,9 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure { // volatile field operations are never patchable because a klass // must be loaded to know it's volatile which means that the offset - // it always known as well. + // is always known as well. void volatile_field_store(LIR_Opr value, LIR_Address* address, CodeEmitInfo* info); + // volatile_field_load provides trailing membar semantics void volatile_field_load(LIR_Address* address, LIR_Opr result, CodeEmitInfo* info); void put_Object_unsafe(LIR_Opr src, LIR_Opr offset, LIR_Opr data, BasicType type, bool is_volatile); diff --git a/src/hotspot/share/gc/shared/c1/barrierSetC1.cpp b/src/hotspot/share/gc/shared/c1/barrierSetC1.cpp index a31078f7e67..692893544d5 100644 --- a/src/hotspot/share/gc/shared/c1/barrierSetC1.cpp +++ b/src/hotspot/share/gc/shared/c1/barrierSetC1.cpp @@ -183,6 +183,7 @@ void BarrierSetC1::load_at_resolved(LIRAccess& access, LIR_Opr result) { bool needs_patching = (decorators & C1_NEEDS_PATCHING) != 0; bool mask_boolean = (decorators & C1_MASK_BOOLEAN) != 0; bool in_native = (decorators & IN_NATIVE) != 0; + bool needs_trailing_membar = is_volatile; if (support_IRIW_for_not_multiple_copy_atomic_cpu && is_volatile) { __ membar(); @@ -192,12 +193,15 @@ void BarrierSetC1::load_at_resolved(LIRAccess& access, LIR_Opr result) { if (in_native) { __ move_wide(access.resolved_addr()->as_address_ptr(), result); } else if ((is_volatile || needs_atomic) && !needs_patching) { + // volatile_field_load provides trailing membar semantics. + // Hence separate trailing membar is not needed. + needs_trailing_membar = false; gen->volatile_field_load(access.resolved_addr()->as_address_ptr(), result, access.access_emit_info()); } else { __ load(access.resolved_addr()->as_address_ptr(), result, access.access_emit_info(), patch_code); } - if (is_volatile) { + if (needs_trailing_membar) { __ membar_acquire(); } diff --git a/src/hotspot/share/oops/accessDecorators.hpp b/src/hotspot/share/oops/accessDecorators.hpp index b972c54a064..bbf5cd8722e 100644 --- a/src/hotspot/share/oops/accessDecorators.hpp +++ b/src/hotspot/share/oops/accessDecorators.hpp @@ -108,7 +108,8 @@ const DecoratorSet INTERNAL_DECORATOR_MASK = INTERNAL_CONVERT_COMPRESS // - Guarantees from relaxed loads hold. // * MO_SEQ_CST: Sequentially consistent loads. // - These loads observe MO_SEQ_CST stores in the same order on other processors -// - Preceding loads and stores in program order are not reordered with subsequent loads and stores in program order. +// - Preceding MO_SEQ_CST loads and stores in program order are not reordered with +// subsequent MO_SEQ_CST loads and stores in program order. // - Guarantees from acquiring loads hold. // === Atomic Cmpxchg === // * MO_RELAXED: Atomic but relaxed cmpxchg. diff --git a/test/hotspot/jtreg/compiler/gcbarriers/TestImplicitNullChecks.java b/test/hotspot/jtreg/compiler/gcbarriers/TestImplicitNullChecks.java index 34583b8fea9..06057a34b61 100644 --- a/test/hotspot/jtreg/compiler/gcbarriers/TestImplicitNullChecks.java +++ b/test/hotspot/jtreg/compiler/gcbarriers/TestImplicitNullChecks.java @@ -64,6 +64,8 @@ public class TestImplicitNullChecks { public static void main(String[] args) { TestFramework.runWithFlags("-XX:CompileCommand=inline,java.lang.ref.*::*", "-XX:-TieredCompilation"); + TestFramework.runWithFlags("-XX:CompileCommand=inline,java.lang.ref.*::*", + "-XX:+TieredCompilation", "-XX:TieredStopAtLevel=1"); } @Test From 9a3588b4b78152297701926c841bc6867b5403e0 Mon Sep 17 00:00:00 2001 From: Casper Norrbin Date: Mon, 20 Apr 2026 12:09:39 +0000 Subject: [PATCH 359/359] 8379744: Add a way to update the key of a red-black tree node Reviewed-by: jsikstro, phubner --- src/hotspot/share/utilities/rbTree.hpp | 9 +++ src/hotspot/share/utilities/rbTree.inline.hpp | 23 ++++++++ test/hotspot/gtest/utilities/test_rbtree.cpp | 59 +++++++++++++++++++ 3 files changed, 91 insertions(+) diff --git a/src/hotspot/share/utilities/rbTree.hpp b/src/hotspot/share/utilities/rbTree.hpp index 9c04ccbe9ab..fb505ebe9ca 100644 --- a/src/hotspot/share/utilities/rbTree.hpp +++ b/src/hotspot/share/utilities/rbTree.hpp @@ -385,6 +385,15 @@ public: void free_node(RBNode* node); + // Updates the key in the given node or node cursor. + // This will never trigger a tree rebalancing. + // The user must ensure that no tree properties are broken: + // There must not exist any node with the new key + // For all nodes with key < old_key, must also have key < new_key + // For all nodes with key > old_key, must also have key > new_key + void update_key(const Cursor& node_cursor, const K& new_key); + void update_key(RBNode* node, const K& new_key); + // Inserts a node with the given key/value into the tree, // if the key already exist, the value is updated instead. // Returns false if and only if allocation of a new node failed. diff --git a/src/hotspot/share/utilities/rbTree.inline.hpp b/src/hotspot/share/utilities/rbTree.inline.hpp index 381cb916405..1bd8ba8faf8 100644 --- a/src/hotspot/share/utilities/rbTree.inline.hpp +++ b/src/hotspot/share/utilities/rbTree.inline.hpp @@ -1147,6 +1147,29 @@ inline void RBTree::free_node(RBNode* node) { _allocator.free(node); } +template +inline void RBTree::update_key(const Cursor& node_cursor, const K& new_key) { + precond(node_cursor.valid()); + precond(node_cursor.found()); + + RBNode* node = node_cursor.node(); + update_key(node, new_key); +} + +template +inline void RBTree::update_key(RBNode* node, const K& new_key) { + precond(node != nullptr); + #ifdef ASSERT + const RBNode* prev = node->prev(); + const RBNode* next = node->next(); + + if (prev != nullptr) assert(COMPARATOR::cmp(new_key, prev->key()) == RBTreeOrdering::GT, "updated key not GT previous node's key."); + if (next != nullptr) assert(COMPARATOR::cmp(new_key, next->key()) == RBTreeOrdering::LT, "updated key not LT next node's key."); + #endif // ASSERT + + node->_key = new_key; +} + template inline bool RBTree::upsert(const K& key, const V& val, const RBNode* hint_node) { Cursor node_cursor = cursor(key, hint_node); diff --git a/test/hotspot/gtest/utilities/test_rbtree.cpp b/test/hotspot/gtest/utilities/test_rbtree.cpp index 7eca5f54831..bb306935f45 100644 --- a/test/hotspot/gtest/utilities/test_rbtree.cpp +++ b/test/hotspot/gtest/utilities/test_rbtree.cpp @@ -851,6 +851,46 @@ public: tree.verify_self(); } + void test_update_key() { + RBTreeInt tree; + + tree.upsert(10, 10); + tree.upsert(20, 20); + tree.upsert(30, 30); + + RBTreeIntNode* node = tree.find_node(20); + EXPECT_NOT_NULL(node); + + tree.update_key(node, 25); + + EXPECT_NULL(tree.find_node(20)); + + RBTreeIntNode* updated_node = tree.find_node(25); + EXPECT_NOT_NULL(updated_node); + EXPECT_EQ(updated_node, node); + + EXPECT_EQ(25, updated_node->key()); + EXPECT_EQ(20, updated_node->val()); + + RBTreeInt::Cursor cursor = tree.cursor(10); + EXPECT_TRUE(cursor.found()); + + tree.update_key(cursor, 20); + + EXPECT_FALSE(tree.cursor(10).found()); + + RBTreeInt::Cursor updated_cursor = tree.cursor(20); + EXPECT_TRUE(updated_cursor.found()); + + RBTreeIntNode* updated_cursor_node = updated_cursor.node(); + EXPECT_EQ(updated_cursor_node, cursor.node()); + + EXPECT_EQ(20, updated_cursor_node->key()); + EXPECT_EQ(10, updated_cursor_node->val()); + + tree.verify_self(); + } + void test_intrusive() { IntrusiveTreeInt intrusive_tree; int num_iterations = 100; @@ -1167,11 +1207,30 @@ TEST_VM_F(RBTreeTest, CursorReplace) { this->test_cursor_replace(); } +TEST_VM_F(RBTreeTest, UpdateKey) { + this->test_update_key(); +} + #ifdef ASSERT TEST_VM_F(RBTreeTest, NodesVisitedOnce) { this->test_nodes_visited_once(); } +TEST_VM_ASSERT_MSG(RBTreeTestNonFixture, UpdateKeyAssert, + ".*updated key not LT next node's key.*") { + typedef RBTreeCHeap TreeType; + + TreeType tree; + tree.upsert(10, 10); + tree.upsert(20, 20); + tree.upsert(30, 30); + + RBNode* node = tree.find_node(20); + ASSERT_NOT_NULL(node); + + tree.update_key(node, 35); +} + TEST_VM_ASSERT_MSG(RBTreeTestNonFixture, CustomVerifyAssert, ".*failed on key = 7") { typedef RBTreeCHeap TreeType; typedef RBNode NodeType;